From 8fe97c0fd70ea00565ab27d947c1b810cd0353a8 Mon Sep 17 00:00:00 2001 From: Victor Piolin Date: Fri, 30 May 2025 10:06:52 -0400 Subject: [PATCH 1/2] feat: Add support for bulk actions in Custom object Service for Records --- __tests__/services/custom-objects.spec.ts | 58 +++++++++++++- src/models/custom-objects.ts | 94 +++++++++++++++++++++++ src/services/custom-object-service.ts | 22 +++++- 3 files changed, 172 insertions(+), 2 deletions(-) diff --git a/__tests__/services/custom-objects.spec.ts b/__tests__/services/custom-objects.spec.ts index 34b6cc7..d4bbd72 100644 --- a/__tests__/services/custom-objects.spec.ts +++ b/__tests__/services/custom-objects.spec.ts @@ -1,7 +1,9 @@ import { ICreateCustomObjectRecordBody, CustomObjectFieldType, - ListCutomObjectRecordsSortingOptions + ListCutomObjectRecordsSortingOptions, + RecordBulkAction, + IBulkJobBodyCreate } from "@models/custom-objects"; import { CustomObjectService } from "@services/index"; import { Client } from "@zendesk/sell-zaf-app-toolbox"; @@ -387,5 +389,59 @@ describe("CustomObjectService", () => { }); expect(requestMock).toHaveBeenCalledTimes(2); }); + + it("should call Zendesk API for bulk jobs correctly", async () => { + requestMock.mockResolvedValueOnce({ + "job_status": { + "id": "V3-291e720c98aef4d953563ab090486213", + "message": null, + "progress": null, + "results": null, + "status": "queued", + "total": 2, + "url": "https://test.zendesk.com/api/v2/job_statuses/V3-291e720c98aef4d953563ab090486213.json" + } + }); + + const body: IBulkJobBodyCreate = { + "job": { + "action": RecordBulkAction.create, + "items": [ + { + "custom_object_fields": { + "color": "Red", + "year": "2020" + }, + "name": "2020 Tesla" + }, + { + "custom_object_fields": { + "color": "Blue", + "external_id": "ddd444", + "year": "2012" + }, + "name": "2012 Toyota" + }, + { + "custom_object_fields": { + "color": "Silver", + "external_id": "ddd445", + "year": "2017" + }, + "name": "2017 Ford" + } + ] + } + }; + await service.bulkJobsForRecords("foo", body); + + expect(requestMock).toHaveBeenCalledWith({ + url: `/api/v2/custom_objects/foo/jobs`, + type: "POST", + contentType: "application/json", + data: JSON.stringify(body) + }); + expect(requestMock).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/src/models/custom-objects.ts b/src/models/custom-objects.ts index febfd0c..986ef17 100644 --- a/src/models/custom-objects.ts +++ b/src/models/custom-objects.ts @@ -147,6 +147,20 @@ export interface ISearchCustomObjectRecordsFilter extends IListCustomObjectRecor export interface ICreateCustomObjectRecordBody { custom_object_fields: T; + external_id?: string; + name: string; +} + +export interface IUpdateCustomObjectRecordBody { + custom_object_fields: T; + external_id?: string; + name: string; + id: string; +} + +export interface ICreateCustomObjectRecordBodyWithExternalId { + custom_object_fields: T; + external_id: string; name: string; } @@ -184,3 +198,83 @@ export interface IListCustomObjectRecordsResponse { custom_object_record: ICustomObjectRecord; } + +export enum RecordBulkAction { + create = "create", + delete = "delete", + delete_by_external_id = "delete_by_external_id", + create_or_update_by_external_id = "create_or_update_by_external_id", + create_or_update_by_name = "create_or_update_by_name", + update = "update" +} + +interface IBulkJobBodyBase { + job: { + action: RecordBulkAction; + items: T[]; + }; +} + +export interface IBulkJobBodyCreate extends IBulkJobBodyBase> { + job: { + action: RecordBulkAction.create; + items: ICreateCustomObjectRecordBody[]; + }; +} + +export interface IBulkJobBodyUpdate extends IBulkJobBodyBase> { + job: { + action: RecordBulkAction.update; + items: IUpdateCustomObjectRecordBody[]; + }; +} + +export interface IBulkJobBodyCreateOrUpdateByName + extends IBulkJobBodyBase> { + job: { + action: RecordBulkAction.create_or_update_by_name; + items: ICreateCustomObjectRecordBody[]; + }; +} + +export interface IBulkJobBodyCreateOrUpdateByExternalId + extends IBulkJobBodyBase> { + job: { + action: RecordBulkAction.create_or_update_by_external_id; + items: ICreateCustomObjectRecordBodyWithExternalId[]; + }; +} + +export interface IBulkJobBodyDelete extends IBulkJobBodyBase { + job: { + action: RecordBulkAction.delete; + items: string[]; + }; +} + +export interface IBulkJobBodyDeleteByExternalId extends IBulkJobBodyBase { + job: { + action: RecordBulkAction.delete_by_external_id; + items: string[]; + }; +} + +export type IBulkJobBody = + | IBulkJobBodyCreate + | IBulkJobBodyUpdate + | IBulkJobBodyCreateOrUpdateByName + | IBulkJobBodyCreateOrUpdateByExternalId + | IBulkJobBodyDelete + | IBulkJobBodyDeleteByExternalId; + +export interface IBulkJobResponse { + "job_status": { + "id": string; + "message": string; + "progress": string; + "results": unknown; + "status": string; + "total": number; + "url": string; + }; +} diff --git a/src/services/custom-object-service.ts b/src/services/custom-object-service.ts index 6fe599e..207f66f 100644 --- a/src/services/custom-object-service.ts +++ b/src/services/custom-object-service.ts @@ -12,7 +12,9 @@ import { ICustomObjectRecord, ListCutomObjectRecordsSortingOptions, ICustomObjectRecordField, - ISearchCustomObjectRecordsFilter + ISearchCustomObjectRecordsFilter, + IBulkJobResponse, + IBulkJobBody } from "@models/index"; import { Client } from "@zendesk/sell-zaf-app-toolbox"; @@ -233,6 +235,24 @@ export class CustomObjectService { } as ISearchCustomObjectRecordsFilter); } + /** + * Bulk create or update custom object records + * This endpoint allows you to create or update multiple custom object records in a single request. + * The job will be processed asynchronously, and you can check the status of the job using the job ID returned in the response. + * + * @param key - The custom object key + * @param job - The bulk job body containing the records to be created or updated + * @see https://developer.zendesk.com/api-reference/custom-data/custom-objects/custom_object_records/#custom-object-record-bulk-jobs + */ + public async bulkJobsForRecords(key: string, job: IBulkJobBody): Promise { + return this.client.request({ + url: `/api/v2/custom_objects/${key}/jobs`, + type: "POST", + contentType: CONTENT_TYPE, + data: JSON.stringify(job) + }); + } + /** * Generic method to fetch all records using pagination * From 8404668d85ce3d41162983a0c72078cd61e59ff2 Mon Sep 17 00:00:00 2001 From: Vico1993 Date: Fri, 30 May 2025 14:09:51 +0000 Subject: [PATCH 2/2] [BOT] Bump version from 0.5.0 to 0.6.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 978802a..b97ba40 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zendesk/zaf-toolbox", - "version": "0.5.0", + "version": "0.6.0", "description": "A toolbox for ZAF application built with 🩷 by Zendesk Labs", "main": "lib/src/index.js", "types": "lib/src/index.d.ts",