Skip to content

Commit

Permalink
feat(hubspot): [nan-1888] [nan-1900] Hubspot products sync and create…
Browse files Browse the repository at this point in the history
…-property (#70)

## Describe your changes
- Adds `products` sync
- Adds `create-property` action

## Issue ticket number and link
NAN-1888
NAN-1900

## Checklist before requesting a review (skip if just adding/editing
APIs & templates)
- [ ] I added tests, otherwise the reason is:
- [ ] External API requests have `retries`
- [ ] Pagination is used where appropriate
- [ ] The built in `nango.paginate` call is used instead of a `while
(true)` loop
- [ ] Third party requests are NOT parallelized (this can cause issues
with rate limits)
- [ ] If a sync requires metadata the `nango.yaml` has `auto_start:
false`
- [ ] If the sync is a `full` sync then `track_deletes: true` is set
  • Loading branch information
khaliqgant authored Oct 23, 2024
1 parent ad5ab48 commit a6f831c
Show file tree
Hide file tree
Showing 20 changed files with 1,031 additions and 7 deletions.
132 changes: 132 additions & 0 deletions flows.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3225,6 +3225,16 @@ integrations:
sync_type: full
track_deletes: true
endpoint: GET /deals
products:
runs: every day
description: |
Fetches a list of products from Hubspot
output: Product
sync_type: full
track_deletes: true
endpoint: GET /products
scopes:
- e-commerce
owners:
runs: every day
description: |
Expand Down Expand Up @@ -3283,6 +3293,21 @@ integrations:
input: InputProperty
output: PropertyResponse
endpoint: GET /properties
create-property:
description: Create a property in Hubspot
input: CreatePropertyInput
output: CreatedProperty
endpoint: POST /properties
scopes:
- oauth
- crm.schemas.orders.write
- crm.objects.orders.write
- crm.schemas.contacts.write
- crm.schemas.carts.write
- crm.schemas.deals.write
- crm.objects.users.write
- crm.schemas.companies.write
- crm.objects.carts.write
create-deal:
description: Creates a single deal in Hubspot
output: CreateUpdateDealOutput
Expand All @@ -3308,6 +3333,14 @@ integrations:
scopes:
- crm.objects.deals.write
- oauth
fetch-pipelines:
description: Fetch all pipelines for an object type. Defaults to deals
input: OptionalObjectType
output: PipelineOutput
endpoint: GET /pipelines
scopes:
- oauth
- crm.objects.deals.read
create-user:
description: Creates a single user in Hubspot
output: CreatedUser
Expand Down Expand Up @@ -3443,6 +3476,11 @@ integrations:
success: boolean
Id:
id: string
Timestamps:
updatedAt: string
createdAt: string
OptionalObjectType:
objectType?: string
InputProperty:
name: string
PropertyResponse:
Expand Down Expand Up @@ -3475,6 +3513,65 @@ integrations:
value: string
displayOrder: number
hidden: boolean
CreatePropertyInput:
objectType: string
data: CustomProperty
CustomProperty:
hidden?: boolean
displayOrder?: number
description?: string
label: string
type: string
formField?: boolean
groupName: string
referencedObjectType?: string
name: string
options?: CustomPropertyOption[]
calculationFormula?: string
hasUniqueValue?: boolean
fieldType: string
externalOptions?: boolean
CustomPropertyOption:
hidden: boolean
displayOrder?: number
description?: string
label: string
value: string
CreatedProperty:
createdUserId: string
hidden: boolean
modificationMetadata:
readOnlyOptions?: boolean
readOnlyValue: boolean
readOnlyDefinition: boolean
archivable: boolean
displayOrder: number
description: string
showCurrencySymbol?: boolean
label: string
type: string
hubspotDefined?: boolean
formField: boolean
dataSensitivity?: string
createdAt: string
archivedAt?: string
archived: boolean
groupName: string
referencedObjectType?: string
name: string
options:
- hidden: boolean
displayOrder: number
description: string
label: string
value: string
calculationFormula?: string
hasUniqueValue: boolean
fieldType: string
updatedUserId: string
calculated: boolean
externalOptions: boolean
updatedAt: string
RoleResponse:
results: Role[]
Role:
Expand Down Expand Up @@ -3797,6 +3894,41 @@ integrations:
CustomObject:
id: string
__string: any
Product:
updatedAt: string
createdAt: string
id: string
amount: number | null
description: string | null
discount: number | null
sku: string | null
url: string | null
name: string
price: string
quantity: number | null
recurringBillingFrequency: number | null
tax: null | number
PipelineOutput:
pipelines: Pipeline[]
Pipeline:
updatedAt: string
createdAt: string
label: string
displayOrder: number
id: string
archived: boolean
stages: Stage[]
Stage:
updatedAt: string
createdAt: string
label: string
displayOrder: number
metadata:
isClosed: boolean
probability: string
id: string
archived: boolean
writePermissions: string
instantly:
actions:
set-campaign-name:
Expand Down
35 changes: 35 additions & 0 deletions integrations/hubspot/actions/create-property.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { NangoAction, CreatedProperty, CreatePropertyInput } from '../../models';
import { CreatePropertyInputSchema } from '../schema.js';

