From 7e862e24074d95ea1133c9a4e41ae66f71f82e40 Mon Sep 17 00:00:00 2001 From: Hywel Wong Date: Fri, 17 Feb 2023 20:02:54 -0800 Subject: [PATCH 1/5] Added blackbaud createConstituentAction --- .../__snapshots__/snapshot.test.ts.snap | 21 +++ .../blackbaud-raisers-edge-nxt/api/index.ts | 8 + .../__snapshots__/snapshot.test.ts.snap | 22 +++ .../__tests__/index.test.ts | 84 +++++++++ .../__tests__/snapshot.test.ts | 77 +++++++++ .../createConstituentAction/fixtures.ts | 31 ++++ .../generated-types.ts | 139 +++++++++++++++ .../createConstituentAction/index.ts | 161 ++++++++++++++++++ .../blackbaud-raisers-edge-nxt/index.ts | 5 +- .../blackbaud-raisers-edge-nxt/types/index.ts | 21 +++ .../blackbaud-raisers-edge-nxt/utils/index.ts | 37 ++++ 11 files changed, 605 insertions(+), 1 deletion(-) create mode 100644 packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/__snapshots__/snapshot.test.ts.snap create mode 100644 packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/index.test.ts create mode 100644 packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/snapshot.test.ts create mode 100644 packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/fixtures.ts create mode 100644 packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts create mode 100644 packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/__tests__/__snapshots__/snapshot.test.ts.snap index 3d7321fcd7..2f762eea36 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/__tests__/__snapshots__/snapshot.test.ts.snap +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/__tests__/__snapshots__/snapshot.test.ts.snap @@ -1,5 +1,26 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Testing snapshot for actions-blackbaud-raisers-edge-nxt destination: createConstituentAction action - all fields 1`] = ` +Object { + "birthdate": Object { + "d": "31", + "m": "1", + "y": "2021", + }, + "first": "x3tNm3W0", + "gender": "x3tNm3W0", + "income": "x3tNm3W0", + "last": "x3tNm3W0", + "lookup_id": "x3tNm3W0", +} +`; + +exports[`Testing snapshot for actions-blackbaud-raisers-edge-nxt destination: createConstituentAction action - required fields 1`] = ` +Object { + "lookup_id": "x3tNm3W0", +} +`; + exports[`Testing snapshot for actions-blackbaud-raisers-edge-nxt destination: createGift action - all fields 1`] = ` Object { "birthdate": Object { diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/api/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/api/index.ts index 2ab79c2916..861dda5062 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/api/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/api/index.ts @@ -3,6 +3,7 @@ import { SKY_API_CONSTITUENT_URL, SKY_API_GIFTS_URL } from '../constants' import { Address, Constituent, + ConstituentAction, CreateConstituentResult, Email, ExistingAddress, @@ -553,4 +554,11 @@ export class BlackbaudSkyApi { json: giftData }) } + + async createConstituentAction(constituentActionData: ConstituentAction): Promise { + return this.request(`${SKY_API_CONSTITUENT_URL}/actions`, { + method: 'post', + json: constituentActionData + }) + } } diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..0ae000165e --- /dev/null +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for BlackbaudRaisersEdgeNxt's createConstituentAction destination action: all fields 1`] = ` +Object { + "birthdate": Object { + "d": "31", + "m": "1", + "y": "2021", + }, + "first": "bUa9Yg9hQ", + "gender": "bUa9Yg9hQ", + "income": "bUa9Yg9hQ", + "last": "bUa9Yg9hQ", + "lookup_id": "bUa9Yg9hQ", +} +`; + +exports[`Testing snapshot for BlackbaudRaisersEdgeNxt's createConstituentAction destination action: required fields 1`] = ` +Object { + "lookup_id": "bUa9Yg9hQ", +} +`; diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/index.test.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/index.test.ts new file mode 100644 index 0000000000..65cb14cb73 --- /dev/null +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/index.test.ts @@ -0,0 +1,84 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration, IntegrationError } from '@segment/actions-core' +import Destination from '../../index' +import { SKY_API_CONSTITUENT_URL } from '../../constants' +import { trackEventData, trackEventDataNewConstituent, trackEventDataNoConstituent } from '../fixtures' + +const testDestination = createTestIntegration(Destination) + +const mapping = { + constituent_email: { + address: { + '@path': '$.properties.email' + }, + type: { + '@path': '$.properties.emailType' + } + }, + constituent_id: { + '@path': '$.properties.constituentId' + }, + date: { + '@path': '$.timestamp' + }, + category: { + '@path': '$.properties.category' + } +} + +describe('BlackbaudRaisersEdgeNxt.createConstituentAction', () => { + test('should create a new constituent action successfully', async () => { + const event = createTestEvent(trackEventData) + + nock(SKY_API_CONSTITUENT_URL).post('/actions').reply(200, { + id: '1000' + }) + + await expect( + testDestination.testAction('createConstituentAction', { + event, + mapping, + useDefaultMappings: true + }) + ).resolves.not.toThrowError() + }) + + test('should create a new constituent and associate action with it', async () => { + const event = createTestEvent(trackEventDataNewConstituent) + + nock(SKY_API_CONSTITUENT_URL) + .get('/constituents/search?search_field=email_address&search_text=john@example.biz') + .reply(200, { + count: 0, + value: [] + }) + + nock(SKY_API_CONSTITUENT_URL).post('/constituents').reply(200, { + id: '456' + }) + + nock(SKY_API_CONSTITUENT_URL).post('/actions').reply(200, { + id: '1001' + }) + + await expect( + testDestination.testAction('createConstituentAction', { + event, + mapping, + useDefaultMappings: true + }) + ).resolves.not.toThrowError() + }) + + test('should throw an IntegrationError if no constituent provided', async () => { + const event = createTestEvent(trackEventDataNoConstituent) + + await expect( + testDestination.testAction('createConstituentAction', { + event, + mapping, + useDefaultMappings: true + }) + ).rejects.toThrowError(new IntegrationError('Missing constituent_id value', 'MISSING_REQUIRED_FIELD', 400)) + }) +}) diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..ef0a77a1e8 --- /dev/null +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/snapshot.test.ts @@ -0,0 +1,77 @@ +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import { generateTestData } from '../../../../lib/test-data' +import destination from '../../index' +import nock from 'nock' + +const testDestination = createTestIntegration(destination) +const actionSlug = 'createConstituentAction' +const destinationSlug = 'BlackbaudRaisersEdgeNxt' +const seedName = `${destinationSlug}#${actionSlug}` + +describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => { + it('required fields', async () => { + const action = destination.actions[actionSlug] + const [eventData, settingsData] = generateTestData(seedName, destination, action, true) + + nock(/.*/).persist().get(/.*/).reply(200, {}) + nock(/.*/).persist().patch(/.*/).reply(200, {}) + nock(/.*/).persist().post(/.*/).reply(200, {}) + nock(/.*/).persist().put(/.*/).reply(200, {}) + + const event = createTestEvent({ + properties: eventData + }) + + const responses = await testDestination.testAction(actionSlug, { + event: event, + mapping: event.properties, + settings: settingsData, + auth: undefined + }) + + const request = responses[0].request + const rawBody = await request.text() + + try { + const json = JSON.parse(rawBody) + expect(json).toMatchSnapshot() + return + } catch (err) { + expect(rawBody).toMatchSnapshot() + } + + expect(request.headers).toMatchSnapshot() + }) + + it('all fields', async () => { + const action = destination.actions[actionSlug] + const [eventData, settingsData] = generateTestData(seedName, destination, action, false) + + nock(/.*/).persist().get(/.*/).reply(200, {}) + nock(/.*/).persist().patch(/.*/).reply(200, {}) + nock(/.*/).persist().post(/.*/).reply(200, {}) + nock(/.*/).persist().put(/.*/).reply(200, {}) + + const event = createTestEvent({ + properties: eventData + }) + + const responses = await testDestination.testAction(actionSlug, { + event: event, + mapping: event.properties, + settings: settingsData, + auth: undefined + }) + + const request = responses[0].request + const rawBody = await request.text() + + try { + const json = JSON.parse(rawBody) + expect(json).toMatchSnapshot() + return + } catch (err) { + expect(rawBody).toMatchSnapshot() + } + }) +}) diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/fixtures.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/fixtures.ts new file mode 100644 index 0000000000..f8cf4d83d4 --- /dev/null +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/fixtures.ts @@ -0,0 +1,31 @@ +import { SegmentEvent } from '@segment/actions-core' + +// track events +export const trackEventData: Partial = { + type: 'track', + properties: { + constituentId: '123', + category: 'Task/Other' + }, + timestamp: '2022-12-12T19:11:01.249Z' +} + +export const trackEventDataNewConstituent: Partial = { + type: 'track', + properties: { + email: 'john@example.biz', + emailType: 'Personal', + firstName: 'John', + lastName: 'Doe', + category: 'Task/Other' + }, + timestamp: '2022-12-12T19:11:01.249Z' +} + +export const trackEventDataNoConstituent: Partial = { + type: 'track', + properties: { + category: 'Task/Other' + }, + timestamp: '2022-12-12T19:11:01.249Z' +} diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts new file mode 100644 index 0000000000..0b9fb3f009 --- /dev/null +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts @@ -0,0 +1,139 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * The ID of the constituent. + */ + constituent_id?: string + /** + * The action date in ISO-8601 format. + */ + date: string | number + /** + * The channel or intent of the constituent interaction. Available values are Phone Call, Meeting, Mailing, Email, and Task/Other. + */ + category: string + /** + * Indicates whether the action is complete. + */ + completed?: boolean + /** + * The date when the action was completed in ISO-8601 format. + */ + completed_date?: string | number + /** + * The detailed explanation that elaborates on the action summary. + */ + description?: string + /** + * The direction of the action. Available values are "Inbound" and "Outbound". The default is Inbound. + */ + direction?: string + /** + * The end time of the action. Uses 24-hour time in the HH:mm format. + */ + end_time?: string + /** + * The set of immutable constituent system record IDs for the fundraisers associated with the action. + */ + fundraisers?: string + /** + * The location of the action. Available values are the entries in the Action Locations table. + */ + location?: string + /** + * The immutable system record ID of the opportunity associated with the action. + */ + opportunity_id?: string + /** + * The outcome of the action. Available values are Successful and Unsuccessful. + */ + outcome?: string + /** + * The priority of the action. Available values are Normal, High, and Low. The default is Normal. + */ + priority?: string + /** + * The start time of the action. Uses 24-hour time in the HH:mm format. + */ + start_time?: string + /** + * The action status. If the system is configured to use custom action statuses, available values are the entries in the Action Status table. + */ + status?: string + /** + * The short description of the action that appears at the top of the record. Character limit: 255. + */ + summary?: string + /** + * Additional description of the action to complement the category. Available values are the entries in the Actions table. + */ + type?: string + /** + * The author of the action's summary and description. If not supplied, will have a default set based on the user's account. Character limit: 50. + */ + author?: string + /** + * The constituent's address. + */ + constituent_address?: { + address_lines?: string + city?: string + country?: string + do_not_mail?: boolean + postal_code?: string + primary?: boolean + state?: string + type?: string + } + /** + * The constituent's birthdate. + */ + constituent_birthdate?: string | number + /** + * The constituent's email address. + */ + constituent_email?: { + address?: string + do_not_email?: boolean + primary?: boolean + type?: string + } + /** + * The constituent's first name up to 50 characters. + */ + constituent_first?: string + /** + * The constituent's gender. + */ + constituent_gender?: string + /** + * The constituent's income. + */ + constituent_income?: string + /** + * The constituent's last name up to 100 characters. This is required to create a constituent. + */ + constituent_last?: string + /** + * The organization-defined identifier for the constituent. + */ + constituent_lookup_id?: string + /** + * The constituent's online presence. + */ + constituent_online_presence?: { + address?: string + primary?: boolean + type?: string + } + /** + * The constituent's phone number. + */ + constituent_phone?: { + do_not_call?: boolean + number?: string + primary?: boolean + type?: string + } +} diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts new file mode 100644 index 0000000000..0bcf1b2ee4 --- /dev/null +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts @@ -0,0 +1,161 @@ +import { ActionDefinition, ExecuteInput, InputField, IntegrationError, RequestFn } from '@segment/actions-core' +import type { Settings } from '../generated-types' +import type { Payload } from '../createConstituentAction/generated-types' +import { + fields as createOrUpdateIndividualConstituentFields, + perform as performCreateOrUpdateIndividualConstituent +} from '../createOrUpdateIndividualConstituent' +import { BlackbaudSkyApi } from '../api' +import { ConstituentAction, StringIndexedObject } from '../types' +import { buildConstituentActionDataFromPayload, buildConstituentPayloadFromPayload } from '../utils' + +const fields: Record = { + constituent_id: { + label: 'Constituent ID', + description: 'The ID of the constituent associated with the action.', + type: 'string' + }, + date: { + label: 'Date', + description: 'The action date in ISO-8601 format.', + type: 'datetime', + required: true, + default: { + '@path': '$.timestamp' + } + }, + category: { + label: 'Category', + description: + 'The channel or intent of the constituent interaction. Available values are Phone Call, Meeting, Mailing, Email, and Task/Other.', + type: 'string', + required: true + }, + completed: { + label: 'Completed', + description: 'Indicates whether the action is complete.', + type: 'boolean' + }, + completed_date: { + label: 'Completed Date', + description: 'The date when the action was completed in ISO-8601 format.', + type: 'datetime' + }, + description: { + label: 'Description', + description: 'The detailed explanation that elaborates on the action summary.', + type: 'string' + }, + direction: { + label: 'Direction', + description: 'The direction of the action. Available values are "Inbound" and "Outbound". The default is Inbound.', + type: 'string', + default: 'Inbound' + }, + end_time: { + label: 'End Time', + description: 'The end time of the action. Uses 24-hour time in the HH:mm format.', + type: 'string' + }, + fundraisers: { + label: 'Fundraisers', + description: 'The set of immutable constituent system record IDs for the fundraisers associated with the action.', + type: 'string' + }, + location: { + label: 'Location', + description: 'The location of the action. Available values are the entries in the Action Locations table.', + type: 'string' + }, + opportunity_id: { + label: 'Opportunity ID', + description: 'The immutable system record ID of the opportunity associated with the action.', + type: 'string' + }, + outcome: { + label: 'Outcome', + description: 'The outcome of the action. Available values are Successful and Unsuccessful.', + type: 'string' + }, + priority: { + label: 'Priority', + description: 'The priority of the action. Available values are Normal, High, and Low. The default is Normal.', + type: 'string', + default: 'Normal' + }, + start_time: { + label: 'Start Time', + description: 'The start time of the action. Uses 24-hour time in the HH:mm format.', + type: 'string' + }, + status: { + label: 'Status', + description: + 'The action status. If the system is configured to use custom action statuses, available values are the entries in the Action Status table.', + type: 'string' + }, + summary: { + label: 'Summary', + description: 'The short description of the action that appears at the top of the record. Character limit: 255.', + type: 'string' + }, + type: { + label: 'Type', + description: + 'Additional description of the action to complement the category. Available values are the entries in the Actions table.', + type: 'string' + }, + author: { + label: 'Author', + description: + "The author of the action's summary and description. If not supplied, will have a default set based on the user's account. Character limit: 50.", + type: 'string' + } +} + +Object.keys(createOrUpdateIndividualConstituentFields).forEach((key: string) => { + let fieldKey = 'constituent_' + key + let fieldLabel = 'Constituent ' + createOrUpdateIndividualConstituentFields[key].label + if (key === 'constituent_id') { + fieldKey = key + fieldLabel = createOrUpdateIndividualConstituentFields[key].label + } + fields[fieldKey] = { + ...createOrUpdateIndividualConstituentFields[key], + label: fieldLabel + } +}) + +const perform: RequestFn = async (request, { settings, payload }) => { + // Refactor this into a method that createGift can use as well + const constituentPayload = buildConstituentPayloadFromPayload(payload as StringIndexedObject) + + let constituentId = payload.constituent_id + if (Object.keys(constituentPayload).length > 0) { + const createOrUpdateIndividualConstituentResponse = await performCreateOrUpdateIndividualConstituent(request, { + settings: settings, + payload: constituentPayload + } as ExecuteInput) + constituentId = createOrUpdateIndividualConstituentResponse.id + } else if (constituentId === undefined) { + throw new IntegrationError('Missing constituent_id value', 'MISSING_REQUIRED_FIELD', 400) + } + + const blackbaudSkyApiClient: BlackbaudSkyApi = new BlackbaudSkyApi(request) + + const constituentActionData = buildConstituentActionDataFromPayload( + constituentId as string, + payload + ) as ConstituentAction + + return blackbaudSkyApiClient.createConstituentAction(constituentActionData) +} + +const action: ActionDefinition = { + title: 'Create Constituent Action', + description: "Create a Constituent Action record in Raiser's Edge NXT.", + fields, + perform +} + +export default action diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/index.ts index ef24abe14e..e153516bb2 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/index.ts @@ -5,6 +5,8 @@ import { RefreshTokenResponse } from './types' import createGift from './createGift' import createOrUpdateIndividualConstituent from './createOrUpdateIndividualConstituent' +import createConstituentAction from './createConstituentAction' + const destination: DestinationDefinition = { name: "Blackbaud Raiser's Edge NXT", slug: 'actions-blackbaud-raisers-edge-nxt', @@ -56,7 +58,8 @@ const destination: DestinationDefinition = { actions: { createGift, - createOrUpdateIndividualConstituent + createOrUpdateIndividualConstituent, + createConstituentAction } } diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/types/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/types/index.ts index f1be3ceab5..2cc81c8822 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/types/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/types/index.ts @@ -139,3 +139,24 @@ export interface RecurringGiftSchedule { frequency: string start_date: string | number } + +export interface ConstituentAction { + constituent_id: string + date: string | number + category: string + completed?: boolean + completed_date?: string | number + description?: string + direction?: string + end_time?: string + fundraisers?: string[] + location?: string + opportunity_id?: string + outcome?: string + priority?: string + start_time?: string + status?: string + summary?: string + type?: string + author?: string +} diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts index ee49d45f9c..c0379490ed 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts @@ -1,6 +1,7 @@ import { Address, Constituent, + ConstituentAction, Email, Gift, GiftAcknowledgement, @@ -11,6 +12,7 @@ import { } from '../types' import { Payload as CreateOrUpdateIndividualConstituentPayload } from '../createOrUpdateIndividualConstituent/generated-types' import { Payload as CreateGiftPayload } from '../createGift/generated-types' +import { Payload as CreateConstituentAction } from '../createConstituentAction/generated-types' export const dateStringToFuzzyDate = (dateString: string | number) => { // Ignore timezone @@ -206,6 +208,41 @@ export const buildGiftDataFromPayload = (constituentId: string, payload: CreateG return giftData } +export const buildConstituentActionDataFromPayload = (constituentId: string, payload: CreateConstituentAction) => { + // data for constituent action call + const constituentActionData: Partial = { + constituent_id: constituentId, + date: payload.date, + category: payload.category, + completed: payload.completed, + completed_date: payload.completed_date, + description: payload.description, + direction: payload.direction, + end_time: payload.end_time, + location: payload.location, + opportunity_id: payload.opportunity_id, + outcome: payload.outcome, + priority: payload.priority, + start_time: payload.start_time, + status: payload.status, + summary: payload.summary, + type: payload.type, + author: payload.author + } + Object.keys(constituentActionData).forEach((key) => { + if (!constituentActionData[key as keyof ConstituentAction]) { + delete constituentActionData[key as keyof ConstituentAction] + } + }) + + // create fundraisers array + if (payload.fundraisers) { + constituentActionData.fundraisers = payload.fundraisers.split(',') + } + + return constituentActionData +} + export const filterObjectListByMatchFields = ( list: StringIndexedObject[], data: StringIndexedObject, From cab7fd7c0cddb112ef3e5fe31c79d5ec0648f3d2 Mon Sep 17 00:00:00 2001 From: Noah Cooper Date: Sat, 18 Feb 2023 08:22:19 -0500 Subject: [PATCH 2/5] Remove constituent_id since it is provided by constituent fields --- .../createConstituentAction/generated-types.ts | 8 ++++---- .../createConstituentAction/index.ts | 5 ----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts index 0b9fb3f009..292cb08da7 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts @@ -1,10 +1,6 @@ // Generated file. DO NOT MODIFY IT BY HAND. export interface Payload { - /** - * The ID of the constituent. - */ - constituent_id?: string /** * The action date in ISO-8601 format. */ @@ -90,6 +86,10 @@ export interface Payload { * The constituent's birthdate. */ constituent_birthdate?: string | number + /** + * The ID of the constituent. + */ + constituent_id?: string /** * The constituent's email address. */ diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts index 0bcf1b2ee4..b600b137fb 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts @@ -10,11 +10,6 @@ import { ConstituentAction, StringIndexedObject } from '../types' import { buildConstituentActionDataFromPayload, buildConstituentPayloadFromPayload } from '../utils' const fields: Record = { - constituent_id: { - label: 'Constituent ID', - description: 'The ID of the constituent associated with the action.', - type: 'string' - }, date: { label: 'Date', description: 'The action date in ISO-8601 format.', From b695a8815d9700d9115c439b0d3c7ec975a0f805 Mon Sep 17 00:00:00 2001 From: Hywel Wong Date: Fri, 3 Mar 2023 11:12:06 -0800 Subject: [PATCH 3/5] Add augmentFieldsWithConstituentFields --- .../createConstituentAction/index.ts | 26 +++++-------------- .../createGift/index.ts | 26 +++++-------------- .../blackbaud-raisers-edge-nxt/utils/index.ts | 22 ++++++++++++++-- 3 files changed, 34 insertions(+), 40 deletions(-) diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts index b600b137fb..99506bfbc6 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts @@ -1,15 +1,16 @@ import { ActionDefinition, ExecuteInput, InputField, IntegrationError, RequestFn } from '@segment/actions-core' import type { Settings } from '../generated-types' import type { Payload } from '../createConstituentAction/generated-types' -import { - fields as createOrUpdateIndividualConstituentFields, - perform as performCreateOrUpdateIndividualConstituent -} from '../createOrUpdateIndividualConstituent' +import { perform as performCreateOrUpdateIndividualConstituent } from '../createOrUpdateIndividualConstituent' import { BlackbaudSkyApi } from '../api' import { ConstituentAction, StringIndexedObject } from '../types' -import { buildConstituentActionDataFromPayload, buildConstituentPayloadFromPayload } from '../utils' +import { + augmentFieldsWithConstituentFields, + buildConstituentActionDataFromPayload, + buildConstituentPayloadFromPayload +} from '../utils' -const fields: Record = { +const fields: Record = augmentFieldsWithConstituentFields({ date: { label: 'Date', description: 'The action date in ISO-8601 format.', @@ -106,19 +107,6 @@ const fields: Record = { "The author of the action's summary and description. If not supplied, will have a default set based on the user's account. Character limit: 50.", type: 'string' } -} - -Object.keys(createOrUpdateIndividualConstituentFields).forEach((key: string) => { - let fieldKey = 'constituent_' + key - let fieldLabel = 'Constituent ' + createOrUpdateIndividualConstituentFields[key].label - if (key === 'constituent_id') { - fieldKey = key - fieldLabel = createOrUpdateIndividualConstituentFields[key].label - } - fields[fieldKey] = { - ...createOrUpdateIndividualConstituentFields[key], - label: fieldLabel - } }) const perform: RequestFn = async (request, { settings, payload }) => { diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createGift/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createGift/index.ts index 6b3f70dd29..aebe62ea9c 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createGift/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createGift/index.ts @@ -1,15 +1,16 @@ import { ActionDefinition, ExecuteInput, InputField, IntegrationError, RequestFn } from '@segment/actions-core' import type { Settings } from '../generated-types' import type { Payload } from './generated-types' -import { - fields as createOrUpdateIndividualConstituentFields, - perform as performCreateOrUpdateIndividualConstituent -} from '../createOrUpdateIndividualConstituent' +import { perform as performCreateOrUpdateIndividualConstituent } from '../createOrUpdateIndividualConstituent' import { BlackbaudSkyApi } from '../api' import { Gift, StringIndexedObject } from '../types' -import { buildConstituentPayloadFromPayload, buildGiftDataFromPayload } from '../utils' +import { + augmentFieldsWithConstituentFields, + buildConstituentPayloadFromPayload, + buildGiftDataFromPayload +} from '../utils' -const fields: Record = { +const fields: Record = augmentFieldsWithConstituentFields({ acknowledgement: { label: 'Acknowledgement', description: 'The gift acknowledgement.', @@ -214,19 +215,6 @@ const fields: Record = { { label: 'RecurringGiftPayment', value: 'RecurringGiftPayment' } ] } -} - -Object.keys(createOrUpdateIndividualConstituentFields).forEach((key: string) => { - let fieldKey = 'constituent_' + key - let fieldLabel = 'Constituent ' + createOrUpdateIndividualConstituentFields[key].label - if (key === 'constituent_id') { - fieldKey = key - fieldLabel = createOrUpdateIndividualConstituentFields[key].label - } - fields[fieldKey] = { - ...createOrUpdateIndividualConstituentFields[key], - label: fieldLabel - } }) const perform: RequestFn = async (request, { settings, payload }) => { diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts index c0379490ed..68c16c31e8 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts @@ -1,3 +1,4 @@ +import { InputField } from '@segment/actions-core' import { Address, Constituent, @@ -10,9 +11,10 @@ import { Phone, StringIndexedObject } from '../types' -import { Payload as CreateOrUpdateIndividualConstituentPayload } from '../createOrUpdateIndividualConstituent/generated-types' -import { Payload as CreateGiftPayload } from '../createGift/generated-types' import { Payload as CreateConstituentAction } from '../createConstituentAction/generated-types' +import { Payload as CreateGiftPayload } from '../createGift/generated-types' +import { Payload as CreateOrUpdateIndividualConstituentPayload } from '../createOrUpdateIndividualConstituent/generated-types' +import { fields as createOrUpdateIndividualConstituentFields } from '../createOrUpdateIndividualConstituent' export const dateStringToFuzzyDate = (dateString: string | number) => { // Ignore timezone @@ -32,6 +34,22 @@ export const dateStringToFuzzyDate = (dateString: string | number) => { } } +export const augmentFieldsWithConstituentFields = (fields: Record) => { + Object.keys(createOrUpdateIndividualConstituentFields).forEach((key: string) => { + let fieldKey = 'constituent_' + key + let fieldLabel = 'Constituent ' + createOrUpdateIndividualConstituentFields[key].label + if (key === 'constituent_id') { + fieldKey = key + fieldLabel = createOrUpdateIndividualConstituentFields[key].label + } + fields[fieldKey] = { + ...createOrUpdateIndividualConstituentFields[key], + label: fieldLabel + } + }) + return fields +} + export const splitConstituentPayload = (payload: CreateOrUpdateIndividualConstituentPayload) => { const constituentData: Partial = { first: payload.first, From e5ac60f0d64c03be672155318d002fd0487d36b5 Mon Sep 17 00:00:00 2001 From: Hywel Wong Date: Fri, 3 Mar 2023 14:28:41 -0800 Subject: [PATCH 4/5] Cleaned up and updated fields --- .../__snapshots__/snapshot.test.ts.snap | 4 +-- .../__snapshots__/snapshot.test.ts.snap | 4 +-- .../generated-types.ts | 6 ++-- .../createConstituentAction/index.ts | 35 +++++++++++++++---- .../blackbaud-raisers-edge-nxt/utils/index.ts | 6 +--- 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/__tests__/__snapshots__/snapshot.test.ts.snap index 2f762eea36..1a432beec1 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/__tests__/__snapshots__/snapshot.test.ts.snap +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/__tests__/__snapshots__/snapshot.test.ts.snap @@ -3,8 +3,8 @@ exports[`Testing snapshot for actions-blackbaud-raisers-edge-nxt destination: createConstituentAction action - all fields 1`] = ` Object { "birthdate": Object { - "d": "31", - "m": "1", + "d": "1", + "m": "2", "y": "2021", }, "first": "x3tNm3W0", diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/__snapshots__/snapshot.test.ts.snap index 0ae000165e..d62257682b 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/__snapshots__/snapshot.test.ts.snap +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/__tests__/__snapshots__/snapshot.test.ts.snap @@ -3,8 +3,8 @@ exports[`Testing snapshot for BlackbaudRaisersEdgeNxt's createConstituentAction destination action: all fields 1`] = ` Object { "birthdate": Object { - "d": "31", - "m": "1", + "d": "1", + "m": "2", "y": "2021", }, "first": "bUa9Yg9hQ", diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts index 292cb08da7..2d28ca2593 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/generated-types.ts @@ -26,13 +26,13 @@ export interface Payload { */ direction?: string /** - * The end time of the action. Uses 24-hour time in the HH:mm format. + * The end time of the action. Uses 24-hour time in the HH:mm format. For example, 17:30 represents 5:30 p.m. */ end_time?: string /** * The set of immutable constituent system record IDs for the fundraisers associated with the action. */ - fundraisers?: string + fundraisers?: string[] /** * The location of the action. Available values are the entries in the Action Locations table. */ @@ -50,7 +50,7 @@ export interface Payload { */ priority?: string /** - * The start time of the action. Uses 24-hour time in the HH:mm format. + * The start time of the action. Uses 24-hour time in the HH:mm format. For example, 17:30 represents 5:30 p.m. */ start_time?: string /** diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts index 99506bfbc6..3ce9a22735 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts @@ -25,7 +25,14 @@ const fields: Record = augmentFieldsWithConstituentFields({ description: 'The channel or intent of the constituent interaction. Available values are Phone Call, Meeting, Mailing, Email, and Task/Other.', type: 'string', - required: true + required: true, + choices: [ + { label: 'Phone Call', value: 'Phone Call' }, + { label: 'Meeting', value: 'Meeting' }, + { label: 'Mailing', value: 'Mailing' }, + { label: 'Email', value: 'Email' }, + { label: 'Task/Other', value: 'Task/Other' } + ] }, completed: { label: 'Completed', @@ -46,17 +53,22 @@ const fields: Record = augmentFieldsWithConstituentFields({ label: 'Direction', description: 'The direction of the action. Available values are "Inbound" and "Outbound". The default is Inbound.', type: 'string', - default: 'Inbound' + default: 'Inbound', + choices: [ + { label: 'Inbound', value: 'Inbound' }, + { label: 'Outbound', value: 'Outbound' } + ] }, end_time: { label: 'End Time', - description: 'The end time of the action. Uses 24-hour time in the HH:mm format.', + description: 'The end time of the action. Uses 24-hour time in the HH:mm format. For example, 17:30 represents 5:30 p.m.', type: 'string' }, fundraisers: { label: 'Fundraisers', description: 'The set of immutable constituent system record IDs for the fundraisers associated with the action.', - type: 'string' + type: 'string', + multiple: true }, location: { label: 'Location', @@ -71,17 +83,26 @@ const fields: Record = augmentFieldsWithConstituentFields({ outcome: { label: 'Outcome', description: 'The outcome of the action. Available values are Successful and Unsuccessful.', - type: 'string' + type: 'string', + choices: [ + { label: 'Successful', value: 'Successful' }, + { label: 'Unsuccessful', value: 'Unsuccessful' } + ] }, priority: { label: 'Priority', description: 'The priority of the action. Available values are Normal, High, and Low. The default is Normal.', type: 'string', - default: 'Normal' + default: 'Normal', + choices: [ + { label: 'High', value: 'High' }, + { label: 'Low', value: 'Low' }, + { label: 'Normal', value: 'Normal' } + ] }, start_time: { label: 'Start Time', - description: 'The start time of the action. Uses 24-hour time in the HH:mm format.', + description: 'The start time of the action. Uses 24-hour time in the HH:mm format. For example, 17:30 represents 5:30 p.m.', type: 'string' }, status: { diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts index 68c16c31e8..da1ce4356b 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/utils/index.ts @@ -237,6 +237,7 @@ export const buildConstituentActionDataFromPayload = (constituentId: string, pay description: payload.description, direction: payload.direction, end_time: payload.end_time, + fundraisers: payload.fundraisers, location: payload.location, opportunity_id: payload.opportunity_id, outcome: payload.outcome, @@ -253,11 +254,6 @@ export const buildConstituentActionDataFromPayload = (constituentId: string, pay } }) - // create fundraisers array - if (payload.fundraisers) { - constituentActionData.fundraisers = payload.fundraisers.split(',') - } - return constituentActionData } From 274c5d8d5b2dca60ede1a7b471e0348d7db24244 Mon Sep 17 00:00:00 2001 From: Hywel Wong Date: Mon, 6 Mar 2023 09:25:33 -0800 Subject: [PATCH 5/5] Removed comment --- .../blackbaud-raisers-edge-nxt/createConstituentAction/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts index 3ce9a22735..82eaae93f7 100644 --- a/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts +++ b/packages/destination-actions/src/destinations/blackbaud-raisers-edge-nxt/createConstituentAction/index.ts @@ -131,7 +131,6 @@ const fields: Record = augmentFieldsWithConstituentFields({ }) const perform: RequestFn = async (request, { settings, payload }) => { - // Refactor this into a method that createGift can use as well const constituentPayload = buildConstituentPayloadFromPayload(payload as StringIndexedObject) let constituentId = payload.constituent_id