/**
* Executes an action to create a custom property in the CRM.
* It validates the input against the defined schema, logs any validation errors,
* and then sends a POST request to create the custom properties if the input is valid.
* @param nango - An instance of NangoAction used to interact with the Nango API and handle logging.
* @param input - The input data for creating the custom property, validated by the CustomPropertyInputSchema.
* @returns A promise that resolves with the result of the API call, which includes the details of the created custom property.
* @throws An ActionError if the input validation fails.
*/
export default async function runAction(nango: NangoAction, input: CreatePropertyInput): Promise<CreatedProperty> {
const parsedInput = CreatePropertyInputSchema.safeParse(input);

if (!parsedInput.success) {
for (const error of parsedInput.error.errors) {
await nango.log(`Invalid input provided to create custom property: ${error.message} at path ${error.path.join('.')}`, { level: 'error' });
}
throw new nango.ActionError({
message: 'Invalid input provided to create custom property'
});
}

const inputData = parsedInput.data;

const response = await nango.post({
// https://developers.hubspot.com/docs/api/crm/properties
endpoint: `/crm/v3/properties/${inputData.objectType}`,
data: inputData.data,
retries: 10
});

return response.data;
}
17 changes: 17 additions & 0 deletions integrations/hubspot/actions/fetch-pipelines.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { NangoAction, OptionalObjectType, PipelineOutput } from '../../models';

export default async function runAction(nango: NangoAction, input: OptionalObjectType): Promise<PipelineOutput> {
const objectType = input?.objectType || 'deal';

const response = await nango.get({
// https://developers.hubspot.com/docs/api/crm/pipelines
endpoint: `/crm/v3/pipelines/${objectType}`,
retries: 10
});

const { data } = response;

return {
pipelines: data.results
};
}
31 changes: 31 additions & 0 deletions integrations/hubspot/fixtures/create-property.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"objectType": "companies",
"data": {
"hidden": false,
"displayOrder": 1,
"description": "string",
"label": "My Company Property",
"type": "enumeration",
"formField": false,
"groupName": "companyinformation",
"name": "my_cool_company_property",
"options": [
{
"label": "Option A",
"value": "A",
"hidden": false,
"description": "Choice number one",
"displayOrder": 1
},
{
"label": "Option B",
"value": "B",
"hidden": false,
"description": "Choice number two",
"displayOrder": 2
}
],
"hasUniqueValue": false,
"fieldType": "select"
}
}
31 changes: 31 additions & 0 deletions integrations/hubspot/mocks/create-property/input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"objectType": "companies",
"data": {
"hidden": false,
"displayOrder": 1,
"description": "string",
"label": "My Company Property",
"type": "enumeration",
"formField": false,
"groupName": "companyinformation",
"name": "my_cool_company_property",
"options": [
{
"label": "Option A",
"value": "A",
"hidden": false,
"description": "Choice number one",
"displayOrder": 1
},
{
"label": "Option B",
"value": "B",
"hidden": false,
"description": "Choice number two",
"displayOrder": 2
}
],
"hasUniqueValue": false,
"fieldType": "select"
}
}
41 changes: 41 additions & 0 deletions integrations/hubspot/mocks/create-property/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"updatedAt": "2024-10-23T12:40:46.602Z",
"createdAt": "2024-10-23T12:40:46.602Z",
"name": "my_cool_company_property",
"label": "My Company Property",
"type": "enumeration",
"fieldType": "select",
"description": "string",
"groupName": "companyinformation",
"options": [
{
"label": "Option A",
"value": "A",
"description": "Choice number one",
"displayOrder": 1,
"hidden": false
},
{
"label": "Option B",
"value": "B",
"description": "Choice number two",
"displayOrder": 2,
"hidden": false
}
],
"createdUserId": "46062047",
"updatedUserId": "46062047",
"displayOrder": 1,
"calculated": false,
"externalOptions": false,
"archived": false,
"hasUniqueValue": false,
"hidden": false,
"modificationMetadata": {
"archivable": true,
"readOnlyDefinition": false,
"readOnlyValue": false
},
"formField": false,
"dataSensitivity": "non_sensitive"
}
Loading

0 comments on commit a6f831c

Please sign in to comment.