From 91bad07037ac6340d6723d47f7a35c11e0c21030 Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Wed, 21 Aug 2024 10:17:31 -0600 Subject: [PATCH 01/17] docs: add prerequisite for bash terminal --- docs/GETTING-STARTED.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/GETTING-STARTED.md b/docs/GETTING-STARTED.md index 0128bc1..6a58f01 100644 --- a/docs/GETTING-STARTED.md +++ b/docs/GETTING-STARTED.md @@ -7,6 +7,8 @@ Before getting started with C3 for Amazon Connect, please ensure the following: - You have a current C3 vendor account - You have an AWS account - You have an Amazon Connect instance +- You are able to run commands from a bash terminal + - If you are using Windows, you can use the [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install) to run bash commands. - You have Node.js (v20+) and npm (v10+) installed on your machine - You have [installed and configured the AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_auth) on your machine From 87785ab9996cb0f81d303855fa89886960e047fa Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Wed, 21 Aug 2024 11:09:22 -0600 Subject: [PATCH 02/17] chore: bump version number --- bin/c3-amazon-connect.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/c3-amazon-connect.ts b/bin/c3-amazon-connect.ts index 085835d..31e33c3 100644 --- a/bin/c3-amazon-connect.ts +++ b/bin/c3-amazon-connect.ts @@ -32,7 +32,7 @@ async function getMostRecentGitTag(): Promise { return stdout.trim(); } catch (error) { console.error('Error fetching the most recent git tag:', error); - return 'v2.1.0'; + return 'v2.2.0'; } } From 812ce0663c313f6884388e0c61f1d7500efc7744 Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:00:09 -0600 Subject: [PATCH 03/17] fix: handle situation where error messages from Zift weren't spoken correctly --- lib/lambda/c3-tokenize-transaction/index.js | 3 ++- lib/lambda/c3-utils-layer/lib/nodejs/formatting.js | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 lib/lambda/c3-utils-layer/lib/nodejs/formatting.js diff --git a/lib/lambda/c3-tokenize-transaction/index.js b/lib/lambda/c3-tokenize-transaction/index.js index 80f763d..717071d 100644 --- a/lib/lambda/c3-tokenize-transaction/index.js +++ b/lib/lambda/c3-tokenize-transaction/index.js @@ -1,4 +1,5 @@ import { decryptData } from '/opt/nodejs/decryption.js'; +import { stripTagsFromText } from '/opt/nodejs/formatting.js'; import { PaymentGateway } from './gateways/payment-gateway.js'; const REDACTED = 'REDACTED'; @@ -68,7 +69,7 @@ export async function handler(event) { // Return the error message to the flow. return { PaymentToken: 'NULL', - Error: tokenizeError.message, + Error: stripTagsFromText(tokenizeError.message), }; } } diff --git a/lib/lambda/c3-utils-layer/lib/nodejs/formatting.js b/lib/lambda/c3-utils-layer/lib/nodejs/formatting.js new file mode 100644 index 0000000..d691fef --- /dev/null +++ b/lib/lambda/c3-utils-layer/lib/nodejs/formatting.js @@ -0,0 +1,12 @@ +/** + * Removes any HTML tags from the given text. + * + * This function is useful for formatting messages to be spoken, to + * ensure that the SSML is not spoken as part of the message. + * + * @param {string} text The text to strip HTML tags from. + * @returns {string} The text with HTML tags removed. + */ +export function stripTagsFromText(text) { + return text.replace(/<[^>]*>/g, ''); +} From 0e3bded031b47552aa0cf31e627f567afe308cc3 Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:19:16 -0600 Subject: [PATCH 04/17] chore: add SSML to dictionary --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 69463db..6ed2a7d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,7 @@ "Popout", "Runtimes", "Softphone", + "SSML", "Tokenizes", "Visualforce", "Zift" From f56b9debe9b0d806c19213974ebc2c9feafd41c8 Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:15:59 -0600 Subject: [PATCH 05/17] feat(ivr): add basic bank account number length validation --- lib/lambda/c3-validate-entry/bank/validation.js | 7 +++++-- lib/lambda/c3-validate-entry/card/validation.js | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/lambda/c3-validate-entry/bank/validation.js b/lib/lambda/c3-validate-entry/bank/validation.js index cf845b9..281d0c5 100644 --- a/lib/lambda/c3-validate-entry/bank/validation.js +++ b/lib/lambda/c3-validate-entry/bank/validation.js @@ -3,14 +3,17 @@ import { ABARoutingNumber } from './routing-number/formats/aba-routing-number.js /** * Validates a bank account number. * - * There is currently no standard format for US bank account numbers, so this function only checks if the account number is present. + * There is currently no standard format for US bank account numbers, so this function only checks if the account number is between + * 4 and 17 digits. * * @param {string} accountNumber The bank account number to validate. * @returns {string | null} An IVR-speakable error message if the bank account number is invalid, or null if it's valid. */ export function validateAccountNumber(accountNumber) { if (!accountNumber) { - return 'Account number is required.'; + return 'An account number is required.'; + } else if (accountNumber.length < 4 || accountNumber.length > 17) { + return 'The account number must be between 4 and 17 digits.'; } return null; } diff --git a/lib/lambda/c3-validate-entry/card/validation.js b/lib/lambda/c3-validate-entry/card/validation.js index 886947b..a82e977 100644 --- a/lib/lambda/c3-validate-entry/card/validation.js +++ b/lib/lambda/c3-validate-entry/card/validation.js @@ -66,7 +66,7 @@ export function getCardNetwork(cardNumber) { */ export function validateExpirationDate(expirationDate) { if (!expirationDate) { - return 'Expiration date is required.'; + return 'An expiration date is required.'; } else if (!/^\d{4}$/.test(expirationDate)) { return 'The expiration date must be four digits long.'; } From 9c0b8c9e6d70331f1a48f7521b942840fe61e38e Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:11:05 -0600 Subject: [PATCH 06/17] refactor: rename option for deploying Amazon Connect workspace apps --- .github/workflows/checks.yml | 2 +- cdk.context.json | 2 +- docs/ALTERNATIVE_IMPORT.md | 2 +- docs/GETTING-STARTED.md | 2 +- lib/c3-amazon-connect-stack.ts | 6 ++++-- lib/models/amazon-connect-context.ts | 2 +- test/c3-amazon-connect.test.ts | 2 +- test/features/agent-assisted-ivr.test.ts | 2 +- test/features/agent-assisted-link.test.ts | 2 +- test/features/self-service-ivr.test.ts | 2 +- test/features/subject-lookup.test.ts | 2 +- test/options/code-signing.test.ts | 2 +- test/options/workspace-app.test.ts | 4 ++-- 13 files changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 6161a01..fb8664e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -36,7 +36,7 @@ jobs: "instanceArn": "placeholder", "securityKeyId": "placeholder", "securityKeyCertificateContent": "-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n", - "workspaceApp": true, + "addAppsToWorkspace": true, "receiptQueueArn": "placeholder" }, "c3": { diff --git a/cdk.context.json b/cdk.context.json index 6b0ef2c..c445237 100644 --- a/cdk.context.json +++ b/cdk.context.json @@ -4,7 +4,7 @@ "instanceArn": "", "securityKeyId": "", "securityKeyCertificateContent": "", - "workspaceApp": true, + "addAppsToWorkspace": true, "receiptQueueArn": "" }, "c3": { diff --git a/docs/ALTERNATIVE_IMPORT.md b/docs/ALTERNATIVE_IMPORT.md index 332a869..b32edcd 100644 --- a/docs/ALTERNATIVE_IMPORT.md +++ b/docs/ALTERNATIVE_IMPORT.md @@ -11,7 +11,7 @@ It might be necessary to use the alternative import method in the following inst - This prevents even your _root_ user from having ECR permissions and they cannot be added. > [!TIP] -> If you are using Salesforce Service Cloud Voice, ensure that the `amazonConnect.workspaceApp` and `options.codeSigning` values are set to `false` in your `cdk.context.json` file. Your account will not have the necessary permissions for these items. +> If you are using Salesforce Service Cloud Voice, ensure that the `amazonConnect.addAppsToWorkspace` and `options.codeSigning` values are set to `false` in your `cdk.context.json` file. Your account will not have the necessary permissions for these items. ## Initial Deployment diff --git a/docs/GETTING-STARTED.md b/docs/GETTING-STARTED.md index 6a58f01..e065458 100644 --- a/docs/GETTING-STARTED.md +++ b/docs/GETTING-STARTED.md @@ -55,7 +55,7 @@ In order to facilitate this process, you will need to provide some values to the | `instanceArn` | The full ARN of your Amazon Connect Instance. You can find this in the AWS console and it should look something like `"arn:aws:connect:us-west-2:815407490078:instance/5c1f1fba-d5f1-4155-9e09-496456e58912"`. | | `securityKeyId` | The ID of the security key that you configured for your Amazon Connect instance. You can find this in the AWS console. | | `securityKeyCertificateContent` | The full content of the certificate associated with your Amazon Connect security key. Begins with `-----BEGIN CERTIFICATE-----` and ends with`-----END CERTIFICATE-----`. **Note**: This must be contained within a single string with newlines denoted with `\\n`. | -| `workspaceApp` | Whether to create the C3 Payment Request app for the Amazon Connect agent workspace. Defaults to `true`. You may want to set this to `false` if you plan to use the workspace through another interface, like Salesforce. **Note**: This option does nothing if no agent-assisted features are enabled. | +| `addAppsToWorkspace` | Whether to add third-party apps to the Amazon Connect agent workspace. Defaults to `true`. You may want to set this to `false` if you plan to use the workspace apps through another interface, like Salesforce. | | `receiptQueueArn` | **Optional**. The full ARN of the Amazon Connect queue to transfer to when there is no email present for the customer and they would like a receipt. This is only valid for self-service payments. If not provided, the customer will not be asked to transfer to an agent and will simply not receive a receipt. | ##### C3 diff --git a/lib/c3-amazon-connect-stack.ts b/lib/c3-amazon-connect-stack.ts index 0d39328..4a1187e 100644 --- a/lib/c3-amazon-connect-stack.ts +++ b/lib/c3-amazon-connect-stack.ts @@ -142,8 +142,10 @@ export class C3AmazonConnectStack extends Stack { this.featuresContext.agentAssistedIVR || this.featuresContext.agentAssistedLink ) { - const appUrl = this.getAppUrl(!this.amazonConnectContext.workspaceApp); - if (this.amazonConnectContext.workspaceApp) { + const appUrl = this.getAppUrl( + !this.amazonConnectContext.addAppsToWorkspace, + ); + if (this.amazonConnectContext.addAppsToWorkspace) { this.create3rdPartyApp(appUrl); } } diff --git a/lib/models/amazon-connect-context.ts b/lib/models/amazon-connect-context.ts index de92d0a..e8b81ab 100644 --- a/lib/models/amazon-connect-context.ts +++ b/lib/models/amazon-connect-context.ts @@ -2,7 +2,7 @@ export interface AmazonConnectContext { instanceArn: string; securityKeyId: string; securityKeyCertificateContent: string; - workspaceApp: boolean; + addAppsToWorkspace: boolean; receiptQueueArn: string; } diff --git a/test/c3-amazon-connect.test.ts b/test/c3-amazon-connect.test.ts index 7c29751..1dd7a4c 100644 --- a/test/c3-amazon-connect.test.ts +++ b/test/c3-amazon-connect.test.ts @@ -17,7 +17,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', - workspaceApp: true, + addAppsToWorkspace: true, receiptQueueArn: 'placeholder', }, c3: { diff --git a/test/features/agent-assisted-ivr.test.ts b/test/features/agent-assisted-ivr.test.ts index ae5bf57..44c8cb6 100644 --- a/test/features/agent-assisted-ivr.test.ts +++ b/test/features/agent-assisted-ivr.test.ts @@ -17,7 +17,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', - workspaceApp: true, + addAppsToWorkspace: true, receiptQueueArn: 'placeholder', }, c3: { diff --git a/test/features/agent-assisted-link.test.ts b/test/features/agent-assisted-link.test.ts index 17ffcea..c690148 100644 --- a/test/features/agent-assisted-link.test.ts +++ b/test/features/agent-assisted-link.test.ts @@ -17,7 +17,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', - workspaceApp: true, + addAppsToWorkspace: true, receiptQueueArn: 'placeholder', }, c3: { diff --git a/test/features/self-service-ivr.test.ts b/test/features/self-service-ivr.test.ts index 7306e00..8b4abcc 100644 --- a/test/features/self-service-ivr.test.ts +++ b/test/features/self-service-ivr.test.ts @@ -17,7 +17,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', - workspaceApp: true, + addAppsToWorkspace: true, receiptQueueArn: 'placeholder', }, c3: { diff --git a/test/features/subject-lookup.test.ts b/test/features/subject-lookup.test.ts index 12b6c04..182524a 100644 --- a/test/features/subject-lookup.test.ts +++ b/test/features/subject-lookup.test.ts @@ -17,7 +17,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', - workspaceApp: true, + addAppsToWorkspace: true, receiptQueueArn: 'placeholder', }, c3: { diff --git a/test/options/code-signing.test.ts b/test/options/code-signing.test.ts index aaa9d55..b1b9f59 100644 --- a/test/options/code-signing.test.ts +++ b/test/options/code-signing.test.ts @@ -17,7 +17,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', - workspaceApp: true, + addAppsToWorkspace: true, receiptQueueArn: 'placeholder', }, c3: { diff --git a/test/options/workspace-app.test.ts b/test/options/workspace-app.test.ts index 8f17c71..e6b6b94 100644 --- a/test/options/workspace-app.test.ts +++ b/test/options/workspace-app.test.ts @@ -17,7 +17,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', - workspaceApp: true, + addAppsToWorkspace: true, receiptQueueArn: 'placeholder', }, c3: { @@ -64,7 +64,7 @@ describe('Workspace app', () => { }); it('Has no 3rd party apps when flag is false', () => { - mockContext.amazonConnect.workspaceApp = false; + mockContext.amazonConnect.addAppsToWorkspace = false; const app = new App({ context: mockContext, }); From 9eeddba63bb1b458546996e46eddbfdc333f0b0d Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 10:14:30 -0600 Subject: [PATCH 07/17] refactor: record a list of all transaction IDs completed for the call --- lib/lambda/c3-submit-payment/index.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/lambda/c3-submit-payment/index.js b/lib/lambda/c3-submit-payment/index.js index 0c169b6..1c845b9 100644 --- a/lib/lambda/c3-submit-payment/index.js +++ b/lib/lambda/c3-submit-payment/index.js @@ -58,9 +58,19 @@ export async function handler(event) { : response.transaction.bankAccountNumber; const endingDigits = maskedNumber.slice(-4); + // Update the list of all transaction IDs. + const previousTransactionIds = contactAttributes.TransactionIds + ? JSON.parse(contactAttributes.TransactionIds) + : []; + const newTransactionIds = [ + ...previousTransactionIds, + response.transaction.id, + ]; + return { TransactionApproved: response.transactionApproved, TransactionId: response.transaction.id, + TransactionIds: JSON.stringify(newTransactionIds), TransactionMeta: response.transactionMeta, PaymentMethodEndingDigits: endingDigits, }; From 22aa00e542d84cd59b665b8abd3a7d961ef514de Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 12:48:43 -0600 Subject: [PATCH 08/17] feat: pass payment submission error messages to call flow and agent --- .../c3-agent-assisted-payment-ivr-flow.json | 1881 ++++++++------- .../modules/c3-payment-ivr-flow-module.json | 2071 +++++++++-------- lib/lambda/c3-submit-payment/index.js | 134 +- .../c3-tokenize-transaction/gateways/zift.js | 2 +- 4 files changed, 2138 insertions(+), 1950 deletions(-) diff --git a/lib/connect/flows/c3-agent-assisted-payment-ivr-flow.json b/lib/connect/flows/c3-agent-assisted-payment-ivr-flow.json index aff9163..4bcdf7b 100644 --- a/lib/connect/flows/c3-agent-assisted-payment-ivr-flow.json +++ b/lib/connect/flows/c3-agent-assisted-payment-ivr-flow.json @@ -16,7 +16,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "db8eee5c-dcb6-4a94-b381-2fa8700ea5cb", + "id": "a8dc521a-919a-49d9-930e-e7754386c958", "operator": { "name": "Is greater than", "value": "GreaterThan", @@ -53,12 +53,6 @@ "isFriendlyName": true, "dynamicParams": [] }, - "5a505241-be5a-4437-8d66-785eb1b0beca": { - "position": { - "x": 8133.6, - "y": 702.4 - } - }, "Record Token": { "position": { "x": 5218.4, @@ -67,55 +61,6 @@ "isFriendlyName": true, "dynamicParams": [] }, - "Report Payment Tokenized": { - "position": { - "x": 5439.2, - "y": 390.4 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": { - "EventText": false - } - }, - "Submit Payment": { - "position": { - "x": 5655.2, - "y": 391.2 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": {} - }, - "Record Transaction Attributes": { - "position": { - "x": 5896.8, - "y": 374.4 - }, - "isFriendlyName": true, - "dynamicParams": [] - }, - "Tokenize Transaction": { - "position": { - "x": 4746.4, - "y": 389.6 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": {} - }, "Report Routing Number Entered": { "position": { "x": 4280.8, @@ -238,36 +183,6 @@ }, "isFriendlyName": true }, - "Report Bank Account Selected Again": { - "position": { - "x": 285.6, - "y": -236.8 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": { - "EventText": false - } - }, - "Report Credit Card Selected Again": { - "position": { - "x": 218.4, - "y": -461.6 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": { - "EventText": false - } - }, "Use Payment Method Again Timeout": { "position": { "x": -345.6, @@ -299,11 +214,11 @@ "isFriendlyName": true, "conditionMetadata": [ { - "id": "65cd3d99-d8ea-4589-b55b-1606c11b5cc7", + "id": "b39478fb-425f-4dda-b9c9-9cb0180ee377", "value": "1" }, { - "id": "53267b11-ef0d-4a81-a3d9-6600b4548a16", + "id": "12c08af4-7076-45d0-9e6e-d1f9ece07a64", "value": "2" } ] @@ -317,7 +232,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "7232cdbc-9879-4fdd-ae36-72ddb428b063", + "id": "aca1925c-e022-4f0e-b849-b301c5bd70e9", "operator": { "name": "Equals", "value": "Equals", @@ -326,7 +241,7 @@ "value": "Card" }, { - "id": "200fe3b0-c4c7-4e6e-90e2-e031ba90eabd", + "id": "d88ad7e3-4d08-420e-89ff-6e444826fd44", "operator": { "name": "Equals", "value": "Equals", @@ -344,11 +259,11 @@ "isFriendlyName": true, "conditionMetadata": [ { - "id": "f3c91d2d-b454-4d83-9dfe-0279f2e3eca6", + "id": "2aa62622-3935-4a10-ac54-5df21368753d", "value": "1" }, { - "id": "7a216324-6b62-4bb9-97af-9b2a0dae09e5", + "id": "92b6a0cb-ebbb-429a-acd8-d1d8e9b972a2", "value": "2" } ] @@ -368,11 +283,11 @@ "isFriendlyName": true, "conditionMetadata": [ { - "id": "437a4d0c-a272-42cf-9b7e-c54b51991817", + "id": "896f3848-8106-4b97-992b-d2f17d61306c", "value": "1" }, { - "id": "b3360b4f-3749-44ed-ab86-29d43c4ef35a", + "id": "b1fc4fa2-42b3-4222-a64e-e4d2b98f5fe7", "value": "2" } ] @@ -544,10 +459,10 @@ "conditionMetadata": [], "countryCodePrefix": "+1" }, - "Report Payment Submission Error": { + "Report Card Number Entered": { "position": { - "x": 5888, - "y": 629.6 + "x": 2480.8, + "y": -180 }, "isFriendlyName": true, "parameters": { @@ -559,254 +474,207 @@ "EventText": false } }, - "Payment Submission Error": { + "Try Expiration Date Again": { "position": { - "x": 6128, - "y": 625.6 + "x": 3320.8, + "y": 62.4 }, "isFriendlyName": true }, - "Report Tokenization Error": { + "Store Encrypted Card Number": { "position": { - "x": 5882.4, - "y": 879.2 + "x": 2243.2, + "y": -180 }, "isFriendlyName": true, "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" + "Attributes": { + "EncryptedCardNumber": { + "useDynamic": true + } } }, - "dynamicMetadata": { - "EventText": false - } - }, - "Remove Failed Payment Token and Method": { - "position": { - "x": 6423.2, - "y": 841.6 - }, - "isFriendlyName": true, - "dynamicParams": [] + "dynamicParams": ["EncryptedCardNumber"] }, - "Payment Validation Error": { + "Card Number Validation Error": { "position": { - "x": 6126.4, - "y": 888 + "x": 1890.4, + "y": 44 }, "isFriendlyName": true }, - "Report Payment Processed": { + "Card Number Timeout Check": { "position": { - "x": 6115.2, - "y": 373.6 + "x": 1680, + "y": -376.8 }, "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" + "conditions": [], + "conditionMetadata": [ + { + "id": "fe3b7783-5612-4ead-8b0c-f20d17886cf3", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "Timeout" } - }, - "dynamicMetadata": { - "EventText": false - } + ] }, - "Check for Customer Email": { + "Check for Card Number Validation Error": { "position": { - "x": 6561.6, - "y": 478.4 + "x": 1996, + "y": -250.4 }, "isFriendlyName": true, "conditions": [], "conditionMetadata": [ { - "id": "2bd9ad21-8178-4669-9b7d-7e5c449ca492", + "id": "9fd01f49-b179-49c6-94a8-14481378e12d", "operator": { - "name": "Contains", - "value": "Contains", - "shortDisplay": "contains" + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" }, - "value": "@" + "value": "NULL" } ] }, - "Payment Success": { - "position": { - "x": 6340, - "y": 476.8 - }, - "isFriendlyName": true - }, - "Report Card Number Entered": { + "Validate Card Number": { "position": { - "x": 2480.8, - "y": -180 + "x": 1776.8, + "y": -175.2 }, "isFriendlyName": true, "parameters": { "LambdaFunctionARN": { - "displayName": "<>" + "displayName": "<>" + }, + "LambdaInvocationAttributes": { + "CustomerEntry": { + "useDynamic": true + } } }, "dynamicMetadata": { - "EventText": false + "ValidationType": false, + "CustomerEntry": true } }, - "Try Expiration Date Again": { - "position": { - "x": 3320.8, - "y": 62.4 - }, - "isFriendlyName": true - }, - "Report Validation Error": { + "Store Encrypted Account Number": { "position": { - "x": 5470.4, - "y": 707.2 + "x": 2291.2, + "y": 635.2 }, "isFriendlyName": true, "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - }, - "LambdaInvocationAttributes": { - "EventText": { + "Attributes": { + "EncryptedAccountNumber": { "useDynamic": true } } }, - "dynamicMetadata": { - "EventText": true - } + "dynamicParams": ["EncryptedAccountNumber"] }, - "Check for Tokenize Error": { + "Account Number Validation Error": { "position": { - "x": 4988.8, - "y": 379.2 + "x": 1960.8, + "y": 840 + }, + "isFriendlyName": true + }, + "Account Number Timeout Check": { + "position": { + "x": 1828.8, + "y": 430.4 }, "isFriendlyName": true, "conditions": [], "conditionMetadata": [ { - "id": "362fe29d-1f68-4fe4-a69e-5a050e627ba5", + "id": "eb198fe9-4132-45d4-8525-e11815e864e9", "operator": { "name": "Equals", "value": "Equals", "shortDisplay": "=" }, - "value": "NULL" + "value": "Timeout" } ] }, - "Speak Validation Error": { - "position": { - "x": 5225.6, - "y": 702.4 - }, - "isFriendlyName": true - }, - "Send Receipt": { + "Check for Account Number Validation Error": { "position": { - "x": 6803.2, - "y": 478.4 + "x": 2076, + "y": 545.6 }, "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" + "conditions": [], + "conditionMetadata": [ + { + "id": "9c6008be-55df-4959-ba9f-0809f9ceea76", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "NULL" } - }, - "dynamicMetadata": {} - }, - "Receipt Success": { - "position": { - "x": 7021.6, - "y": 391.2 - }, - "isFriendlyName": true + ] }, - "Report Receipt Email Error": { + "Validate Account Number": { "position": { - "x": 7033.6, - "y": 576 + "x": 1860.8, + "y": 631.2 }, "isFriendlyName": true, "parameters": { "LambdaFunctionARN": { - "displayName": "<>" + "displayName": "<>" + }, + "LambdaInvocationAttributes": { + "CustomerEntry": { + "useDynamic": true + } } }, "dynamicMetadata": { - "EventText": false + "ValidationType": false, + "CustomerEntry": true } }, - "Receipt Error": { + "Store Routing Number": { "position": { - "x": 7245.6, - "y": 578.4 - }, - "isFriendlyName": true - }, - "90dc6a63-2ae9-4c5f-b65f-75348779d0c6": { - "position": { - "x": 7914.4, - "y": 696 - } - }, - "Internal Error": { - "position": { - "x": 1320, - "y": 1038.4 - }, - "isFriendlyName": true - }, - "Redact Sensitive Contact Attributes": { - "position": { - "x": 7479.2, - "y": 705.6 - }, - "isFriendlyName": true, - "dynamicParams": [] - }, - "Returning To Agent": { - "position": { - "x": 7698.4, - "y": 701.6 - }, - "isFriendlyName": true - }, - "Store Encrypted Card Number": { - "position": { - "x": 2243.2, - "y": -180 + "x": 4047.2, + "y": 632 }, "isFriendlyName": true, "parameters": { "Attributes": { - "EncryptedCardNumber": { + "RoutingNumber": { "useDynamic": true } } }, - "dynamicParams": ["EncryptedCardNumber"] + "dynamicParams": ["RoutingNumber"] }, - "Card Number Validation Error": { + "Routing Number Validation Error": { "position": { - "x": 1890.4, - "y": 44 + "x": 3604, + "y": 886.4 }, "isFriendlyName": true }, - "Card Number Timeout Check": { + "Routing Number Timeout Check": { "position": { - "x": 1680, - "y": -376.8 + "x": 3396, + "y": 447.2 }, "isFriendlyName": true, "conditions": [], "conditionMetadata": [ { - "id": "f9511ba6-b778-4760-be2a-0f15683fbc91", + "id": "60803e6c-c1ed-494c-b629-0b9f96df765b", "operator": { "name": "Equals", "value": "Equals", @@ -816,16 +684,16 @@ } ] }, - "Check for Card Number Validation Error": { + "Check for Routing Number Validation Error": { "position": { - "x": 1996, - "y": -250.4 + "x": 3719.2, + "y": 595.2 }, "isFriendlyName": true, "conditions": [], "conditionMetadata": [ { - "id": "ebd07eeb-7f27-41bf-9280-de9c2c3fdf01", + "id": "1c837d4e-4985-414b-8222-f87b65fd6eef", "operator": { "name": "Equals", "value": "Equals", @@ -835,10 +703,10 @@ } ] }, - "Validate Card Number": { + "Validate Routing Number": { "position": { - "x": 1776.8, - "y": -175.2 + "x": 3471.2, + "y": 652.8 }, "isFriendlyName": true, "parameters": { @@ -856,38 +724,54 @@ "CustomerEntry": true } }, - "Store Encrypted Account Number": { + "Expiration Date Timeout": { "position": { - "x": 2291.2, - "y": 635.2 + "x": 3223.2, + "y": -557.6 + }, + "isFriendlyName": true + }, + "Get Expiration Date": { + "position": { + "x": 3256, + "y": -155.2 + }, + "isFriendlyName": true, + "conditionMetadata": [], + "countryCodePrefix": "+1" + }, + "Store Expiration Date": { + "position": { + "x": 4054.4, + "y": -175.2 }, "isFriendlyName": true, "parameters": { "Attributes": { - "EncryptedAccountNumber": { + "ExpirationDate": { "useDynamic": true } } }, - "dynamicParams": ["EncryptedAccountNumber"] + "dynamicParams": ["ExpirationDate"] }, - "Account Number Validation Error": { + "Expiration Date Validation Error": { "position": { - "x": 1960.8, - "y": 840 + "x": 3649.6, + "y": 50.4 }, "isFriendlyName": true }, - "Account Number Timeout Check": { + "Expiration Date Timeout Check": { "position": { - "x": 1828.8, - "y": 430.4 + "x": 3315.2, + "y": -353.6 }, "isFriendlyName": true, "conditions": [], "conditionMetadata": [ { - "id": "3daff475-825f-40de-aeb1-39066a975f55", + "id": "057289d9-e708-4161-8677-2f0cc94f8cee", "operator": { "name": "Equals", "value": "Equals", @@ -897,16 +781,16 @@ } ] }, - "Check for Account Number Validation Error": { + "Check for Expiration Date Validation Error": { "position": { - "x": 2076, - "y": 545.6 + "x": 3753.6, + "y": -271.2 }, "isFriendlyName": true, "conditions": [], "conditionMetadata": [ { - "id": "fbdc393c-2df1-443a-b10b-e6427aa300d2", + "id": "b724e0ed-9435-45d3-841e-c22c687b3237", "operator": { "name": "Equals", "value": "Equals", @@ -916,10 +800,10 @@ } ] }, - "Validate Account Number": { + "Validate Expiration Date": { "position": { - "x": 1860.8, - "y": 631.2 + "x": 3512.8, + "y": -155.2 }, "isFriendlyName": true, "parameters": { @@ -937,182 +821,344 @@ "CustomerEntry": true } }, - "Store Routing Number": { - "position": { - "x": 4047.2, - "y": 632 - }, - "isFriendlyName": true, - "parameters": { - "Attributes": { - "RoutingNumber": { - "useDynamic": true - } - } - }, - "dynamicParams": ["RoutingNumber"] - }, - "Routing Number Validation Error": { - "position": { - "x": 3604, - "y": 886.4 - }, - "isFriendlyName": true - }, - "Routing Number Timeout Check": { + "Check for Tokenize Error": { "position": { - "x": 3396, - "y": 447.2 + "x": 4988.8, + "y": 379.2 }, "isFriendlyName": true, "conditions": [], "conditionMetadata": [ { - "id": "978332d8-9023-43e0-9ceb-afc454bd108e", + "id": "9d6984ae-e96d-4b6b-9604-18f1272ea629", "operator": { "name": "Equals", "value": "Equals", "shortDisplay": "=" }, - "value": "Timeout" + "value": "NULL" } ] }, - "Check for Routing Number Validation Error": { + "Send Receipt": { "position": { - "x": 3719.2, - "y": 595.2 + "x": 7141.6, + "y": 472 }, "isFriendlyName": true, - "conditions": [], - "conditionMetadata": [ - { - "id": "e07fc5d6-7eae-4080-b874-fb5fadac823a", - "operator": { - "name": "Equals", - "value": "Equals", - "shortDisplay": "=" - }, - "value": "NULL" + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" } - ] + }, + "dynamicMetadata": {} }, - "Validate Routing Number": { + "Report Receipt Email Error": { "position": { - "x": 3471.2, - "y": 652.8 + "x": 7372, + "y": 569.6 }, "isFriendlyName": true, "parameters": { "LambdaFunctionARN": { - "displayName": "<>" - }, - "LambdaInvocationAttributes": { - "CustomerEntry": { - "useDynamic": true - } + "displayName": "<>" } }, "dynamicMetadata": { - "ValidationType": false, - "CustomerEntry": true + "EventText": false } }, - "Expiration Date Timeout": { + "5a505241-be5a-4437-8d66-785eb1b0beca": { "position": { - "x": 3223.2, - "y": -557.6 + "x": 8472, + "y": 696 + } + }, + "Internal Error": { + "position": { + "x": 1320, + "y": 1038.4 }, "isFriendlyName": true }, - "Get Expiration Date": { + "90dc6a63-2ae9-4c5f-b65f-75348779d0c6": { "position": { - "x": 3256, - "y": -155.2 + "x": 8252.8, + "y": 689.6 + } + }, + "Payment Success": { + "position": { + "x": 6678.4, + "y": 470.4 }, - "isFriendlyName": true, - "conditionMetadata": [], - "countryCodePrefix": "+1" + "isFriendlyName": true }, - "Store Expiration Date": { + "Receipt Success": { "position": { - "x": 4054.4, - "y": -175.2 + "x": 7360, + "y": 384.8 }, - "isFriendlyName": true, - "parameters": { - "Attributes": { - "ExpirationDate": { - "useDynamic": true - } - } + "isFriendlyName": true + }, + "Receipt Error": { + "position": { + "x": 7584, + "y": 572 }, - "dynamicParams": ["ExpirationDate"] + "isFriendlyName": true }, - "Expiration Date Validation Error": { + "Returning To Agent": { "position": { - "x": 3649.6, - "y": 50.4 + "x": 8036.8, + "y": 695.2 }, "isFriendlyName": true }, - "Expiration Date Timeout Check": { + "Check for Customer Email": { "position": { - "x": 3315.2, - "y": -353.6 + "x": 6900, + "y": 472 }, "isFriendlyName": true, "conditions": [], "conditionMetadata": [ { - "id": "a036f1bf-2754-46e7-aaf4-57bdc3463110", + "id": "694a6664-879d-4f49-afec-27575259b69d", "operator": { - "name": "Equals", - "value": "Equals", - "shortDisplay": "=" + "name": "Contains", + "value": "Contains", + "shortDisplay": "contains" }, - "value": "Timeout" + "value": "@" } ] }, - "Check for Expiration Date Validation Error": { + "Redact Sensitive Contact Attributes": { "position": { - "x": 3753.6, - "y": -271.2 + "x": 7817.6, + "y": 699.2 }, "isFriendlyName": true, - "conditions": [], - "conditionMetadata": [ - { - "id": "5a8c6d0e-e326-462c-a814-c02f04d275d5", - "operator": { - "name": "Equals", - "value": "Equals", - "shortDisplay": "=" - }, - "value": "NULL" - } - ] + "dynamicParams": [] }, - "Validate Expiration Date": { + "Report Payment Processed": { "position": { - "x": 3512.8, - "y": -155.2 + "x": 6453.6, + "y": 367.2 }, "isFriendlyName": true, "parameters": { "LambdaFunctionARN": { - "displayName": "<>" - }, - "LambdaInvocationAttributes": { - "CustomerEntry": { - "useDynamic": true - } + "displayName": "<>" } }, "dynamicMetadata": { - "ValidationType": false, - "CustomerEntry": true + "EventText": false + } + }, + "Report Payment Tokenized": { + "position": { + "x": 5439.2, + "y": 390.4 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Report Bank Account Selected Again": { + "position": { + "x": 285.6, + "y": -236.8 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Report Credit Card Selected Again": { + "position": { + "x": 218.4, + "y": -461.6 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Tokenize Transaction": { + "position": { + "x": 4746.4, + "y": 389.6 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": {} + }, + "Report Tokenization Error": { + "position": { + "x": 5056, + "y": 927.2 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Payment Validation Error": { + "position": { + "x": 5294.4, + "y": 934.4 + }, + "isFriendlyName": true + }, + "Record Transaction Attributes": { + "position": { + "x": 6172.8, + "y": 377.6 + }, + "isFriendlyName": true, + "dynamicParams": [] + }, + "Check for Submit Payment Error": { + "position": { + "x": 5896.8, + "y": 386.4 + }, + "isFriendlyName": true, + "conditions": [], + "conditionMetadata": [ + { + "id": "a21b3261-d9d2-4b46-a6e1-bf56502aa73d", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "NULL" + } + ] + }, + "Speak Payment Submission Error": { + "position": { + "x": 6177.6, + "y": 569.6 + }, + "isFriendlyName": true + }, + "Report Payment Submission Error": { + "position": { + "x": 6418.4, + "y": 578.4 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + }, + "LambdaInvocationAttributes": { + "EventText": { + "useDynamic": true + } + } + }, + "dynamicMetadata": { + "EventText": true + } + }, + "Speak Paymen Submission Unknown Error": { + "position": { + "x": 5920.8, + "y": 620.8 + }, + "isFriendlyName": true + }, + "Submit Payment": { + "position": { + "x": 5655.2, + "y": 391.2 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": {} + }, + "Report Payment Submission Unknown Error": { + "position": { + "x": 5708.8, + "y": 626.4 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Speak Validation Error": { + "position": { + "x": 5225.6, + "y": 702.4 + }, + "isFriendlyName": true + }, + "Remove Failed Payment Token and Method": { + "position": { + "x": 6761.6, + "y": 835.2 + }, + "isFriendlyName": true, + "dynamicParams": [] + }, + "Report Validation Error": { + "position": { + "x": 5470.4, + "y": 707.2 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + }, + "LambdaInvocationAttributes": { + "EventText": { + "useDynamic": true + } + } + }, + "dynamicMetadata": { + "EventText": true } } }, @@ -1259,12 +1305,6 @@ ] } }, - { - "Parameters": {}, - "Identifier": "5a505241-be5a-4437-8d66-785eb1b0beca", - "Type": "DisconnectParticipant", - "Transitions": {} - }, { "Parameters": { "Attributes": { @@ -1289,19 +1329,19 @@ "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "PaymentTokenized" + "EventText": "RoutingNumberEntered" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Payment Tokenized", + "Identifier": "Report Routing Number Entered", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Submit Payment", + "NextAction": "Tokenize Transaction", "Errors": [ { - "NextAction": "Submit Payment", + "NextAction": "Tokenize Transaction", "ErrorType": "NoMatchingError" } ] @@ -1309,19 +1349,22 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "ExpirationDateEntered" + }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Submit Payment", + "Identifier": "Report Expiration Entered", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Record Transaction Attributes", + "NextAction": "Tokenize Transaction", "Errors": [ { - "NextAction": "Report Payment Submission Error", + "NextAction": "Tokenize Transaction", "ErrorType": "NoMatchingError" } ] @@ -1329,19 +1372,22 @@ }, { "Parameters": { - "Attributes": { - "TransactionId": "$.External.TransactionId", - "PaymentMethodEndingDigits": "$.External.PaymentMethodEndingDigits" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "PaymentRequestError" }, - "TargetContact": "Current" + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Record Transaction Attributes", - "Type": "UpdateContactAttributes", + "Identifier": "Report Payment Request Error", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Report Payment Processed", + "NextAction": "Payment Request Error", "Errors": [ { - "NextAction": "Report Payment Processed", + "NextAction": "Payment Request Error", "ErrorType": "NoMatchingError" } ] @@ -1349,19 +1395,15 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "ResponseValidation": { - "ResponseType": "JSON" - } + "Text": "\n>\" rate=\"<>\">\nThere was an error creating the payment request.\n\n" }, - "Identifier": "Tokenize Transaction", - "Type": "InvokeLambdaFunction", + "Identifier": "Payment Request Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Check for Tokenize Error", + "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", "Errors": [ { - "NextAction": "Report Tokenization Error", + "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", "ErrorType": "NoMatchingError" } ] @@ -1372,104 +1414,19 @@ "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "RoutingNumberEntered" + "EventText": "NoPaymentInfoError" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Routing Number Entered", + "Identifier": "Report No Payment Info Error", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Tokenize Transaction", + "NextAction": "No Payment Information", "Errors": [ { - "NextAction": "Tokenize Transaction", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "ExpirationDateEntered" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } - }, - "Identifier": "Report Expiration Entered", - "Type": "InvokeLambdaFunction", - "Transitions": { - "NextAction": "Tokenize Transaction", - "Errors": [ - { - "NextAction": "Tokenize Transaction", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "PaymentRequestError" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } - }, - "Identifier": "Report Payment Request Error", - "Type": "InvokeLambdaFunction", - "Transitions": { - "NextAction": "Payment Request Error", - "Errors": [ - { - "NextAction": "Payment Request Error", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "Text": "\n>\" rate=\"<>\">\nThere was an error creating the payment request.\n\n" - }, - "Identifier": "Payment Request Error", - "Type": "MessageParticipant", - "Transitions": { - "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", - "Errors": [ - { - "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "NoPaymentInfoError" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } - }, - "Identifier": "Report No Payment Info Error", - "Type": "InvokeLambdaFunction", - "Transitions": { - "NextAction": "No Payment Information", - "Errors": [ - { - "NextAction": "No Payment Information", + "NextAction": "No Payment Information", "ErrorType": "NoMatchingError" } ] @@ -1584,52 +1541,6 @@ ] } }, - { - "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "BankAccountSelected" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } - }, - "Identifier": "Report Bank Account Selected Again", - "Type": "InvokeLambdaFunction", - "Transitions": { - "NextAction": "Submit Payment", - "Errors": [ - { - "NextAction": "Submit Payment", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "CreditCardSelected" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } - }, - "Identifier": "Report Credit Card Selected Again", - "Type": "InvokeLambdaFunction", - "Transitions": { - "NextAction": "Submit Payment", - "Errors": [ - { - "NextAction": "Submit Payment", - "ErrorType": "NoMatchingError" - } - ] - } - }, { "Parameters": { "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" @@ -2193,19 +2104,19 @@ "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "PaymentSubmissionError" + "EventText": "CardNumberEntered" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Payment Submission Error", + "Identifier": "Report Card Number Entered", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Payment Submission Error", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "Payment Submission Error", + "NextAction": "Get Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -2213,15 +2124,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nWe're sorry, an error has occured preventing us from submitting your payment. You have not been charged.\n\n" + "Text": "\n>\" rate=\"<>\">\nThere was a problem with your expiration date. Please check your entry and try again.\n\n" }, - "Identifier": "Payment Submission Error", + "Identifier": "Try Expiration Date Again", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "Get Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -2229,22 +2140,108 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", + "Attributes": { + "EncryptedCardNumber": "$.StoredCustomerInput" + }, + "TargetContact": "Current" + }, + "Identifier": "Store Encrypted Card Number", + "Type": "UpdateContactAttributes", + "Transitions": { + "NextAction": "Report Card Number Entered", + "Errors": [ + { + "NextAction": "Report Card Number Encryption Error", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" + }, + "Identifier": "Card Number Validation Error", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Get & Encrypt Card Number", + "Errors": [ + { + "NextAction": "Get & Encrypt Card Number", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "ComparisonValue": "$.StoredCustomerInput" + }, + "Identifier": "Card Number Timeout Check", + "Type": "Compare", + "Transitions": { + "NextAction": "Validate Card Number", + "Conditions": [ + { + "NextAction": "Card Number Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } + } + ], + "Errors": [ + { + "NextAction": "Validate Card Number", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "ComparisonValue": "$.External.ValidationError" + }, + "Identifier": "Check for Card Number Validation Error", + "Type": "Compare", + "Transitions": { + "NextAction": "Card Number Validation Error", + "Conditions": [ + { + "NextAction": "Store Encrypted Card Number", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], + "Errors": [ + { + "NextAction": "Card Number Validation Error", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "TokenizationError" + "ValidationType": "CardNumber", + "CustomerEntry": "$.StoredCustomerInput" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Tokenization Error", + "Identifier": "Validate Card Number", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Payment Validation Error", + "NextAction": "Check for Card Number Validation Error", "Errors": [ { - "NextAction": "Payment Validation Error", + "NextAction": "Store Encrypted Card Number", "ErrorType": "NoMatchingError" } ] @@ -2253,18 +2250,17 @@ { "Parameters": { "Attributes": { - "PaymentToken": "NULL", - "PaymentMethod": "NULL" + "EncryptedAccountNumber": "$.StoredCustomerInput" }, "TargetContact": "Current" }, - "Identifier": "Remove Failed Payment Token and Method", + "Identifier": "Store Encrypted Account Number", "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Report Account Number Entered", "Errors": [ { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Report Account Number Encryption Error", "ErrorType": "NoMatchingError" } ] @@ -2272,15 +2268,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nThere was a problem validating your $.Attributes.PaymentMethod information.\n\n" + "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" }, - "Identifier": "Payment Validation Error", + "Identifier": "Account Number Validation Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "Get & Encrypt Account Number", "Errors": [ { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "Get & Encrypt Account Number", "ErrorType": "NoMatchingError" } ] @@ -2288,22 +2284,73 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", + "ComparisonValue": "$.StoredCustomerInput" + }, + "Identifier": "Account Number Timeout Check", + "Type": "Compare", + "Transitions": { + "NextAction": "Validate Account Number", + "Conditions": [ + { + "NextAction": "Account Number Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } + } + ], + "Errors": [ + { + "NextAction": "Validate Account Number", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "ComparisonValue": "$.External.ValidationError" + }, + "Identifier": "Check for Account Number Validation Error", + "Type": "Compare", + "Transitions": { + "NextAction": "Account Number Validation Error", + "Conditions": [ + { + "NextAction": "Store Encrypted Account Number", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], + "Errors": [ + { + "NextAction": "Account Number Validation Error", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "PaymentProcessed" + "ValidationType": "AccountNumber", + "CustomerEntry": "$.StoredCustomerInput" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Payment Processed", + "Identifier": "Validate Account Number", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Payment Success", + "NextAction": "Check for Account Number Validation Error", "Errors": [ { - "NextAction": "Payment Success", + "NextAction": "Store Encrypted Account Number", "ErrorType": "NoMatchingError" } ] @@ -2311,40 +2358,186 @@ }, { "Parameters": { - "ComparisonValue": "$.Attributes.Email" + "Attributes": { + "RoutingNumber": "$.StoredCustomerInput" + }, + "TargetContact": "Current" }, - "Identifier": "Check for Customer Email", + "Identifier": "Store Routing Number", + "Type": "UpdateContactAttributes", + "Transitions": { + "NextAction": "Report Routing Number Entered", + "Errors": [ + { + "NextAction": "Report Routing Number Error", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" + }, + "Identifier": "Routing Number Validation Error", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Get Routing Number", + "Errors": [ + { + "NextAction": "Get Routing Number", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "ComparisonValue": "$.StoredCustomerInput" + }, + "Identifier": "Routing Number Timeout Check", "Type": "Compare", "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", - "Conditions": [ - { - "NextAction": "Send Receipt", - "Condition": { - "Operator": "TextContains", - "Operands": ["@"] - } - } - ], + "NextAction": "Validate Routing Number", + "Conditions": [ + { + "NextAction": "Routing Number Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } + } + ], + "Errors": [ + { + "NextAction": "Validate Routing Number", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "ComparisonValue": "$.External.ValidationError" + }, + "Identifier": "Check for Routing Number Validation Error", + "Type": "Compare", + "Transitions": { + "NextAction": "Routing Number Validation Error", + "Conditions": [ + { + "NextAction": "Store Routing Number", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], + "Errors": [ + { + "NextAction": "Routing Number Validation Error", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "ValidationType": "RoutingNumber", + "CustomerEntry": "$.StoredCustomerInput" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Validate Routing Number", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "Check for Routing Number Validation Error", + "Errors": [ + { + "NextAction": "Store Routing Number", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" + }, + "Identifier": "Expiration Date Timeout", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Get Expiration Date", + "Errors": [ + { + "NextAction": "Get Expiration Date", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "StoreInput": "True", + "InputTimeLimitSeconds": "5", + "Text": "\n>\" rate=\"<>\">\nPlease enter your card's expiration date in the format month-month-year-year, followed by the pound key when complete.\n\n", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" + }, + "InputValidation": { + "CustomValidation": { + "MaximumLength": "4" + } + } + }, + "Identifier": "Get Expiration Date", + "Type": "GetParticipantInput", + "Transitions": { + "NextAction": "Expiration Date Timeout Check", + "Errors": [ + { + "NextAction": "Try Expiration Date Again", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Attributes": { + "ExpirationDate": "$.StoredCustomerInput" + }, + "TargetContact": "Current" + }, + "Identifier": "Store Expiration Date", + "Type": "UpdateContactAttributes", + "Transitions": { + "NextAction": "Report Expiration Entered", "Errors": [ { - "NextAction": "Redact Sensitive Contact Attributes", - "ErrorType": "NoMatchingCondition" + "NextAction": "Report Expiration Date Error", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nYour payment was processed successfully.\n\n" + "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" }, - "Identifier": "Payment Success", + "Identifier": "Expiration Date Validation Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Check for Customer Email", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "Check for Customer Email", + "NextAction": "Get Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -2352,61 +2545,73 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "CardNumberEntered" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Report Card Number Entered", - "Type": "InvokeLambdaFunction", + "Identifier": "Expiration Date Timeout Check", + "Type": "Compare", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Validate Expiration Date", + "Conditions": [ + { + "NextAction": "Expiration Date Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } + } + ], "Errors": [ { - "NextAction": "Get Expiration Date", - "ErrorType": "NoMatchingError" + "NextAction": "Validate Expiration Date", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nThere was a problem with your expiration date. Please check your entry and try again.\n\n" + "ComparisonValue": "$.External.ValidationError" }, - "Identifier": "Try Expiration Date Again", - "Type": "MessageParticipant", + "Identifier": "Check for Expiration Date Validation Error", + "Type": "Compare", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Expiration Date Validation Error", + "Conditions": [ + { + "NextAction": "Store Expiration Date", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], "Errors": [ { - "NextAction": "Get Expiration Date", - "ErrorType": "NoMatchingError" + "NextAction": "Expiration Date Validation Error", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "LambdaFunctionARN": "<>", + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "$.External.Error" + "ValidationType": "ExpirationDate", + "CustomerEntry": "$.StoredCustomerInput" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Validation Error", + "Identifier": "Validate Expiration Date", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "Check for Expiration Date Validation Error", "Errors": [ { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "Store Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -2437,22 +2642,6 @@ ] } }, - { - "Parameters": { - "Text": "\n>\" rate=\"<>\">\nThe payment failed because of the following error:\n\n$.External.Error\n\n" - }, - "Identifier": "Speak Validation Error", - "Type": "MessageParticipant", - "Transitions": { - "NextAction": "Report Validation Error", - "Errors": [ - { - "NextAction": "Report Validation Error", - "ErrorType": "NoMatchingError" - } - ] - } - }, { "Parameters": { "LambdaFunctionARN": "<>", @@ -2473,22 +2662,6 @@ ] } }, - { - "Parameters": { - "Text": "\n>\" rate=\"<>\">\nA receipt has been sent to your email address, $.Attributes.['Email'].\n\n" - }, - "Identifier": "Receipt Success", - "Type": "MessageParticipant", - "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", - "Errors": [ - { - "NextAction": "Redact Sensitive Contact Attributes", - "ErrorType": "NoMatchingError" - } - ] - } - }, { "Parameters": { "LambdaFunctionARN": "<>", @@ -2512,17 +2685,23 @@ ] } }, + { + "Parameters": {}, + "Identifier": "5a505241-be5a-4437-8d66-785eb1b0beca", + "Type": "DisconnectParticipant", + "Transitions": {} + }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nThere was an error sending the receipt to your email address, $.Attributes.['Email']. Please contact customer support to receive a receipt for this transaction.\n\n" + "Text": "\n>\" rate=\"<>\">\nWe're sorry, an error has occurred that prevents us from collecting the payment.\n\n" }, - "Identifier": "Receipt Error", + "Identifier": "Internal Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Returning To Agent", "Errors": [ { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Returning To Agent", "ErrorType": "NoMatchingError" } ] @@ -2546,36 +2725,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nWe're sorry, an error has occurred that prevents us from collecting the payment.\n\n" + "Text": "\n>\" rate=\"<>\">\nYour payment was processed successfully.\n\n" }, - "Identifier": "Internal Error", + "Identifier": "Payment Success", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Returning To Agent", - "Errors": [ - { - "NextAction": "Returning To Agent", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "Attributes": { - "EncryptedCardNumber": "REDACTED", - "ExpirationDate": "REDACTED", - "EncryptedAccountNumber": "REDACTED" - }, - "TargetContact": "Current" - }, - "Identifier": "Redact Sensitive Contact Attributes", - "Type": "UpdateContactAttributes", - "Transitions": { - "NextAction": "Returning To Agent", + "NextAction": "Check for Customer Email", "Errors": [ { - "NextAction": "Returning To Agent", + "NextAction": "Check for Customer Email", "ErrorType": "NoMatchingError" } ] @@ -2583,15 +2741,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nReturning you to the agent...\n\n" + "Text": "\n>\" rate=\"<>\">\nA receipt has been sent to your email address, $.Attributes.['Email'].\n\n" }, - "Identifier": "Returning To Agent", + "Identifier": "Receipt Success", "Type": "MessageParticipant", "Transitions": { - "NextAction": "90dc6a63-2ae9-4c5f-b65f-75348779d0c6", + "NextAction": "Redact Sensitive Contact Attributes", "Errors": [ { - "NextAction": "90dc6a63-2ae9-4c5f-b65f-75348779d0c6", + "NextAction": "Redact Sensitive Contact Attributes", "ErrorType": "NoMatchingError" } ] @@ -2599,18 +2757,15 @@ }, { "Parameters": { - "Attributes": { - "EncryptedCardNumber": "$.StoredCustomerInput" - }, - "TargetContact": "Current" + "Text": "\n>\" rate=\"<>\">\nThere was an error sending the receipt to your email address, $.Attributes.['Email']. Please contact customer support to receive a receipt for this transaction.\n\n" }, - "Identifier": "Store Encrypted Card Number", - "Type": "UpdateContactAttributes", + "Identifier": "Receipt Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Report Card Number Entered", + "NextAction": "Redact Sensitive Contact Attributes", "Errors": [ { - "NextAction": "Report Card Number Encryption Error", + "NextAction": "Redact Sensitive Contact Attributes", "ErrorType": "NoMatchingError" } ] @@ -2618,15 +2773,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" + "Text": "\n>\" rate=\"<>\">\nReturning you to the agent...\n\n" }, - "Identifier": "Card Number Validation Error", + "Identifier": "Returning To Agent", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "90dc6a63-2ae9-4c5f-b65f-75348779d0c6", "Errors": [ { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "90dc6a63-2ae9-4c5f-b65f-75348779d0c6", "ErrorType": "NoMatchingError" } ] @@ -2634,24 +2789,24 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "ComparisonValue": "$.Attributes.Email" }, - "Identifier": "Card Number Timeout Check", + "Identifier": "Check for Customer Email", "Type": "Compare", "Transitions": { - "NextAction": "Validate Card Number", + "NextAction": "Redact Sensitive Contact Attributes", "Conditions": [ { - "NextAction": "Card Number Timeout", + "NextAction": "Send Receipt", "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] + "Operator": "TextContains", + "Operands": ["@"] } } ], "Errors": [ { - "NextAction": "Validate Card Number", + "NextAction": "Redact Sensitive Contact Attributes", "ErrorType": "NoMatchingCondition" } ] @@ -2659,48 +2814,43 @@ }, { "Parameters": { - "ComparisonValue": "$.External.ValidationError" + "Attributes": { + "EncryptedCardNumber": "REDACTED", + "ExpirationDate": "REDACTED", + "EncryptedAccountNumber": "REDACTED" + }, + "TargetContact": "Current" }, - "Identifier": "Check for Card Number Validation Error", - "Type": "Compare", + "Identifier": "Redact Sensitive Contact Attributes", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Card Number Validation Error", - "Conditions": [ - { - "NextAction": "Store Encrypted Card Number", - "Condition": { - "Operator": "Equals", - "Operands": ["NULL"] - } - } - ], + "NextAction": "Returning To Agent", "Errors": [ { - "NextAction": "Card Number Validation Error", - "ErrorType": "NoMatchingCondition" + "NextAction": "Returning To Agent", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "LambdaFunctionARN": "<>", + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "ValidationType": "CardNumber", - "CustomerEntry": "$.StoredCustomerInput" + "EventText": "PaymentProcessed" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Validate Card Number", + "Identifier": "Report Payment Processed", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Check for Card Number Validation Error", + "NextAction": "Payment Success", "Errors": [ { - "NextAction": "Store Encrypted Card Number", + "NextAction": "Payment Success", "ErrorType": "NoMatchingError" } ] @@ -2708,18 +2858,22 @@ }, { "Parameters": { - "Attributes": { - "EncryptedAccountNumber": "$.StoredCustomerInput" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "PaymentTokenized" }, - "TargetContact": "Current" + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Store Encrypted Account Number", - "Type": "UpdateContactAttributes", + "Identifier": "Report Payment Tokenized", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Report Account Number Entered", + "NextAction": "Submit Payment", "Errors": [ { - "NextAction": "Report Account Number Encryption Error", + "NextAction": "Submit Payment", "ErrorType": "NoMatchingError" } ] @@ -2727,15 +2881,22 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "BankAccountSelected" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Account Number Validation Error", - "Type": "MessageParticipant", + "Identifier": "Report Bank Account Selected Again", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Get & Encrypt Account Number", + "NextAction": "Submit Payment", "Errors": [ { - "NextAction": "Get & Encrypt Account Number", + "NextAction": "Submit Payment", "ErrorType": "NoMatchingError" } ] @@ -2743,73 +2904,65 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "CreditCardSelected" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Account Number Timeout Check", - "Type": "Compare", + "Identifier": "Report Credit Card Selected Again", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Validate Account Number", - "Conditions": [ - { - "NextAction": "Account Number Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - } - ], + "NextAction": "Submit Payment", "Errors": [ { - "NextAction": "Validate Account Number", - "ErrorType": "NoMatchingCondition" + "NextAction": "Submit Payment", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "ComparisonValue": "$.External.ValidationError" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Check for Account Number Validation Error", - "Type": "Compare", + "Identifier": "Tokenize Transaction", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Account Number Validation Error", - "Conditions": [ - { - "NextAction": "Store Encrypted Account Number", - "Condition": { - "Operator": "Equals", - "Operands": ["NULL"] - } - } - ], + "NextAction": "Check for Tokenize Error", "Errors": [ { - "NextAction": "Account Number Validation Error", - "ErrorType": "NoMatchingCondition" + "NextAction": "Report Tokenization Error", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "LambdaFunctionARN": "<>", + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "ValidationType": "AccountNumber", - "CustomerEntry": "$.StoredCustomerInput" + "EventText": "TokenizationError" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Validate Account Number", + "Identifier": "Report Tokenization Error", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Check for Account Number Validation Error", + "NextAction": "Payment Validation Error", "Errors": [ { - "NextAction": "Store Encrypted Account Number", + "NextAction": "Payment Validation Error", "ErrorType": "NoMatchingError" } ] @@ -2817,18 +2970,15 @@ }, { "Parameters": { - "Attributes": { - "RoutingNumber": "$.StoredCustomerInput" - }, - "TargetContact": "Current" + "Text": "\n>\" rate=\"<>\">\nThere was a problem validating your $.Attributes.PaymentMethod information.\n\n" }, - "Identifier": "Store Routing Number", - "Type": "UpdateContactAttributes", + "Identifier": "Payment Validation Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Report Routing Number Entered", + "NextAction": "Remove Failed Payment Token and Method", "Errors": [ { - "NextAction": "Report Routing Number Error", + "NextAction": "Remove Failed Payment Token and Method", "ErrorType": "NoMatchingError" } ] @@ -2836,15 +2986,20 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" + "Attributes": { + "TransactionId": "$.External.TransactionId", + "PaymentMethodEndingDigits": "$.External.PaymentMethodEndingDigits", + "TransactionIds": "$.External.TransactionId" + }, + "TargetContact": "Current" }, - "Identifier": "Routing Number Validation Error", - "Type": "MessageParticipant", + "Identifier": "Record Transaction Attributes", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Get Routing Number", + "NextAction": "Report Payment Processed", "Errors": [ { - "NextAction": "Get Routing Number", + "NextAction": "Report Payment Processed", "ErrorType": "NoMatchingError" } ] @@ -2852,24 +3007,24 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "ComparisonValue": "$.External.Error" }, - "Identifier": "Routing Number Timeout Check", + "Identifier": "Check for Submit Payment Error", "Type": "Compare", "Transitions": { - "NextAction": "Validate Routing Number", + "NextAction": "Speak Payment Submission Error", "Conditions": [ { - "NextAction": "Routing Number Timeout", + "NextAction": "Record Transaction Attributes", "Condition": { "Operator": "Equals", - "Operands": ["Timeout"] + "Operands": ["NULL"] } } ], "Errors": [ { - "NextAction": "Validate Routing Number", + "NextAction": "Speak Payment Submission Error", "ErrorType": "NoMatchingCondition" } ] @@ -2877,48 +3032,38 @@ }, { "Parameters": { - "ComparisonValue": "$.External.ValidationError" + "Text": "\n>\" rate=\"<>\">\nThe payment failed to submit because of the following error:\n\n$.External.Error\n\nYou have not been charged.\n\n" }, - "Identifier": "Check for Routing Number Validation Error", - "Type": "Compare", + "Identifier": "Speak Payment Submission Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Routing Number Validation Error", - "Conditions": [ - { - "NextAction": "Store Routing Number", - "Condition": { - "Operator": "Equals", - "Operands": ["NULL"] - } - } - ], + "NextAction": "Report Payment Submission Error", "Errors": [ { - "NextAction": "Routing Number Validation Error", - "ErrorType": "NoMatchingCondition" + "NextAction": "Report Payment Submission Error", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "LambdaFunctionARN": "<>", + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "ValidationType": "RoutingNumber", - "CustomerEntry": "$.StoredCustomerInput" + "EventText": "$.External.Error" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Validate Routing Number", + "Identifier": "Report Payment Submission Error", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Check for Routing Number Validation Error", + "NextAction": "Remove Failed Payment Token and Method", "Errors": [ { - "NextAction": "Store Routing Number", + "NextAction": "Remove Failed Payment Token and Method", "ErrorType": "NoMatchingError" } ] @@ -2926,15 +3071,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" + "Text": "\n>\" rate=\"<>\">\nThe payment failed to submit because of an unknown error. You have not been charged.\n\n" }, - "Identifier": "Expiration Date Timeout", + "Identifier": "Speak Paymen Submission Unknown Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Remove Failed Payment Token and Method", "Errors": [ { - "NextAction": "Get Expiration Date", + "NextAction": "Remove Failed Payment Token and Method", "ErrorType": "NoMatchingError" } ] @@ -2942,26 +3087,19 @@ }, { "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "5", - "Text": "\n>\" rate=\"<>\">\nPlease enter your card's expiration date in the format month-month-year-year, followed by the pound key when complete.\n\n", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "4" - } + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "ResponseValidation": { + "ResponseType": "JSON" } }, - "Identifier": "Get Expiration Date", - "Type": "GetParticipantInput", + "Identifier": "Submit Payment", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Expiration Date Timeout Check", + "NextAction": "Check for Submit Payment Error", "Errors": [ { - "NextAction": "Try Expiration Date Again", + "NextAction": "Report Payment Submission Unknown Error", "ErrorType": "NoMatchingError" } ] @@ -2969,18 +3107,22 @@ }, { "Parameters": { - "Attributes": { - "ExpirationDate": "$.StoredCustomerInput" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "PaymentSubmissionError" }, - "TargetContact": "Current" + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Store Expiration Date", - "Type": "UpdateContactAttributes", + "Identifier": "Report Payment Submission Unknown Error", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Report Expiration Entered", + "NextAction": "Speak Paymen Submission Unknown Error", "Errors": [ { - "NextAction": "Report Expiration Date Error", + "NextAction": "Speak Paymen Submission Unknown Error", "ErrorType": "NoMatchingError" } ] @@ -2988,15 +3130,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" + "Text": "\n>\" rate=\"<>\">\nThe payment failed because of the following error:\n\n$.External.Error\n\n" }, - "Identifier": "Expiration Date Validation Error", + "Identifier": "Speak Validation Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Report Validation Error", "Errors": [ { - "NextAction": "Get Expiration Date", + "NextAction": "Report Validation Error", "ErrorType": "NoMatchingError" } ] @@ -3004,73 +3146,42 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" - }, - "Identifier": "Expiration Date Timeout Check", - "Type": "Compare", - "Transitions": { - "NextAction": "Validate Expiration Date", - "Conditions": [ - { - "NextAction": "Expiration Date Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - } - ], - "Errors": [ - { - "NextAction": "Validate Expiration Date", - "ErrorType": "NoMatchingCondition" - } - ] - } - }, - { - "Parameters": { - "ComparisonValue": "$.External.ValidationError" + "Attributes": { + "PaymentToken": "NULL", + "PaymentMethod": "NULL" + }, + "TargetContact": "Current" }, - "Identifier": "Check for Expiration Date Validation Error", - "Type": "Compare", + "Identifier": "Remove Failed Payment Token and Method", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Expiration Date Validation Error", - "Conditions": [ - { - "NextAction": "Store Expiration Date", - "Condition": { - "Operator": "Equals", - "Operands": ["NULL"] - } - } - ], + "NextAction": "Redact Sensitive Contact Attributes", "Errors": [ { - "NextAction": "Expiration Date Validation Error", - "ErrorType": "NoMatchingCondition" + "NextAction": "Redact Sensitive Contact Attributes", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "LambdaFunctionARN": "<>", + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "ValidationType": "ExpirationDate", - "CustomerEntry": "$.StoredCustomerInput" + "EventText": "$.External.Error" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Validate Expiration Date", + "Identifier": "Report Validation Error", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Check for Expiration Date Validation Error", + "NextAction": "Remove Failed Payment Token and Method", "Errors": [ { - "NextAction": "Store Expiration Date", + "NextAction": "Remove Failed Payment Token and Method", "ErrorType": "NoMatchingError" } ] diff --git a/lib/connect/flows/modules/c3-payment-ivr-flow-module.json b/lib/connect/flows/modules/c3-payment-ivr-flow-module.json index 5e6eff5..3d81df8 100644 --- a/lib/connect/flows/modules/c3-payment-ivr-flow-module.json +++ b/lib/connect/flows/modules/c3-payment-ivr-flow-module.json @@ -7,14 +7,6 @@ "y": 231.2 }, "ActionMetadata": { - "Record Token": { - "position": { - "x": 5877.6, - "y": -299.2 - }, - "isFriendlyName": true, - "dynamicParams": [] - }, "b2786200-e897-45bd-b888-0f53246f72ed": { "position": { "x": -748.8, @@ -87,7 +79,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "fbb7b741-79e8-4bbf-80c6-f637db1187eb", + "id": "b3c87725-e30d-4f80-b5c5-b7787691a94b", "operator": { "name": "Equals", "value": "Equals", @@ -96,7 +88,7 @@ "value": "Timeout" }, { - "id": "e800a29f-47a5-439c-a1ba-3518abca5dd6", + "id": "0fb4b498-807b-4071-ab9f-21c90348b3a7", "operator": { "name": "Is greater than", "value": "GreaterThan", @@ -105,7 +97,7 @@ "value": "$.Attributes.PaymentAmountDue" }, { - "id": "d5ba66bb-6326-4524-b61d-f6166be11a6c", + "id": "0832b707-bc38-4d83-bf93-f81c3a5ac86b", "operator": { "name": "Is less than", "value": "LessThan", @@ -115,47 +107,6 @@ } ] }, - "Get Payment Amount": { - "position": { - "x": 60.8, - "y": -46.4 - }, - "isFriendlyName": true, - "conditionMetadata": [], - "countryCodePrefix": "+1" - }, - "Use Card Again?": { - "position": { - "x": 1289.6, - "y": -720 - }, - "isFriendlyName": true, - "conditionMetadata": [ - { - "id": "2672653b-67d6-4be2-8417-3ca598c7b68d", - "value": "1" - }, - { - "id": "e3075be3-bafa-4dd7-8015-61175164dde0", - "value": "2" - } - ] - }, - "Set Payment Amount to Entered Amount": { - "position": { - "x": 452, - "y": -34.4 - }, - "isFriendlyName": true, - "parameters": { - "Attributes": { - "PaymentAmount": { - "useDynamic": true - } - } - }, - "dynamicParams": ["PaymentAmount"] - }, "Use Payment Method Again Timeout": { "position": { "x": 1083.2, @@ -171,28 +122,11 @@ "isFriendlyName": true, "conditionMetadata": [ { - "id": "fc508a3c-975c-45dd-921f-ec913ac5559b", - "value": "1" - }, - { - "id": "a5c6ac9f-eaac-426e-bc19-c3603d63cc0c", - "value": "2" - } - ] - }, - "Use Bank Account Again?": { - "position": { - "x": 1410.4, - "y": -397.6 - }, - "isFriendlyName": true, - "conditionMetadata": [ - { - "id": "19f7fe11-d51f-4898-a7bd-7840fc909cdf", + "id": "ad270a42-6cd6-45d8-b2c8-fc8025488f8d", "value": "1" }, { - "id": "12db631d-2765-4086-a1c8-f64e27bac035", + "id": "113d4f98-c51b-45a5-9d10-b856d88c64da", "value": "2" } ] @@ -206,7 +140,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "91f6a266-31b3-4053-a7b5-7e89b96ae6a0", + "id": "c43f713d-ec23-4ea5-b604-141384782cb6", "operator": { "name": "Equals", "value": "Equals", @@ -215,7 +149,7 @@ "value": "Card" }, { - "id": "7335bbf0-7873-4eb6-bf30-d6d2b502133a", + "id": "35e1e947-808f-42a0-9972-900aad9c0608", "operator": { "name": "Equals", "value": "Equals", @@ -248,7 +182,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "838f3cf4-de91-4a72-ae32-ce0062f6ca38", + "id": "ce83234a-df4c-4018-b71d-3d0cdc4589eb", "operator": { "name": "Equals", "value": "Equals", @@ -257,7 +191,7 @@ "value": "PaymentAmountDue" }, { - "id": "68ff0418-d7a7-4462-a6ca-57070b7b0f4f", + "id": "89538b6b-474a-4194-bbaa-70a37deeb71e", "operator": { "name": "Is greater than", "value": "GreaterThan", @@ -274,21 +208,6 @@ }, "isFriendlyName": true }, - "Set Payment Amount to Full Amount": { - "position": { - "x": 468, - "y": 447.2 - }, - "isFriendlyName": true, - "parameters": { - "Attributes": { - "PaymentAmount": { - "useDynamic": true - } - } - }, - "dynamicParams": ["PaymentAmount"] - }, "Prompt for Payment Amount Choice": { "position": { "x": -479.2, @@ -297,11 +216,11 @@ "isFriendlyName": true, "conditionMetadata": [ { - "id": "d310b2e2-b48f-45eb-8d91-f60e260cbe07", + "id": "f30e307e-1d61-4425-b90b-886c1074c059", "value": "1" }, { - "id": "4ce16c76-b545-43f7-9011-4e3c8427f18f", + "id": "378c3ae5-b61a-4d75-81bb-9e976bbf307d", "value": "2" } ] @@ -321,15 +240,6 @@ }, "isFriendlyName": true }, - "Get & Encrypt Account Number": { - "position": { - "x": 2915.2, - "y": 106.4 - }, - "isFriendlyName": true, - "conditionMetadata": [], - "countryCodePrefix": "+1" - }, "Set Payment Method to Card": { "position": { "x": 2685.6, @@ -345,15 +255,6 @@ }, "isFriendlyName": true }, - "Get & Encrypt Card Number": { - "position": { - "x": 2907.2, - "y": -807.2 - }, - "isFriendlyName": true, - "conditionMetadata": [], - "countryCodePrefix": "+1" - }, "Routing Number Timeout": { "position": { "x": 4033.6, @@ -391,88 +292,6 @@ "conditionMetadata": [], "countryCodePrefix": "+1" }, - "Check for Tokenize Error": { - "position": { - "x": 5646.4, - "y": -300 - }, - "isFriendlyName": true, - "conditions": [], - "conditionMetadata": [ - { - "id": "3549ffbd-5bb2-4c96-8538-133bb1f04a02", - "operator": { - "name": "Equals", - "value": "Equals", - "shortDisplay": "=" - }, - "value": "NULL" - } - ] - }, - "Speak Validation Error": { - "position": { - "x": 5847.2, - "y": 235.2 - }, - "isFriendlyName": true - }, - "Tokenize Transaction": { - "position": { - "x": 5397.6, - "y": -304.8 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": {} - }, - "Payment Validation Error": { - "position": { - "x": 6692.8, - "y": 472 - }, - "isFriendlyName": true - }, - "Submit Payment": { - "position": { - "x": 6360.8, - "y": -295.2 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": {} - }, - "Remove Failed Payment Token and Method": { - "position": { - "x": 6968.8, - "y": 382.4 - }, - "isFriendlyName": true, - "dynamicParams": [] - }, - "Payment Submission Error": { - "position": { - "x": 6683.2, - "y": 229.6 - }, - "isFriendlyName": true - }, - "Record Transaction Attributes": { - "position": { - "x": 6600.8, - "y": -296.8 - }, - "isFriendlyName": true, - "dynamicParams": [] - }, "Check for Customer Email": { "position": { "x": 7265.6, @@ -482,7 +301,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "ee2d8bda-581a-4f47-9f97-891b4c74f2b3", + "id": "8fe0b2de-1f8a-4b03-9ca5-144b94f7360a", "operator": { "name": "Contains", "value": "Contains", @@ -492,13 +311,6 @@ } ] }, - "Payment Success": { - "position": { - "x": 7044, - "y": -211.2 - }, - "isFriendlyName": true - }, "Redact Sensitive Contact Attributes Copy": { "position": { "x": 8241.6, @@ -516,7 +328,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "32d9fe15-7110-4fcb-864c-61cdddd67f7d", + "id": "9d9bdb40-a7e8-4266-92c7-612e75cf47c4", "operator": { "name": "Equals", "value": "Equals", @@ -548,11 +360,11 @@ "isFriendlyName": true, "conditionMetadata": [ { - "id": "9fb530c0-45f4-4b9c-8e4e-6a3ab0e7b3e3", + "id": "879c99ba-1774-4fef-b530-d0c81c7b4ba9", "value": "1" }, { - "id": "b388dbec-8ef6-4090-a10f-9fec43d97016", + "id": "d1b69330-c104-4fed-85d9-324d9559e1a4", "value": "2" } ] @@ -577,14 +389,6 @@ }, "dynamicMetadata": {} }, - "Redact Sensitive Contact Attributes": { - "position": { - "x": 8200, - "y": 86.4 - }, - "isFriendlyName": true, - "dynamicParams": [] - }, "Receipt Error": { "position": { "x": 7777.6, @@ -660,7 +464,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "096a7918-993a-48ec-a206-95f2e325f217", + "id": "3240b95a-17f3-4030-a58d-75701333329b", "operator": { "name": "Equals", "value": "Equals", @@ -677,21 +481,6 @@ }, "isFriendlyName": true }, - "Store Encrypted Card Number": { - "position": { - "x": 3570.4, - "y": -817.6 - }, - "isFriendlyName": true, - "parameters": { - "Attributes": { - "EncryptedCardNumber": { - "useDynamic": true - } - } - }, - "dynamicParams": ["EncryptedCardNumber"] - }, "Validate Card Number": { "position": { "x": 3139.2, @@ -722,7 +511,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "4079afa6-5af7-451c-b7de-21a6dcfec9cc", + "id": "388108e8-644a-4969-9ebc-37ddeb457bbc", "operator": { "name": "Equals", "value": "Equals", @@ -741,7 +530,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "835afd0a-3a9b-42f7-8da1-5c7b0217983b", + "id": "dddf5257-9e8f-4019-9b75-50ded0538188", "operator": { "name": "Equals", "value": "Equals", @@ -758,13 +547,6 @@ }, "isFriendlyName": true }, - "Internal Error": { - "position": { - "x": 2711.2, - "y": 773.6 - }, - "isFriendlyName": true - }, "Get Routing Number": { "position": { "x": 4123.2, @@ -804,7 +586,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "caff22e3-dc17-46d8-8c9c-4fbc87bbf60f", + "id": "a5d93225-0213-41a9-b347-80f11dd4b5d3", "operator": { "name": "Equals", "value": "Equals", @@ -814,36 +596,6 @@ } ] }, - "Store Encrypted Account Number": { - "position": { - "x": 3565.6, - "y": 100.8 - }, - "isFriendlyName": true, - "parameters": { - "Attributes": { - "EncryptedAccountNumber": { - "useDynamic": true - } - } - }, - "dynamicParams": ["EncryptedAccountNumber"] - }, - "Store Routing Number": { - "position": { - "x": 4786.4, - "y": 88 - }, - "isFriendlyName": true, - "parameters": { - "Attributes": { - "RoutingNumber": { - "useDynamic": true - } - } - }, - "dynamicParams": ["RoutingNumber"] - }, "Routing Number Validation Error": { "position": { "x": 4427.2, @@ -860,7 +612,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "63497af9-b1d6-4e68-8fdc-f52f1bbd423d", + "id": "6eeffb2a-60a1-430a-8de7-ced59432d3ac", "operator": { "name": "Equals", "value": "Equals", @@ -879,7 +631,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "dcea6e50-4c52-4a27-b07b-d8e05a25d9c1", + "id": "d1e1810c-e9aa-45cd-a4e9-03c007955350", "operator": { "name": "Equals", "value": "Equals", @@ -910,21 +662,6 @@ "CustomerEntry": true } }, - "Store Expiration Date": { - "position": { - "x": 4842.4, - "y": -732.8 - }, - "isFriendlyName": true, - "parameters": { - "Attributes": { - "ExpirationDate": { - "useDynamic": true - } - } - }, - "dynamicParams": ["ExpirationDate"] - }, "Expiration Date Validation Error": { "position": { "x": 4470.4, @@ -941,7 +678,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "2f922546-5cd7-405c-9a55-af3ed8b5957a", + "id": "db6441c0-f2b2-4cde-b0f8-27559c14b33a", "operator": { "name": "Equals", "value": "Equals", @@ -960,7 +697,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "1c91b217-46a0-4ee6-be8e-f0418c4b9c6c", + "id": "9016c485-d4d3-47a2-8d36-88fd710631fa", "operator": { "name": "Equals", "value": "Equals", @@ -990,13 +727,301 @@ "ValidationType": false, "CustomerEntry": true } - } - }, - "Annotations": [ - { - "type": "default", - "id": "3488450f-b48c-41aa-a37e-e3b430d5f199", - "content": "This needs to be done because a user-defined value for the Set Working Queue block type doesn't seem to work?", + }, + "Get Payment Amount": { + "position": { + "x": 60.8, + "y": -46.4 + }, + "isFriendlyName": true, + "conditionMetadata": [], + "countryCodePrefix": "+1" + }, + "Set Payment Amount to Entered Amount": { + "position": { + "x": 452, + "y": -34.4 + }, + "isFriendlyName": true, + "parameters": { + "Attributes": { + "PaymentAmount": { + "useDynamic": true + } + } + }, + "dynamicParams": ["PaymentAmount"] + }, + "Set Payment Amount to Full Amount": { + "position": { + "x": 468, + "y": 447.2 + }, + "isFriendlyName": true, + "parameters": { + "Attributes": { + "PaymentAmount": { + "useDynamic": true + } + } + }, + "dynamicParams": ["PaymentAmount"] + }, + "Get & Encrypt Account Number": { + "position": { + "x": 2915.2, + "y": 106.4 + }, + "isFriendlyName": true, + "conditionMetadata": [], + "countryCodePrefix": "+1" + }, + "Get & Encrypt Card Number": { + "position": { + "x": 2907.2, + "y": -807.2 + }, + "isFriendlyName": true, + "conditionMetadata": [], + "countryCodePrefix": "+1" + }, + "Redact Sensitive Contact Attributes": { + "position": { + "x": 8200, + "y": 86.4 + }, + "isFriendlyName": true, + "dynamicParams": [] + }, + "Store Encrypted Card Number": { + "position": { + "x": 3570.4, + "y": -817.6 + }, + "isFriendlyName": true, + "parameters": { + "Attributes": { + "EncryptedCardNumber": { + "useDynamic": true + } + } + }, + "dynamicParams": ["EncryptedCardNumber"] + }, + "Store Encrypted Account Number": { + "position": { + "x": 3565.6, + "y": 100.8 + }, + "isFriendlyName": true, + "parameters": { + "Attributes": { + "EncryptedAccountNumber": { + "useDynamic": true + } + } + }, + "dynamicParams": ["EncryptedAccountNumber"] + }, + "Store Routing Number": { + "position": { + "x": 4786.4, + "y": 88 + }, + "isFriendlyName": true, + "parameters": { + "Attributes": { + "RoutingNumber": { + "useDynamic": true + } + } + }, + "dynamicParams": ["RoutingNumber"] + }, + "Store Expiration Date": { + "position": { + "x": 4842.4, + "y": -732.8 + }, + "isFriendlyName": true, + "parameters": { + "Attributes": { + "ExpirationDate": { + "useDynamic": true + } + } + }, + "dynamicParams": ["ExpirationDate"] + }, + "Internal Error": { + "position": { + "x": 2711.2, + "y": 773.6 + }, + "isFriendlyName": true + }, + "Speak Validation Error": { + "position": { + "x": 5846.4, + "y": 234.4 + }, + "isFriendlyName": true + }, + "Check for Tokenize Error": { + "position": { + "x": 5646.4, + "y": -300 + }, + "isFriendlyName": true, + "conditions": [], + "conditionMetadata": [ + { + "id": "cf1b4038-9fdf-4271-8bb4-8b086887722d", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "NULL" + } + ] + }, + "Payment Success": { + "position": { + "x": 7044, + "y": -211.2 + }, + "isFriendlyName": true + }, + "Tokenize Transaction": { + "position": { + "x": 5397.6, + "y": -304.8 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": {} + }, + "Payment Validation Error": { + "position": { + "x": 6692.8, + "y": 472 + }, + "isFriendlyName": true + }, + "Use Card Again?": { + "position": { + "x": 1289.6, + "y": -720 + }, + "isFriendlyName": true, + "conditionMetadata": [ + { + "id": "d3dc0c90-0eff-4056-95c9-0b1825d94e2f", + "value": "1" + }, + { + "id": "ab6bf500-8ca4-4a98-b8dc-3ac9801e4cdf", + "value": "2" + } + ] + }, + "Use Bank Account Again?": { + "position": { + "x": 1410.4, + "y": -397.6 + }, + "isFriendlyName": true, + "conditionMetadata": [ + { + "id": "f7d270e1-4380-42e4-8790-4b9ed943c0f5", + "value": "1" + }, + { + "id": "8d691fe2-8388-49f0-8262-df69cca9a5d4", + "value": "2" + } + ] + }, + "Record Token": { + "position": { + "x": 5877.6, + "y": -299.2 + }, + "isFriendlyName": true, + "dynamicParams": [] + }, + "Record Transaction Attributes": { + "position": { + "x": 6752, + "y": -297.6 + }, + "isFriendlyName": true, + "dynamicParams": [] + }, + "Submit Payment": { + "position": { + "x": 6295.2, + "y": -303.2 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": {} + }, + "Speak Payment Submission Unknown Error": { + "position": { + "x": 6431.2, + "y": 13.6 + }, + "isFriendlyName": true + }, + "Check for Submit Payment Error": { + "position": { + "x": 6531.2, + "y": -299.2 + }, + "isFriendlyName": true, + "conditionMetadata": [ + { + "id": "c958368f-9f65-4dcc-9415-c4ddb97042ce", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "NULL" + } + ] + }, + "Remove Failed Payment Token and Method": { + "position": { + "x": 6968.8, + "y": 382.4 + }, + "isFriendlyName": true, + "dynamicParams": [] + }, + "Speak Payment Submission Error": { + "position": { + "x": 6681.6, + "y": 228 + }, + "isFriendlyName": true + } + }, + "Annotations": [ + { + "type": "default", + "id": "3488450f-b48c-41aa-a37e-e3b430d5f199", + "content": "This needs to be done because a user-defined value for the Set Working Queue block type doesn't seem to work?", "actionId": "Set Receipt Queue ID", "isFolded": true, "position": { @@ -1075,25 +1100,6 @@ "hash": {} }, "Actions": [ - { - "Parameters": { - "Attributes": { - "PaymentToken": "$.External.PaymentToken" - }, - "TargetContact": "Current" - }, - "Identifier": "Record Token", - "Type": "UpdateContactAttributes", - "Transitions": { - "NextAction": "Submit Payment", - "Errors": [ - { - "NextAction": "Submit Payment", - "ErrorType": "NoMatchingError" - } - ] - } - }, { "Parameters": {}, "Identifier": "b2786200-e897-45bd-b888-0f53246f72ed", @@ -1201,158 +1207,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" - }, - "Identifier": "Payment Method Timeout", - "Type": "MessageParticipant", - "Transitions": { - "NextAction": "Ask for Payment Method", - "Errors": [ - { - "NextAction": "Ask for Payment Method", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "Text": "\n>\" rate=\"<>\">\nYour entry was not recognized. Please try again.\n\n" - }, - "Identifier": "Method Input Not Recognized", - "Type": "MessageParticipant", - "Transitions": { - "NextAction": "Ask for Payment Method", - "Errors": [ - { - "NextAction": "Ask for Payment Method", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" - }, - "Identifier": "Check Payment Amount", - "Type": "Compare", - "Transitions": { - "NextAction": "Set Payment Amount to Entered Amount", - "Conditions": [ - { - "NextAction": "Payment Amount Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - }, - { - "NextAction": "Payment Too Large", - "Condition": { - "Operator": "NumberGreaterThan", - "Operands": ["$.Attributes.PaymentAmountDue"] - } - }, - { - "NextAction": "Payment Too Small", - "Condition": { - "Operator": "NumberLessThan", - "Operands": ["$.Attributes.PaymentMinimumPayment"] - } - } - ], - "Errors": [ - { - "NextAction": "Set Payment Amount to Entered Amount", - "ErrorType": "NoMatchingCondition" - } - ] - } - }, - { - "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "5", - "Text": "\n>\" rate=\"<>\">\nPlease enter the amount you would like to pay in whole dollars, followed by the pound key.\n\n", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "20" - } - } - }, - "Identifier": "Get Payment Amount", - "Type": "GetParticipantInput", - "Transitions": { - "NextAction": "Check Payment Amount", - "Errors": [ - { - "NextAction": "Internal Error", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "StoreInput": "False", - "InputTimeLimitSeconds": "5", - "Text": "\n>\" rate=\"<>\">\nYou previously paid with a credit or debit card ending in $.Attributes.PaymentMethodEndingDigits.\n\nIf you would like to use this card again for this payment, press 1.\nTo use a different payment method, press 2.\n\n" - }, - "Identifier": "Use Card Again?", - "Type": "GetParticipantInput", - "Transitions": { - "NextAction": "Ask for Payment Method", - "Conditions": [ - { - "NextAction": "Submit Payment", - "Condition": { - "Operator": "Equals", - "Operands": ["1"] - } - }, - { - "NextAction": "Ask for Payment Method", - "Condition": { - "Operator": "Equals", - "Operands": ["2"] - } - } - ], - "Errors": [ - { - "NextAction": "Use Payment Method Again Timeout", - "ErrorType": "InputTimeLimitExceeded" - }, - { - "NextAction": "Ask for Payment Method", - "ErrorType": "NoMatchingCondition" - }, - { - "NextAction": "Ask for Payment Method", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "Attributes": { - "PaymentAmount": "$.StoredCustomerInput" - }, - "TargetContact": "Current" + "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" }, - "Identifier": "Set Payment Amount to Entered Amount", - "Type": "UpdateContactAttributes", + "Identifier": "Payment Method Timeout", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Check Last Payment Method", + "NextAction": "Ask for Payment Method", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingError" } ] @@ -1360,15 +1223,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" + "Text": "\n>\" rate=\"<>\">\nYour entry was not recognized. Please try again.\n\n" }, - "Identifier": "Use Payment Method Again Timeout", + "Identifier": "Method Input Not Recognized", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Check Last Payment Method", + "NextAction": "Ask for Payment Method", "Errors": [ { - "NextAction": "Check Last Payment Method", + "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingError" } ] @@ -1376,41 +1239,54 @@ }, { "Parameters": { - "StoreInput": "False", - "InputTimeLimitSeconds": "5", - "Text": "\n>\" rate=\"<>\">\nTo pay with a credit or debit card, press 1.\nTo pay directly with your bank account, press 2.\n\n" + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Ask for Payment Method", - "Type": "GetParticipantInput", + "Identifier": "Check Payment Amount", + "Type": "Compare", "Transitions": { - "NextAction": "Method Input Not Recognized", + "NextAction": "Set Payment Amount to Entered Amount", "Conditions": [ { - "NextAction": "Set Payment Method to Card", + "NextAction": "Payment Amount Timeout", "Condition": { "Operator": "Equals", - "Operands": ["1"] + "Operands": ["Timeout"] } }, { - "NextAction": "Set Payment Method to Bank", + "NextAction": "Payment Too Large", "Condition": { - "Operator": "Equals", - "Operands": ["2"] + "Operator": "NumberGreaterThan", + "Operands": ["$.Attributes.PaymentAmountDue"] + } + }, + { + "NextAction": "Payment Too Small", + "Condition": { + "Operator": "NumberLessThan", + "Operands": ["$.Attributes.PaymentMinimumPayment"] } } ], "Errors": [ { - "NextAction": "Payment Method Timeout", - "ErrorType": "InputTimeLimitExceeded" - }, - { - "NextAction": "Method Input Not Recognized", + "NextAction": "Set Payment Amount to Entered Amount", "ErrorType": "NoMatchingCondition" - }, + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" + }, + "Identifier": "Use Payment Method Again Timeout", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Check Last Payment Method", + "Errors": [ { - "NextAction": "Method Input Not Recognized", + "NextAction": "Check Last Payment Method", "ErrorType": "NoMatchingError" } ] @@ -1420,22 +1296,22 @@ "Parameters": { "StoreInput": "False", "InputTimeLimitSeconds": "5", - "Text": "\n>\" rate=\"<>\">\nYou previously paid with a bank account ending in $.Attributes.PaymentMethodEndingDigits.\n\nIf you would like to use this account again for this payment, press 1.\nTo use a different payment method, press 2.\n\n" + "Text": "\n>\" rate=\"<>\">\nTo pay with a credit or debit card, press 1.\nTo pay directly with your bank account, press 2.\n\n" }, - "Identifier": "Use Bank Account Again?", + "Identifier": "Ask for Payment Method", "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Ask for Payment Method", + "NextAction": "Method Input Not Recognized", "Conditions": [ { - "NextAction": "Submit Payment", + "NextAction": "Set Payment Method to Card", "Condition": { "Operator": "Equals", "Operands": ["1"] } }, { - "NextAction": "Ask for Payment Method", + "NextAction": "Set Payment Method to Bank", "Condition": { "Operator": "Equals", "Operands": ["2"] @@ -1444,15 +1320,15 @@ ], "Errors": [ { - "NextAction": "Use Payment Method Again Timeout", + "NextAction": "Payment Method Timeout", "ErrorType": "InputTimeLimitExceeded" }, { - "NextAction": "Ask for Payment Method", + "NextAction": "Method Input Not Recognized", "ErrorType": "NoMatchingCondition" }, { - "NextAction": "Ask for Payment Method", + "NextAction": "Method Input Not Recognized", "ErrorType": "NoMatchingError" } ] @@ -1570,25 +1446,6 @@ ] } }, - { - "Parameters": { - "Attributes": { - "PaymentAmount": "$.Customer.Attributes.PaymentAmountDue" - }, - "TargetContact": "Current" - }, - "Identifier": "Set Payment Amount to Full Amount", - "Type": "UpdateContactAttributes", - "Transitions": { - "NextAction": "Check Last Payment Method", - "Errors": [ - { - "NextAction": "Internal Error", - "ErrorType": "NoMatchingError" - } - ] - } - }, { "Parameters": { "StoreInput": "False", @@ -1666,11 +1523,110 @@ ] } }, + { + "Parameters": { + "Attributes": { + "PaymentMethod": "Card" + }, + "TargetContact": "Current" + }, + "Identifier": "Set Payment Method to Card", + "Type": "UpdateContactAttributes", + "Transitions": { + "NextAction": "Get & Encrypt Card Number", + "Errors": [ + { + "NextAction": "Get & Encrypt Card Number", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" + }, + "Identifier": "Card Number Timeout", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Get & Encrypt Card Number", + "Errors": [ + { + "NextAction": "Get & Encrypt Card Number", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" + }, + "Identifier": "Routing Number Timeout", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Get Routing Number", + "Errors": [ + { + "NextAction": "Get Routing Number", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\nThere was a problem with your bank routing number. Please check your entry and try again.\n\n" + }, + "Identifier": "Try Routing Number Again", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Get Routing Number", + "Errors": [ + { + "NextAction": "Get Routing Number", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" + }, + "Identifier": "Expiration Date Timeout", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Get Expiration Date", + "Errors": [ + { + "NextAction": "Get Expiration Date", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\nThere was a problem with your expiration date. Please check your entry and try again.\n\n" + }, + "Identifier": "Try Expiration Date Again", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Get Expiration Date", + "Errors": [ + { + "NextAction": "Get Expiration Date", + "ErrorType": "NoMatchingError" + } + ] + } + }, { "Parameters": { "StoreInput": "True", - "InputTimeLimitSeconds": "10", - "Text": "\n>\" rate=\"<>\">\nPlease enter your bank account number followed by the pound key when complete.\n\n", + "InputTimeLimitSeconds": "5", + "Text": "\n>\" rate=\"<>\">\nPlease enter your card's expiration date in the format month-month-year-year, followed by the pound key when complete.\n\n", "DTMFConfiguration": { "DisableCancelKey": "False", "InputTerminationSequence": "#" @@ -1679,19 +1635,61 @@ "CustomValidation": { "MaximumLength": "25" } - }, - "InputEncryption": { - "EncryptionKeyId": "<>", - "Key": "<>" } }, - "Identifier": "Get & Encrypt Account Number", + "Identifier": "Get Expiration Date", "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Account Number Timeout Check", + "NextAction": "Expiration Date Timeout Check", + "Errors": [ + { + "NextAction": "Try Expiration Date Again", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "ComparisonValue": "$.Attributes.Email" + }, + "Identifier": "Check for Customer Email", + "Type": "Compare", + "Transitions": { + "NextAction": "Has Specified Receipt Queue", + "Conditions": [ + { + "NextAction": "Send Receipt", + "Condition": { + "Operator": "TextContains", + "Operands": ["@"] + } + } + ], + "Errors": [ + { + "NextAction": "Has Specified Receipt Queue", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "Attributes": { + "EncryptedCardNumber": "REDACTED", + "EncryptedAccountNumber": "REDACTED", + "ExpirationDate": "REDACTED" + }, + "TargetContact": "Current" + }, + "Identifier": "Redact Sensitive Contact Attributes Copy", + "Type": "UpdateContactAttributes", + "Transitions": { + "NextAction": "Set Queue", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "Set Queue", "ErrorType": "NoMatchingError" } ] @@ -1699,19 +1697,25 @@ }, { "Parameters": { - "Attributes": { - "PaymentMethod": "Card" - }, - "TargetContact": "Current" + "ComparisonValue": "$.FlowAttributes.ReceiptQueueId" }, - "Identifier": "Set Payment Method to Card", - "Type": "UpdateContactAttributes", + "Identifier": "Has Specified Receipt Queue", + "Type": "Compare", "Transitions": { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Ask to Transfer for Receipt", + "Conditions": [ + { + "NextAction": "Redact Sensitive Contact Attributes", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], "Errors": [ { - "NextAction": "Get & Encrypt Card Number", - "ErrorType": "NoMatchingError" + "NextAction": "Ask to Transfer for Receipt", + "ErrorType": "NoMatchingCondition" } ] } @@ -1720,13 +1724,13 @@ "Parameters": { "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" }, - "Identifier": "Card Number Timeout", + "Identifier": "Receipt Timeout", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Ask to Transfer for Receipt", "Errors": [ { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Ask to Transfer for Receipt", "ErrorType": "NoMatchingError" } ] @@ -1734,30 +1738,15 @@ }, { "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "10", - "Text": "\n>\" rate=\"<>\">\nPlease enter your card number followed by the pound key when complete.\n\n", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "25" - } - }, - "InputEncryption": { - "EncryptionKeyId": "<>", - "Key": "<>" - } + "Text": "\n>\" rate=\"<>\">\nYour entry was not recognized. Please try again.\n\n" }, - "Identifier": "Get & Encrypt Card Number", - "Type": "GetParticipantInput", + "Identifier": "Receipt Entry Not Recognized", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Card Number Timeout Check", + "NextAction": "Ask to Transfer for Receipt", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "Ask to Transfer for Receipt", "ErrorType": "NoMatchingError" } ] @@ -1765,15 +1754,41 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" + "StoreInput": "False", + "InputTimeLimitSeconds": "5", + "Text": "\n>\" rate=\"<>\">\nTo transfer to a representative and receive a receipt for your payment, press 1.\nTo continue without a receipt, press 2.\n\n" }, - "Identifier": "Routing Number Timeout", - "Type": "MessageParticipant", + "Identifier": "Ask to Transfer for Receipt", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Get Routing Number", + "NextAction": "Receipt Entry Not Recognized", + "Conditions": [ + { + "NextAction": "Redact Sensitive Contact Attributes Copy", + "Condition": { + "Operator": "Equals", + "Operands": ["1"] + } + }, + { + "NextAction": "Redact Sensitive Contact Attributes", + "Condition": { + "Operator": "Equals", + "Operands": ["2"] + } + } + ], "Errors": [ { - "NextAction": "Get Routing Number", + "NextAction": "Receipt Timeout", + "ErrorType": "InputTimeLimitExceeded" + }, + { + "NextAction": "Receipt Entry Not Recognized", + "ErrorType": "NoMatchingCondition" + }, + { + "NextAction": "Receipt Entry Not Recognized", "ErrorType": "NoMatchingError" } ] @@ -1781,15 +1796,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nThere was a problem with your bank routing number. Please check your entry and try again.\n\n" + "Text": "\n>\" rate=\"<>\">\nA receipt has been sent to your email address, $.Attributes.['Email'].\n\n" }, - "Identifier": "Try Routing Number Again", + "Identifier": "Receipt Success", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Routing Number", + "NextAction": "Redact Sensitive Contact Attributes", "Errors": [ { - "NextAction": "Get Routing Number", + "NextAction": "Redact Sensitive Contact Attributes", "ErrorType": "NoMatchingError" } ] @@ -1797,15 +1812,19 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Expiration Date Timeout", - "Type": "MessageParticipant", + "Identifier": "Send Receipt", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Receipt Success", "Errors": [ { - "NextAction": "Get Expiration Date", + "NextAction": "Receipt Error", "ErrorType": "NoMatchingError" } ] @@ -1813,42 +1832,39 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nThere was a problem with your expiration date. Please check your entry and try again.\n\n" + "Text": "\n>\" rate=\"<>\">\nThere was an error sending the receipt to your email address, $.Attributes.['Email']. Please contact customer support to receive a receipt for this transaction.\n\n" }, - "Identifier": "Try Expiration Date Again", + "Identifier": "Receipt Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Redact Sensitive Contact Attributes", "Errors": [ { - "NextAction": "Get Expiration Date", + "NextAction": "Redact Sensitive Contact Attributes", "ErrorType": "NoMatchingError" } ] } }, { - "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "5", - "Text": "\n>\" rate=\"<>\">\nPlease enter your card's expiration date in the format month-month-year-year, followed by the pound key when complete.\n\n", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "25" - } - } - }, - "Identifier": "Get Expiration Date", - "Type": "GetParticipantInput", + "Parameters": {}, + "Identifier": "a3ea896e-4f43-4677-8edd-159f677dc41e", + "Type": "EndFlowModuleExecution", + "Transitions": {} + }, + { + "Parameters": {}, + "Identifier": "Transfer to Representative", + "Type": "TransferContactToQueue", "Transitions": { - "NextAction": "Expiration Date Timeout Check", + "NextAction": "Transfer Error", "Errors": [ { - "NextAction": "Try Expiration Date Again", + "NextAction": "Transfer Error", + "ErrorType": "QueueAtCapacity" + }, + { + "NextAction": "Transfer Error", "ErrorType": "NoMatchingError" } ] @@ -1856,40 +1872,31 @@ }, { "Parameters": { - "ComparisonValue": "$.External.Error" + "QueueId": "$.FlowAttributes.ReceiptQueueId" }, - "Identifier": "Check for Tokenize Error", - "Type": "Compare", + "Identifier": "Set Queue", + "Type": "UpdateContactTargetQueue", "Transitions": { - "NextAction": "Speak Validation Error", - "Conditions": [ - { - "NextAction": "Record Token", - "Condition": { - "Operator": "Equals", - "Operands": ["NULL"] - } - } - ], + "NextAction": "Transfer to Representative", "Errors": [ { - "NextAction": "Speak Validation Error", - "ErrorType": "NoMatchingCondition" + "NextAction": "Transfer Error", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nThe payment failed because of the following error:\n\n$.External.Error\n\n" + "Text": "\n>\" rate=\"<>\">\nAn error prevented us from connecting you to a representative. Please try calling the customer service number directly in order to receive a receipt.\n\n" }, - "Identifier": "Speak Validation Error", + "Identifier": "Transfer Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "a3ea896e-4f43-4677-8edd-159f677dc41e", "Errors": [ { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "a3ea896e-4f43-4677-8edd-159f677dc41e", "ErrorType": "NoMatchingError" } ] @@ -1897,19 +1904,29 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", + "FlowLoggingBehavior": "Disabled" + }, + "Identifier": "87859db2-400d-410b-8818-05c8ae4869aa", + "Type": "UpdateFlowLoggingBehavior", + "Transitions": { + "NextAction": "Set Receipt Queue ID" + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Tokenize Transaction", + "Identifier": "Create Payment Request", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Check for Tokenize Error", + "NextAction": "Record Payment Request ID", "Errors": [ { - "NextAction": "Payment Validation Error", + "NextAction": "Payment Request Error", "ErrorType": "NoMatchingError" } ] @@ -1917,15 +1934,19 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nThere was a problem validating your $.Attributes.PaymentMethod information.\n\n" + "FlowAttributes": { + "ReceiptQueueId": { + "Value": "<>" + } + } }, - "Identifier": "Payment Validation Error", - "Type": "MessageParticipant", + "Identifier": "Set Receipt Queue ID", + "Type": "UpdateFlowAttributes", "Transitions": { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "Create Payment Request", "Errors": [ { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "Create Payment Request", "ErrorType": "NoMatchingError" } ] @@ -1933,39 +1954,40 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "ResponseValidation": { - "ResponseType": "JSON" - } + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Submit Payment", - "Type": "InvokeLambdaFunction", + "Identifier": "Card Number Timeout Check", + "Type": "Compare", "Transitions": { - "NextAction": "Record Transaction Attributes", + "NextAction": "Validate Card Number", + "Conditions": [ + { + "NextAction": "Card Number Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } + } + ], "Errors": [ { - "NextAction": "Payment Submission Error", - "ErrorType": "NoMatchingError" + "NextAction": "Validate Card Number", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "Attributes": { - "PaymentToken": "NULL", - "PaymentMethod": "NULL" - }, - "TargetContact": "Current" + "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" }, - "Identifier": "Remove Failed Payment Token and Method", - "Type": "UpdateContactAttributes", + "Identifier": "Card Number Validation Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Get & Encrypt Card Number", "Errors": [ { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Get & Encrypt Card Number", "ErrorType": "NoMatchingError" } ] @@ -1973,15 +1995,23 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nWe're sorry, an error has occured preventing us from submitting your payment. You have not been charged.\n\n" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "ValidationType": "CardNumber", + "CustomerEntry": "$.StoredCustomerInput" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Payment Submission Error", - "Type": "MessageParticipant", + "Identifier": "Validate Card Number", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "Check for Card Number Validation Error", "Errors": [ { - "NextAction": "Remove Failed Payment Token and Method", + "NextAction": "Store Encrypted Card Number", "ErrorType": "NoMatchingError" } ] @@ -1989,44 +2019,49 @@ }, { "Parameters": { - "Attributes": { - "TransactionId": "$.External.TransactionId", - "PaymentMethodEndingDigits": "$.External.PaymentMethodEndingDigits" - }, - "TargetContact": "Current" + "ComparisonValue": "$.External.ValidationError" }, - "Identifier": "Record Transaction Attributes", - "Type": "UpdateContactAttributes", + "Identifier": "Check for Card Number Validation Error", + "Type": "Compare", "Transitions": { - "NextAction": "Payment Success", + "NextAction": "Card Number Validation Error", + "Conditions": [ + { + "NextAction": "Store Encrypted Card Number", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], "Errors": [ { - "NextAction": "Payment Success", - "ErrorType": "NoMatchingError" + "NextAction": "Card Number Validation Error", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "ComparisonValue": "$.Attributes.Email" + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Check for Customer Email", + "Identifier": "Account Number Timeout Check", "Type": "Compare", "Transitions": { - "NextAction": "Has Specified Receipt Queue", + "NextAction": "Validate Account Number", "Conditions": [ { - "NextAction": "Send Receipt", + "NextAction": "Account Number Timeout", "Condition": { - "Operator": "TextContains", - "Operands": ["@"] + "Operator": "Equals", + "Operands": ["Timeout"] } } ], "Errors": [ { - "NextAction": "Has Specified Receipt Queue", + "NextAction": "Validate Account Number", "ErrorType": "NoMatchingCondition" } ] @@ -2034,15 +2069,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nYour payment was processed successfully.\n\n" + "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" }, - "Identifier": "Payment Success", + "Identifier": "Account Number Validation Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Check for Customer Email", + "NextAction": "Get & Encrypt Account Number", "Errors": [ { - "NextAction": "Check for Customer Email", + "NextAction": "Get & Encrypt Account Number", "ErrorType": "NoMatchingError" } ] @@ -2050,20 +2085,26 @@ }, { "Parameters": { - "Attributes": { - "EncryptedCardNumber": "REDACTED", - "EncryptedAccountNumber": "REDACTED", - "ExpirationDate": "REDACTED" + "StoreInput": "True", + "InputTimeLimitSeconds": "10", + "Text": "\n>\" rate=\"<>\">\nPlease enter your bank's routing number, followed by the pound key when complete.\n\n", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" }, - "TargetContact": "Current" + "InputValidation": { + "CustomValidation": { + "MaximumLength": "25" + } + } }, - "Identifier": "Redact Sensitive Contact Attributes Copy", - "Type": "UpdateContactAttributes", + "Identifier": "Get Routing Number", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Set Queue", + "NextAction": "Routing Number Timeout Check", "Errors": [ { - "NextAction": "Set Queue", + "NextAction": "Try Routing Number Again", "ErrorType": "NoMatchingError" } ] @@ -2071,56 +2112,64 @@ }, { "Parameters": { - "ComparisonValue": "$.FlowAttributes.ReceiptQueueId" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "ValidationType": "AccountNumber", + "CustomerEntry": "$.StoredCustomerInput" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Has Specified Receipt Queue", - "Type": "Compare", + "Identifier": "Validate Account Number", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Ask to Transfer for Receipt", - "Conditions": [ - { - "NextAction": "Redact Sensitive Contact Attributes", - "Condition": { - "Operator": "Equals", - "Operands": ["NULL"] - } - } - ], + "NextAction": "Check for Account Number Validation Error", "Errors": [ { - "NextAction": "Ask to Transfer for Receipt", - "ErrorType": "NoMatchingCondition" + "NextAction": "Store Encrypted Account Number", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nAre you still there?\n\n" + "ComparisonValue": "$.External.ValidationError" }, - "Identifier": "Receipt Timeout", - "Type": "MessageParticipant", + "Identifier": "Check for Account Number Validation Error", + "Type": "Compare", "Transitions": { - "NextAction": "Ask to Transfer for Receipt", + "NextAction": "Account Number Validation Error", + "Conditions": [ + { + "NextAction": "Store Encrypted Account Number", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], "Errors": [ { - "NextAction": "Ask to Transfer for Receipt", - "ErrorType": "NoMatchingError" + "NextAction": "Account Number Validation Error", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nYour entry was not recognized. Please try again.\n\n" + "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" }, - "Identifier": "Receipt Entry Not Recognized", + "Identifier": "Routing Number Validation Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Ask to Transfer for Receipt", + "NextAction": "Get Routing Number", "Errors": [ { - "NextAction": "Ask to Transfer for Receipt", + "NextAction": "Get Routing Number", "ErrorType": "NoMatchingError" } ] @@ -2128,77 +2177,73 @@ }, { "Parameters": { - "StoreInput": "False", - "InputTimeLimitSeconds": "5", - "Text": "\n>\" rate=\"<>\">\nTo transfer to a representative and receive a receipt for your payment, press 1.\nTo continue without a receipt, press 2.\n\n" + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Ask to Transfer for Receipt", - "Type": "GetParticipantInput", + "Identifier": "Routing Number Timeout Check", + "Type": "Compare", "Transitions": { - "NextAction": "Receipt Entry Not Recognized", + "NextAction": "Validate Routing Number", "Conditions": [ { - "NextAction": "Redact Sensitive Contact Attributes Copy", - "Condition": { - "Operator": "Equals", - "Operands": ["1"] - } - }, - { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Routing Number Timeout", "Condition": { "Operator": "Equals", - "Operands": ["2"] + "Operands": ["Timeout"] } } ], "Errors": [ { - "NextAction": "Receipt Timeout", - "ErrorType": "InputTimeLimitExceeded" - }, - { - "NextAction": "Receipt Entry Not Recognized", + "NextAction": "Validate Routing Number", "ErrorType": "NoMatchingCondition" - }, - { - "NextAction": "Receipt Entry Not Recognized", - "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nA receipt has been sent to your email address, $.Attributes.['Email'].\n\n" + "ComparisonValue": "$.External.ValidationError" }, - "Identifier": "Receipt Success", - "Type": "MessageParticipant", + "Identifier": "Check for Routing Number Validation Error", + "Type": "Compare", "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Routing Number Validation Error", + "Conditions": [ + { + "NextAction": "Store Routing Number", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], "Errors": [ { - "NextAction": "Redact Sensitive Contact Attributes", - "ErrorType": "NoMatchingError" + "NextAction": "Routing Number Validation Error", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "LambdaFunctionARN": "<>", + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "ValidationType": "RoutingNumber", + "CustomerEntry": "$.StoredCustomerInput" + }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Send Receipt", + "Identifier": "Validate Routing Number", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Receipt Success", + "NextAction": "Check for Routing Number Validation Error", "Errors": [ { - "NextAction": "Receipt Error", + "NextAction": "Store Routing Number", "ErrorType": "NoMatchingError" } ] @@ -2206,20 +2251,15 @@ }, { "Parameters": { - "Attributes": { - "EncryptedCardNumber": "REDACTED", - "EncryptedAccountNumber": "REDACTED", - "ExpirationDate": "REDACTED" - }, - "TargetContact": "Current" + "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" }, - "Identifier": "Redact Sensitive Contact Attributes", - "Type": "UpdateContactAttributes", + "Identifier": "Expiration Date Validation Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "a3ea896e-4f43-4677-8edd-159f677dc41e", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "a3ea896e-4f43-4677-8edd-159f677dc41e", + "NextAction": "Get Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -2227,71 +2267,73 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nThere was an error sending the receipt to your email address, $.Attributes.['Email']. Please contact customer support to receive a receipt for this transaction.\n\n" + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Receipt Error", - "Type": "MessageParticipant", + "Identifier": "Expiration Date Timeout Check", + "Type": "Compare", "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", - "Errors": [ + "NextAction": "Validate Expiration Date", + "Conditions": [ { - "NextAction": "Redact Sensitive Contact Attributes", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": {}, - "Identifier": "a3ea896e-4f43-4677-8edd-159f677dc41e", - "Type": "EndFlowModuleExecution", - "Transitions": {} - }, - { - "Parameters": {}, - "Identifier": "Transfer to Representative", - "Type": "TransferContactToQueue", - "Transitions": { - "NextAction": "Transfer Error", + "NextAction": "Expiration Date Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } + } + ], "Errors": [ { - "NextAction": "Transfer Error", - "ErrorType": "QueueAtCapacity" - }, - { - "NextAction": "Transfer Error", - "ErrorType": "NoMatchingError" + "NextAction": "Validate Expiration Date", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "QueueId": "$.FlowAttributes.ReceiptQueueId" + "ComparisonValue": "$.External.ValidationError" }, - "Identifier": "Set Queue", - "Type": "UpdateContactTargetQueue", + "Identifier": "Check for Expiration Date Validation Error", + "Type": "Compare", "Transitions": { - "NextAction": "Transfer to Representative", + "NextAction": "Expiration Date Validation Error", + "Conditions": [ + { + "NextAction": "Store Expiration Date", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], "Errors": [ { - "NextAction": "Transfer Error", - "ErrorType": "NoMatchingError" + "NextAction": "Expiration Date Validation Error", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\nAn error prevented us from connecting you to a representative. Please try calling the customer service number directly in order to receive a receipt.\n\n" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "ValidationType": "ExpirationDate", + "CustomerEntry": "$.StoredCustomerInput" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Transfer Error", - "Type": "MessageParticipant", + "Identifier": "Validate Expiration Date", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "a3ea896e-4f43-4677-8edd-159f677dc41e", + "NextAction": "Check for Expiration Date Validation Error", "Errors": [ { - "NextAction": "a3ea896e-4f43-4677-8edd-159f677dc41e", + "NextAction": "Store Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -2299,29 +2341,45 @@ }, { "Parameters": { - "FlowLoggingBehavior": "Disabled" + "StoreInput": "True", + "InputTimeLimitSeconds": "5", + "Text": "\n>\" rate=\"<>\">\nPlease enter the amount you would like to pay in whole dollars, followed by the pound key.\n\n", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" + }, + "InputValidation": { + "CustomValidation": { + "MaximumLength": "20" + } + } }, - "Identifier": "87859db2-400d-410b-8818-05c8ae4869aa", - "Type": "UpdateFlowLoggingBehavior", + "Identifier": "Get Payment Amount", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Set Receipt Queue ID" + "NextAction": "Check Payment Amount", + "Errors": [ + { + "NextAction": "Internal Error", + "ErrorType": "NoMatchingError" + } + ] } }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "ResponseValidation": { - "ResponseType": "JSON" - } + "Attributes": { + "PaymentAmount": "$.StoredCustomerInput" + }, + "TargetContact": "Current" }, - "Identifier": "Create Payment Request", - "Type": "InvokeLambdaFunction", + "Identifier": "Set Payment Amount to Entered Amount", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Record Payment Request ID", + "NextAction": "Check Last Payment Method", "Errors": [ { - "NextAction": "Payment Request Error", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -2329,19 +2387,18 @@ }, { "Parameters": { - "FlowAttributes": { - "ReceiptQueueId": { - "Value": "<>" - } - } + "Attributes": { + "PaymentAmount": "$.Customer.Attributes.PaymentAmountDue" + }, + "TargetContact": "Current" }, - "Identifier": "Set Receipt Queue ID", - "Type": "UpdateFlowAttributes", + "Identifier": "Set Payment Amount to Full Amount", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Create Payment Request", + "NextAction": "Check Last Payment Method", "Errors": [ { - "NextAction": "Create Payment Request", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -2349,40 +2406,61 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "StoreInput": "True", + "InputTimeLimitSeconds": "10", + "Text": "\n>\" rate=\"<>\">\nPlease enter your bank account number followed by the pound key when complete.\n\n", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" + }, + "InputValidation": { + "CustomValidation": { + "MaximumLength": "25" + } + }, + "InputEncryption": { + "EncryptionKeyId": "<>", + "Key": "<>" + } }, - "Identifier": "Card Number Timeout Check", - "Type": "Compare", + "Identifier": "Get & Encrypt Account Number", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Validate Card Number", - "Conditions": [ - { - "NextAction": "Card Number Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - } - ], + "NextAction": "Account Number Timeout Check", "Errors": [ { - "NextAction": "Validate Card Number", - "ErrorType": "NoMatchingCondition" + "NextAction": "Internal Error", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" + "StoreInput": "True", + "InputTimeLimitSeconds": "10", + "Text": "\n>\" rate=\"<>\">\nPlease enter your card number followed by the pound key when complete.\n\n", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" + }, + "InputValidation": { + "CustomValidation": { + "MaximumLength": "25" + } + }, + "InputEncryption": { + "EncryptionKeyId": "<>", + "Key": "<>" + } }, - "Identifier": "Card Number Validation Error", - "Type": "MessageParticipant", + "Identifier": "Get & Encrypt Card Number", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Card Number Timeout Check", "Errors": [ { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -2391,17 +2469,19 @@ { "Parameters": { "Attributes": { - "EncryptedCardNumber": "$.StoredCustomerInput" + "EncryptedCardNumber": "REDACTED", + "EncryptedAccountNumber": "REDACTED", + "ExpirationDate": "REDACTED" }, "TargetContact": "Current" }, - "Identifier": "Store Encrypted Card Number", + "Identifier": "Redact Sensitive Contact Attributes", "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "a3ea896e-4f43-4677-8edd-159f677dc41e", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "a3ea896e-4f43-4677-8edd-159f677dc41e", "ErrorType": "NoMatchingError" } ] @@ -2409,23 +2489,18 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "ValidationType": "CardNumber", - "CustomerEntry": "$.StoredCustomerInput" + "Attributes": { + "EncryptedCardNumber": "$.StoredCustomerInput" }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "TargetContact": "Current" }, - "Identifier": "Validate Card Number", - "Type": "InvokeLambdaFunction", + "Identifier": "Store Encrypted Card Number", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Check for Card Number Validation Error", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "Store Encrypted Card Number", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -2433,65 +2508,56 @@ }, { "Parameters": { - "ComparisonValue": "$.External.ValidationError" + "Attributes": { + "EncryptedAccountNumber": "$.StoredCustomerInput" + }, + "TargetContact": "Current" }, - "Identifier": "Check for Card Number Validation Error", - "Type": "Compare", + "Identifier": "Store Encrypted Account Number", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Card Number Validation Error", - "Conditions": [ - { - "NextAction": "Store Encrypted Card Number", - "Condition": { - "Operator": "Equals", - "Operands": ["NULL"] - } - } - ], + "NextAction": "Get Routing Number", "Errors": [ { - "NextAction": "Card Number Validation Error", - "ErrorType": "NoMatchingCondition" + "NextAction": "Internal Error", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "Attributes": { + "RoutingNumber": "$.StoredCustomerInput" + }, + "TargetContact": "Current" }, - "Identifier": "Account Number Timeout Check", - "Type": "Compare", + "Identifier": "Store Routing Number", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Validate Account Number", - "Conditions": [ - { - "NextAction": "Account Number Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - } - ], + "NextAction": "Tokenize Transaction", "Errors": [ { - "NextAction": "Validate Account Number", - "ErrorType": "NoMatchingCondition" + "NextAction": "Internal Error", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" + "Attributes": { + "ExpirationDate": "$.StoredCustomerInput" + }, + "TargetContact": "Current" }, - "Identifier": "Account Number Validation Error", - "Type": "MessageParticipant", + "Identifier": "Store Expiration Date", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Get & Encrypt Account Number", + "NextAction": "Tokenize Transaction", "Errors": [ { - "NextAction": "Get & Encrypt Account Number", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -2515,50 +2581,15 @@ }, { "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "10", - "Text": "\n>\" rate=\"<>\">\nPlease enter your bank's routing number, followed by the pound key when complete.\n\n", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "25" - } - } - }, - "Identifier": "Get Routing Number", - "Type": "GetParticipantInput", - "Transitions": { - "NextAction": "Routing Number Timeout Check", - "Errors": [ - { - "NextAction": "Try Routing Number Again", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "ValidationType": "AccountNumber", - "CustomerEntry": "$.StoredCustomerInput" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "Text": "\n>\" rate=\"<>\">\nThe payment failed because of the following error:\n\n$.External.Error\n\n" }, - "Identifier": "Validate Account Number", - "Type": "InvokeLambdaFunction", + "Identifier": "Speak Validation Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Check for Account Number Validation Error", + "NextAction": "Remove Failed Payment Token and Method", "Errors": [ { - "NextAction": "Store Encrypted Account Number", + "NextAction": "Remove Failed Payment Token and Method", "ErrorType": "NoMatchingError" } ] @@ -2566,15 +2597,15 @@ }, { "Parameters": { - "ComparisonValue": "$.External.ValidationError" + "ComparisonValue": "$.External.Error" }, - "Identifier": "Check for Account Number Validation Error", + "Identifier": "Check for Tokenize Error", "Type": "Compare", "Transitions": { - "NextAction": "Account Number Validation Error", + "NextAction": "Speak Validation Error", "Conditions": [ { - "NextAction": "Store Encrypted Account Number", + "NextAction": "Record Token", "Condition": { "Operator": "Equals", "Operands": ["NULL"] @@ -2583,7 +2614,7 @@ ], "Errors": [ { - "NextAction": "Account Number Validation Error", + "NextAction": "Speak Validation Error", "ErrorType": "NoMatchingCondition" } ] @@ -2591,18 +2622,15 @@ }, { "Parameters": { - "Attributes": { - "EncryptedAccountNumber": "$.StoredCustomerInput" - }, - "TargetContact": "Current" + "Text": "\n>\" rate=\"<>\">\nYour payment was processed successfully.\n\n" }, - "Identifier": "Store Encrypted Account Number", - "Type": "UpdateContactAttributes", + "Identifier": "Payment Success", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Routing Number", + "NextAction": "Check for Customer Email", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "Check for Customer Email", "ErrorType": "NoMatchingError" } ] @@ -2610,18 +2638,19 @@ }, { "Parameters": { - "Attributes": { - "RoutingNumber": "$.StoredCustomerInput" - }, - "TargetContact": "Current" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Store Routing Number", - "Type": "UpdateContactAttributes", + "Identifier": "Tokenize Transaction", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Tokenize Transaction", + "NextAction": "Check for Tokenize Error", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "Payment Validation Error", "ErrorType": "NoMatchingError" } ] @@ -2629,15 +2658,15 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" + "Text": "\n>\" rate=\"<>\">\nThere was a problem validating your $.Attributes.PaymentMethod information.\n\n" }, - "Identifier": "Routing Number Validation Error", + "Identifier": "Payment Validation Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Routing Number", + "NextAction": "Remove Failed Payment Token and Method", "Errors": [ { - "NextAction": "Get Routing Number", + "NextAction": "Remove Failed Payment Token and Method", "ErrorType": "NoMatchingError" } ] @@ -2645,73 +2674,102 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "StoreInput": "False", + "InputTimeLimitSeconds": "5", + "Text": "\n>\" rate=\"<>\">\nYou previously paid with a credit or debit card ending in $.Attributes.PaymentMethodEndingDigits.\n\nIf you would like to use this card again for this payment, press 1.\nTo use a different payment method, press 2.\n\n" }, - "Identifier": "Routing Number Timeout Check", - "Type": "Compare", + "Identifier": "Use Card Again?", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Validate Routing Number", + "NextAction": "Ask for Payment Method", "Conditions": [ { - "NextAction": "Routing Number Timeout", + "NextAction": "Submit Payment", "Condition": { "Operator": "Equals", - "Operands": ["Timeout"] + "Operands": ["1"] + } + }, + { + "NextAction": "Ask for Payment Method", + "Condition": { + "Operator": "Equals", + "Operands": ["2"] } } ], "Errors": [ { - "NextAction": "Validate Routing Number", + "NextAction": "Use Payment Method Again Timeout", + "ErrorType": "InputTimeLimitExceeded" + }, + { + "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingCondition" + }, + { + "NextAction": "Ask for Payment Method", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "ComparisonValue": "$.External.ValidationError" + "StoreInput": "False", + "InputTimeLimitSeconds": "5", + "Text": "\n>\" rate=\"<>\">\nYou previously paid with a bank account ending in $.Attributes.PaymentMethodEndingDigits.\n\nIf you would like to use this account again for this payment, press 1.\nTo use a different payment method, press 2.\n\n" }, - "Identifier": "Check for Routing Number Validation Error", - "Type": "Compare", + "Identifier": "Use Bank Account Again?", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Routing Number Validation Error", + "NextAction": "Ask for Payment Method", "Conditions": [ { - "NextAction": "Store Routing Number", + "NextAction": "Submit Payment", "Condition": { "Operator": "Equals", - "Operands": ["NULL"] + "Operands": ["1"] + } + }, + { + "NextAction": "Ask for Payment Method", + "Condition": { + "Operator": "Equals", + "Operands": ["2"] } } ], "Errors": [ { - "NextAction": "Routing Number Validation Error", + "NextAction": "Use Payment Method Again Timeout", + "ErrorType": "InputTimeLimitExceeded" + }, + { + "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingCondition" + }, + { + "NextAction": "Ask for Payment Method", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "ValidationType": "RoutingNumber", - "CustomerEntry": "$.StoredCustomerInput" + "Attributes": { + "PaymentToken": "$.External.PaymentToken" }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "TargetContact": "Current" }, - "Identifier": "Validate Routing Number", - "Type": "InvokeLambdaFunction", + "Identifier": "Record Token", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Check for Routing Number Validation Error", + "NextAction": "Submit Payment", "Errors": [ { - "NextAction": "Store Routing Number", + "NextAction": "Submit Payment", "ErrorType": "NoMatchingError" } ] @@ -2720,17 +2778,19 @@ { "Parameters": { "Attributes": { - "ExpirationDate": "$.StoredCustomerInput" + "TransactionId": "$.External.TransactionId", + "PaymentMethodEndingDigits": "$.External.PaymentMethodEndingDigits", + "TransactionIds": "$.External.TransactionIds" }, "TargetContact": "Current" }, - "Identifier": "Store Expiration Date", + "Identifier": "Record Transaction Attributes", "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Tokenize Transaction", + "NextAction": "Payment Success", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "Payment Success", "ErrorType": "NoMatchingError" } ] @@ -2738,15 +2798,19 @@ }, { "Parameters": { - "Text": "\n>\" rate=\"<>\">\n$.External.ValidationError\n\nPlease check your entry and try again.\n\n" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Expiration Date Validation Error", - "Type": "MessageParticipant", + "Identifier": "Submit Payment", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Check for Submit Payment Error", "Errors": [ { - "NextAction": "Get Expiration Date", + "NextAction": "Speak Payment Submission Unknown Error", "ErrorType": "NoMatchingError" } ] @@ -2754,40 +2818,31 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "Text": "\n>\" rate=\"<>\">\nThe payment failed to submit because of an unknown error. You have not been charged.\n\n" }, - "Identifier": "Expiration Date Timeout Check", - "Type": "Compare", + "Identifier": "Speak Payment Submission Unknown Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Validate Expiration Date", - "Conditions": [ - { - "NextAction": "Expiration Date Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - } - ], + "NextAction": "Remove Failed Payment Token and Method", "Errors": [ { - "NextAction": "Validate Expiration Date", - "ErrorType": "NoMatchingCondition" + "NextAction": "Remove Failed Payment Token and Method", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "ComparisonValue": "$.External.ValidationError" + "ComparisonValue": "$.External.Error" }, - "Identifier": "Check for Expiration Date Validation Error", + "Identifier": "Check for Submit Payment Error", "Type": "Compare", "Transitions": { - "NextAction": "Expiration Date Validation Error", + "NextAction": "Speak Payment Submission Error", "Conditions": [ { - "NextAction": "Store Expiration Date", + "NextAction": "Record Transaction Attributes", "Condition": { "Operator": "Equals", "Operands": ["NULL"] @@ -2796,7 +2851,7 @@ ], "Errors": [ { - "NextAction": "Expiration Date Validation Error", + "NextAction": "Speak Payment Submission Error", "ErrorType": "NoMatchingCondition" } ] @@ -2804,23 +2859,35 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "ValidationType": "ExpirationDate", - "CustomerEntry": "$.StoredCustomerInput" + "Attributes": { + "PaymentToken": "NULL", + "PaymentMethod": "NULL" }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "TargetContact": "Current" }, - "Identifier": "Validate Expiration Date", - "Type": "InvokeLambdaFunction", + "Identifier": "Remove Failed Payment Token and Method", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Check for Expiration Date Validation Error", + "NextAction": "Redact Sensitive Contact Attributes", "Errors": [ { - "NextAction": "Store Expiration Date", + "NextAction": "Redact Sensitive Contact Attributes", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\nThe payment failed to submit because of the following error:\n\n$.External.Error\n\nYou have not been charged.\n\n" + }, + "Identifier": "Speak Payment Submission Error", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Remove Failed Payment Token and Method", + "Errors": [ + { + "NextAction": "Remove Failed Payment Token and Method", "ErrorType": "NoMatchingError" } ] diff --git a/lib/lambda/c3-submit-payment/index.js b/lib/lambda/c3-submit-payment/index.js index 1c845b9..f8faa21 100644 --- a/lib/lambda/c3-submit-payment/index.js +++ b/lib/lambda/c3-submit-payment/index.js @@ -1,4 +1,5 @@ import { getAPIKey } from '/opt/nodejs/c3.js'; +import { stripTagsFromText } from '/opt/nodejs/formatting.js'; /** * @type {import ('aws-lambda').Handler} @@ -6,74 +7,81 @@ import { getAPIKey } from '/opt/nodejs/c3.js'; export async function handler(event) { console.log(`EVENT: ${JSON.stringify(event)}`); - // Get the contact attributes. - let contactAttributes = {}; - contactAttributes = event.Details.ContactData.Attributes; - if (!contactAttributes) { - throw new Error('Contact attributes not found.'); - } - if (!contactAttributes.PaymentToken) { - throw new Error('PaymentToken contact attribute not found.'); - } - if (!contactAttributes.PaymentMethod) { - throw new Error('PaymentMethod contact attribute not found.'); - } - const paymentMethod = contactAttributes.PaymentMethod; + try { + // Get the contact attributes. + let contactAttributes = {}; + contactAttributes = event.Details.ContactData.Attributes; + if (!contactAttributes) { + throw new Error('Contact attributes not found.'); + } + if (!contactAttributes.PaymentToken) { + throw new Error('PaymentToken contact attribute not found.'); + } + if (!contactAttributes.PaymentMethod) { + throw new Error('PaymentMethod contact attribute not found.'); + } + const paymentMethod = contactAttributes.PaymentMethod; - // Post the transaction. - let paymentInfo = { - name: contactAttributes.ContactName, - paymentAmount: +contactAttributes.PaymentAmount, - token: contactAttributes.PaymentToken, + // Post the transaction. + let paymentInfo = { + name: contactAttributes.ContactName, + paymentAmount: +contactAttributes.PaymentAmount, + token: contactAttributes.PaymentToken, - // Passing these if they exist, but they are not required. - address1: contactAttributes.Address1, - address2: contactAttributes.Address2, - city: contactAttributes.City, - state: contactAttributes.State, - zipCode: contactAttributes.ZipCode, - }; - if (paymentMethod === 'Card') { - const creditCardPaymentInfo = { - expiration: '', // Expiration date is not required for Zift. - }; - paymentInfo = { ...paymentInfo, ...creditCardPaymentInfo }; - } else if (paymentMethod === 'Bank') { - const bankAccountPaymentInfo = { - routingNumber: contactAttributes.RoutingNumber, + // Passing these if they exist, but they are not required. + address1: contactAttributes.Address1, + address2: contactAttributes.Address2, + city: contactAttributes.City, + state: contactAttributes.State, + zipCode: contactAttributes.ZipCode, }; - paymentInfo = { ...paymentInfo, ...bankAccountPaymentInfo }; - } + if (paymentMethod === 'Card') { + const creditCardPaymentInfo = { + expiration: '', // Expiration date is not required for Zift. + }; + paymentInfo = { ...paymentInfo, ...creditCardPaymentInfo }; + } else if (paymentMethod === 'Bank') { + const bankAccountPaymentInfo = { + routingNumber: contactAttributes.RoutingNumber, + }; + paymentInfo = { ...paymentInfo, ...bankAccountPaymentInfo }; + } - const response = await postTransaction( - contactAttributes.PaymentRequestId, - paymentInfo, - ); - console.log('Post transaction response:', response); + const response = await postTransaction( + contactAttributes.PaymentRequestId, + paymentInfo, + ); + console.log('Post transaction response:', response); - // Get the last 4 digits of the card number or the bank account number. - const maskedNumber = - paymentMethod === 'Card' - ? response.transaction.cardNumber - : response.transaction.bankAccountNumber; - const endingDigits = maskedNumber.slice(-4); + // Get the last 4 digits of the card number or the bank account number. + const maskedNumber = + paymentMethod === 'Card' + ? response.transaction.cardNumber + : response.transaction.bankAccountNumber; + const endingDigits = maskedNumber.slice(-4); - // Update the list of all transaction IDs. - const previousTransactionIds = contactAttributes.TransactionIds - ? JSON.parse(contactAttributes.TransactionIds) - : []; - const newTransactionIds = [ - ...previousTransactionIds, - response.transaction.id, - ]; + // Update the list of all transaction IDs. + const previousTransactionIds = contactAttributes.TransactionIds + ? JSON.parse(contactAttributes.TransactionIds) + : []; + const newTransactionIds = [ + ...previousTransactionIds, + response.transaction.id, + ]; - return { - TransactionApproved: response.transactionApproved, - TransactionId: response.transaction.id, - TransactionIds: JSON.stringify(newTransactionIds), - TransactionMeta: response.transactionMeta, - PaymentMethodEndingDigits: endingDigits, - }; + return { + TransactionApproved: response.transactionApproved, + TransactionId: response.transaction.id, + TransactionIds: JSON.stringify(newTransactionIds), + TransactionMeta: response.transactionMeta, + PaymentMethodEndingDigits: endingDigits, + Error: 'NULL', + }; + } catch (error) { + return { + Error: stripTagsFromText(error.message), + }; + } } /** @@ -103,8 +111,10 @@ async function postTransaction(paymentRequestId, paymentInfo) { }, ); if (!postTransactionResponse.ok) { + const response = await postTransactionResponse.json(); + const metaInfo = JSON.parse(response.transactionMeta.metaInfo); throw new Error( - `Failed to post transaction: ${postTransactionResponse.statusText}`, + `Zift Error: ${metaInfo.responseMessage ?? 'An unknown error occurred.'}`, ); } return postTransactionResponse.json(); diff --git a/lib/lambda/c3-tokenize-transaction/gateways/zift.js b/lib/lambda/c3-tokenize-transaction/gateways/zift.js index 5262f4d..ae634fd 100644 --- a/lib/lambda/c3-tokenize-transaction/gateways/zift.js +++ b/lib/lambda/c3-tokenize-transaction/gateways/zift.js @@ -155,7 +155,7 @@ export class Zift { : TokenizeErrors.InvalidRoutingNumber; default: // Return the Zift message for any other scenario. - return message; + return `Zift Error: ${message}`; } } } From be8cd818e59d3125f63bfc4a0ee9c90ffea60ddd Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 13:05:06 -0600 Subject: [PATCH 09/17] test: update tests for additional context option --- test/c3-amazon-connect.test.ts | 1 + test/features/agent-assisted-ivr.test.ts | 1 + test/features/agent-assisted-link.test.ts | 1 + test/features/self-service-ivr.test.ts | 1 + test/features/subject-lookup.test.ts | 1 + test/options/code-signing.test.ts | 1 + .../{workspace-app.test.ts => payment-request-app.test.ts} | 5 +++-- 7 files changed, 9 insertions(+), 2 deletions(-) rename test/options/{workspace-app.test.ts => payment-request-app.test.ts} (94%) diff --git a/test/c3-amazon-connect.test.ts b/test/c3-amazon-connect.test.ts index 1dd7a4c..4cef52b 100644 --- a/test/c3-amazon-connect.test.ts +++ b/test/c3-amazon-connect.test.ts @@ -30,6 +30,7 @@ const mockContext: Context = { agentAssistedLink: true, selfServiceIVR: true, subjectLookup: SubjectLookupMode.RequiredEditable, + receiptApp: true, }, options: { codeSigning: true, diff --git a/test/features/agent-assisted-ivr.test.ts b/test/features/agent-assisted-ivr.test.ts index 44c8cb6..fa33014 100644 --- a/test/features/agent-assisted-ivr.test.ts +++ b/test/features/agent-assisted-ivr.test.ts @@ -30,6 +30,7 @@ const mockContext: Context = { agentAssistedLink: false, selfServiceIVR: false, subjectLookup: SubjectLookupMode.Disabled, + receiptApp: false, }, options: { codeSigning: true, diff --git a/test/features/agent-assisted-link.test.ts b/test/features/agent-assisted-link.test.ts index c690148..9f764bc 100644 --- a/test/features/agent-assisted-link.test.ts +++ b/test/features/agent-assisted-link.test.ts @@ -30,6 +30,7 @@ const mockContext: Context = { agentAssistedLink: true, selfServiceIVR: false, subjectLookup: SubjectLookupMode.Disabled, + receiptApp: false, }, options: { codeSigning: true, diff --git a/test/features/self-service-ivr.test.ts b/test/features/self-service-ivr.test.ts index 8b4abcc..84d6a37 100644 --- a/test/features/self-service-ivr.test.ts +++ b/test/features/self-service-ivr.test.ts @@ -30,6 +30,7 @@ const mockContext: Context = { agentAssistedLink: false, selfServiceIVR: true, subjectLookup: SubjectLookupMode.Disabled, + receiptApp: false, }, options: { codeSigning: true, diff --git a/test/features/subject-lookup.test.ts b/test/features/subject-lookup.test.ts index 182524a..45a764b 100644 --- a/test/features/subject-lookup.test.ts +++ b/test/features/subject-lookup.test.ts @@ -30,6 +30,7 @@ const mockContext: Context = { agentAssistedLink: false, selfServiceIVR: false, subjectLookup: SubjectLookupMode.OptionalEditable, + receiptApp: false, }, options: { codeSigning: true, diff --git a/test/options/code-signing.test.ts b/test/options/code-signing.test.ts index b1b9f59..1852391 100644 --- a/test/options/code-signing.test.ts +++ b/test/options/code-signing.test.ts @@ -30,6 +30,7 @@ const mockContext: Context = { agentAssistedLink: true, selfServiceIVR: true, subjectLookup: SubjectLookupMode.RequiredEditable, + receiptApp: true, }, options: { codeSigning: false, diff --git a/test/options/workspace-app.test.ts b/test/options/payment-request-app.test.ts similarity index 94% rename from test/options/workspace-app.test.ts rename to test/options/payment-request-app.test.ts index e6b6b94..b09583e 100644 --- a/test/options/workspace-app.test.ts +++ b/test/options/payment-request-app.test.ts @@ -30,6 +30,7 @@ const mockContext: Context = { agentAssistedLink: false, selfServiceIVR: false, subjectLookup: SubjectLookupMode.Disabled, + receiptApp: false, }, options: { codeSigning: true, @@ -45,8 +46,8 @@ const mockContext: Context = { const NUMBER_OF_LAMBDAS = 6; -// Verify created resources for agent-assisted IVR. -describe('Workspace app', () => { +// Verify created resources for payment request app +describe('Payment Request App', () => { // 3rd party apps describe('3rd party apps', () => { it('Has 1 3rd party app when flag is true', () => { From a4de943844fe268aa9f330afd2b4eeb7da27f012 Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 13:05:21 -0600 Subject: [PATCH 10/17] ci: add context option for workspace app --- .github/workflows/checks.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index fb8664e..d6ccf6e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -48,7 +48,8 @@ jobs: "agentAssistedIVR": true, "agentAssistedLink": true, "selfServiceIVR": true, - "subjectLookup": "required-editable" + "subjectLookup": "required-editable", + "receiptApp": true }, "options": { "codeSigning": true, From 7aa969eefa20fa4456911d740c30437e70439d30 Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 23:28:28 -0600 Subject: [PATCH 11/17] feat!: add receipt app to allow agents to send receipts after a self-service transfer BREAKING CHANGE: renames existing workspace apps --- cdk.context.json | 5 +- lib/c3-amazon-connect-stack.ts | 55 ++- lib/connect/content-transformations.ts | 28 +- lib/connect/flows/c3-receipt-flow.json | 471 +++++++++++++++++++++++++ lib/features/receipt-app.ts | 180 ++++++++++ lib/lambda/c3-send-receipt/index.js | 22 +- lib/models/features-context.ts | 8 + package.json | 2 +- scripts/deploy.sh | 4 +- scripts/insert-placeholders.sh | 10 +- scripts/synth.sh | 4 +- 11 files changed, 762 insertions(+), 27 deletions(-) create mode 100644 lib/connect/flows/c3-receipt-flow.json create mode 100644 lib/features/receipt-app.ts diff --git a/cdk.context.json b/cdk.context.json index c445237..e6486d4 100644 --- a/cdk.context.json +++ b/cdk.context.json @@ -16,7 +16,8 @@ "agentAssistedIVR": true, "agentAssistedLink": true, "selfServiceIVR": true, - "subjectLookup": "" + "subjectLookup": "", + "receiptApp": true }, "options": { "codeSigning": true, @@ -28,4 +29,4 @@ "logoUrl": "", "supportPhone": "", "supportEmail": "" -} +} \ No newline at end of file diff --git a/lib/c3-amazon-connect-stack.ts b/lib/c3-amazon-connect-stack.ts index 4a1187e..d7b46a0 100644 --- a/lib/c3-amazon-connect-stack.ts +++ b/lib/c3-amazon-connect-stack.ts @@ -33,6 +33,7 @@ import { validateOptionsContext, } from './models'; import { writeFileToExports } from './helpers/file'; +import { ReceiptApp } from './features/receipt-app'; export class C3AmazonConnectStack extends Stack { private c3BaseUrl: string; @@ -142,11 +143,25 @@ export class C3AmazonConnectStack extends Stack { this.featuresContext.agentAssistedIVR || this.featuresContext.agentAssistedLink ) { - const appUrl = this.getAppUrl( + const paymentRequestAppUrl = this.getPaymentRequestAppUrl( !this.amazonConnectContext.addAppsToWorkspace, ); if (this.amazonConnectContext.addAppsToWorkspace) { - this.create3rdPartyApp(appUrl); + this.createPaymentRequestApp(paymentRequestAppUrl); + } + + // Create resources needed for agent-assisted receipt app. + if (this.featuresContext.receiptApp) { + new ReceiptApp( + this, + this.stackLabel, + this.amazonConnectContext, + this.sendReceiptFunction, + this.agentAssistedIVRResources?.sendAgentMessageFunction, + this.agentAssistedIVRResources?.hoursOfOperation, + this.agentAssistedIVRResources?.iamRole?.roleArn, + this.c3AppUrlFragment, + ); } } } @@ -473,8 +488,8 @@ export class C3AmazonConnectStack extends Stack { * This app is required in order for an agent to initiate a payment while on a call with a customer. Once created, it will show as * an app in the agent workspace. NOTE: You will also have to enable this app to viewed on the security profile for your agents. */ - private create3rdPartyApp(appUrl: string): void { - console.log('Creating 3rd party application...'); + private createPaymentRequestApp(appUrl: string): void { + console.log('Creating payment request application...'); // Create the app. const stackLabelTitleCase = @@ -482,7 +497,7 @@ export class C3AmazonConnectStack extends Stack { const appLabel = this.stackLabel ? ` - ${stackLabelTitleCase}` : ''; const application = new CfnApplication( this, - `C3ConnectApp${stackLabelTitleCase}`, + `C3ConnectPaymentRequestApp${stackLabelTitleCase}`, { name: 'Payment Request' + appLabel, // App name is unfortunately required to be unique to create. namespace: `c3-payment-${this.stackLabel}`, @@ -497,12 +512,24 @@ export class C3AmazonConnectStack extends Stack { }, ); + // Workaround to delete the existing associations. Necessary when the naming format changes. + const skipAssociations = + this.node.tryGetContext('options').skipAssociations; + if (skipAssociations) { + console.log('โš ๏ธ Skipping Amazon Connect associations! โš ๏ธ'); + return; + } + // Associate the app with the Amazon Connect instance. - new CfnIntegrationAssociation(this, `C3ConnectIntegrationApp`, { - instanceId: this.amazonConnectContext.instanceArn, - integrationType: 'APPLICATION', - integrationArn: application.attrApplicationArn, - }); + new CfnIntegrationAssociation( + this, + `C3ConnectPaymentRequestIntegrationApp`, + { + instanceId: this.amazonConnectContext.instanceArn, + integrationType: 'APPLICATION', + integrationArn: application.attrApplicationArn, + }, + ); } /** @@ -511,7 +538,7 @@ export class C3AmazonConnectStack extends Stack { * @param customEmbed Whether to use a custom embed URL for the app. * @returns The URL for the app. */ - private getAppUrl(customEmbed: boolean): string { + private getPaymentRequestAppUrl(customEmbed: boolean): string { const instanceId = this.amazonConnectContext.instanceArn.split('/')[1]; // Set params for IVR features. @@ -537,10 +564,10 @@ export class C3AmazonConnectStack extends Stack { configuredFeatureParams += '&customEmbed=true'; } - const appUrl = `https://${this.c3Context.vendorId}.${this.c3AppUrlFragment}/agent-workspace?contactCenter=amazon&instanceId=${instanceId}®ion=${region}${agentAssistedIVRParams}${configuredFeatureParams}`; + const appUrl = `https://${this.c3Context.vendorId}.${this.c3AppUrlFragment}/agent-workspace/payment-request?contactCenter=amazon&instanceId=${instanceId}®ion=${region}${agentAssistedIVRParams}${configuredFeatureParams}`; writeFileToExports( - 'C3WorkspaceAppUrl.txt', - `๐ŸŒ Your C3 Payment Request app URL is:\n\n${appUrl}\n`, + 'C3PaymentRequestAppUrl.txt', + `๐Ÿ’ฐ Your C3 Payment Request app URL is:\n\n๐ŸŒ ${appUrl}\n`, ); return appUrl; } diff --git a/lib/connect/content-transformations.ts b/lib/connect/content-transformations.ts index 6fe9731..08c8e1e 100644 --- a/lib/connect/content-transformations.ts +++ b/lib/connect/content-transformations.ts @@ -2,6 +2,7 @@ import { Function } from 'aws-cdk-lib/aws-lambda'; import * as flowModuleJson from './flows/modules/c3-payment-ivr-flow-module.json'; import * as agentAssistedPaymentIVRFlowJson from './flows/c3-agent-assisted-payment-ivr-flow.json'; import * as subjectLookupFlow from './flows/c3-subject-lookup-flow.json'; +import * as receiptFlow from './flows/c3-receipt-flow.json'; import { IvrSpeakingContext } from '../models'; /** @@ -73,7 +74,7 @@ export function getPaymentIVRFlowModuleContent( } transformedContent = transformedContent.replace( /<>/g, - queueId, + queueId ?? '', ); transformedContent = transformedContent.replace( @@ -186,3 +187,28 @@ export function getSubjectLookupFlowContent( ); return transformedContent; } + +/** + * Gets the content for the receipt flow. + * + * @param sendReceiptLambdaArn The Lambda function that sends a receipt. + * @param sendAgentMessageFunction The Lambda function that sends messages to the agent. + * @returns A string representing the content for the receipt flow. + */ +export function getReceiptFlowContent( + sendReceiptLambdaFunction: Function, + sendAgentMessageFunction: Function, +): string { + let transformedContent = JSON.stringify(receiptFlow); + + // Replace the placeholders with the actual values. + transformedContent = transformedContent.replace( + /<>/g, + sendReceiptLambdaFunction.functionArn, + ); + transformedContent = transformedContent.replace( + /<>/g, + sendAgentMessageFunction.functionArn, + ); + return transformedContent; +} diff --git a/lib/connect/flows/c3-receipt-flow.json b/lib/connect/flows/c3-receipt-flow.json new file mode 100644 index 0000000..08c275c --- /dev/null +++ b/lib/connect/flows/c3-receipt-flow.json @@ -0,0 +1,471 @@ +{ + "Version": "2019-10-30", + "StartAction": "f50d211b-96c7-43f0-9f4f-2204e1301fad", + "Metadata": { + "entryPointPosition": { + "x": -868, + "y": -75.2 + }, + "ActionMetadata": { + "Report Transactions Found": { + "position": { + "x": -260, + "y": -80.8 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Report No Transactions Error": { + "position": { + "x": -259.2, + "y": 128.8 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "No Transactions": { + "position": { + "x": -37.6, + "y": 119.2 + }, + "isFriendlyName": true + }, + "13e17aab-f89b-4dc8-8040-4b8e2e4555df": { + "position": { + "x": 937.6, + "y": 180 + } + }, + "Check for Email Address": { + "position": { + "x": -36, + "y": -83.2 + }, + "isFriendlyName": true, + "conditions": [], + "conditionMetadata": [ + { + "id": "7c231476-858b-4909-b603-85f88b6cd074", + "operator": { + "name": "Contains", + "value": "Contains", + "shortDisplay": "contains" + }, + "value": "@" + } + ] + }, + "No Email Address": { + "position": { + "x": 416.8, + "y": 27.2 + }, + "isFriendlyName": true + }, + "Report No Email Address Error": { + "position": { + "x": 193.6, + "y": 28.8 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Check for Transactions": { + "position": { + "x": -492, + "y": -83.2 + }, + "isFriendlyName": true, + "conditions": [], + "conditionMetadata": [ + { + "id": "aa288c83-76ec-4cfe-a5cd-b06e70578a93", + "operator": { + "name": "Contains", + "value": "Contains", + "shortDisplay": "contains" + }, + "value": "\"" + } + ] + }, + "Conference All": { + "position": { + "x": -724.8, + "y": -94.4 + }, + "isFriendlyName": true + }, + "f50d211b-96c7-43f0-9f4f-2204e1301fad": { + "position": { + "x": -870.4, + "y": 105.6 + } + }, + "Report Receipt Error": { + "position": { + "x": 631.2, + "y": -84 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Report Receipts Sent": { + "position": { + "x": 632, + "y": -267.2 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Report Sending Receipts": { + "position": { + "x": 178.4, + "y": -218.4 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Send Receipts": { + "position": { + "x": 400.8, + "y": -221.6 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "SendAll": false + } + } + }, + "Annotations": [], + "name": "C3 Receipt Flow (Working Copy)", + "description": "Flow to send payment receipts in the agent workspace.", + "type": "queueTransfer", + "status": "PUBLISHED", + "hash": {} + }, + "Actions": [ + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "TransactionsFound" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Report Transactions Found", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "Check for Email Address", + "Errors": [ + { + "NextAction": "Check for Email Address", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "NoTransactionsError" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Report No Transactions Error", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "No Transactions", + "Errors": [ + { + "NextAction": "No Transactions", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\nThere are no completed transactions for this customer. Please check that the customer has made a payment on this same call.\n\n" + }, + "Identifier": "No Transactions", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "13e17aab-f89b-4dc8-8040-4b8e2e4555df", + "Errors": [ + { + "NextAction": "13e17aab-f89b-4dc8-8040-4b8e2e4555df", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": {}, + "Identifier": "13e17aab-f89b-4dc8-8040-4b8e2e4555df", + "Type": "DisconnectParticipant", + "Transitions": {} + }, + { + "Parameters": { + "ComparisonValue": "$.Attributes.Email" + }, + "Identifier": "Check for Email Address", + "Type": "Compare", + "Transitions": { + "NextAction": "Report No Email Address Error", + "Conditions": [ + { + "NextAction": "Report Sending Receipts", + "Condition": { + "Operator": "TextContains", + "Operands": ["@"] + } + } + ], + "Errors": [ + { + "NextAction": "Report No Email Address Error", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "Text": "\n>\" rate=\"<>\">\nThere is no email address for this customer. Please provide one in the C3 Receipt app and try again.\n\n" + }, + "Identifier": "No Email Address", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "13e17aab-f89b-4dc8-8040-4b8e2e4555df", + "Errors": [ + { + "NextAction": "13e17aab-f89b-4dc8-8040-4b8e2e4555df", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "NoEmailAddressError" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Report No Email Address Error", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "No Email Address", + "Errors": [ + { + "NextAction": "No Email Address", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "ComparisonValue": "$.Attributes.TransactionIds" + }, + "Identifier": "Check for Transactions", + "Type": "Compare", + "Transitions": { + "NextAction": "Report No Transactions Error", + "Conditions": [ + { + "NextAction": "Report Transactions Found", + "Condition": { + "Operator": "TextContains", + "Operands": ["\""] + } + } + ], + "Errors": [ + { + "NextAction": "Report No Transactions Error", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "PreviousContactParticipantState": "OffHold" + }, + "Identifier": "Conference All", + "Type": "UpdatePreviousContactParticipantState", + "Transitions": { + "NextAction": "Check for Transactions", + "Errors": [ + { + "NextAction": "Check for Transactions", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "FlowLoggingBehavior": "Enabled" + }, + "Identifier": "f50d211b-96c7-43f0-9f4f-2204e1301fad", + "Type": "UpdateFlowLoggingBehavior", + "Transitions": { + "NextAction": "Conference All" + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "SendReceiptError" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Report Receipt Error", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "13e17aab-f89b-4dc8-8040-4b8e2e4555df", + "Errors": [ + { + "NextAction": "13e17aab-f89b-4dc8-8040-4b8e2e4555df", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "ReceiptsSent" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Report Receipts Sent", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "13e17aab-f89b-4dc8-8040-4b8e2e4555df", + "Errors": [ + { + "NextAction": "13e17aab-f89b-4dc8-8040-4b8e2e4555df", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "SendingReceipts" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Report Sending Receipts", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "Send Receipts", + "Errors": [ + { + "NextAction": "Send Receipts", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "SendAll": "true" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Send Receipts", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "Report Receipts Sent", + "Errors": [ + { + "NextAction": "Report Receipt Error", + "ErrorType": "NoMatchingError" + } + ] + } + } + ] +} diff --git a/lib/features/receipt-app.ts b/lib/features/receipt-app.ts new file mode 100644 index 0000000..69e4057 --- /dev/null +++ b/lib/features/receipt-app.ts @@ -0,0 +1,180 @@ +import { Stack } from 'aws-cdk-lib'; +import { + CfnContactFlow, + CfnHoursOfOperation, + CfnIntegrationAssociation, + CfnQueue, + CfnQuickConnect, +} from 'aws-cdk-lib/aws-connect'; +import { Function } from 'aws-cdk-lib/aws-lambda'; +import { getReceiptFlowContent } from '../connect/content-transformations'; +import { AmazonConnectContext, C3Context } from '../models'; +import { writeFileToExports } from '../helpers/file'; +import { CfnApplication } from 'aws-cdk-lib/aws-appintegrations'; + +/** + * Class for creating the necessary resources for the agent-assisted receipt app. + */ +export class ReceiptApp { + private receiptQueue: CfnQueue; + private receiptFlow: CfnContactFlow; + + /** + * Creates the necessary resources for the agent-assisted receipt app. + */ + constructor( + private stack: Stack, + private stackLabel: string, + private amazonConnectContext: AmazonConnectContext, + private sendReceiptFunction: Function, + private sendAgentMessageFunction: Function, + private hoursOfOperation: CfnHoursOfOperation, + private externalRoleArn: string, + private c3AppUrlFragment: string, + ) { + console.log('Creating resources for receipt app...'); + this.createReceiptQueue(); + this.createReceiptFlow(); + this.createReceiptQuickConnect(); + const appUrl = this.getReceiptAppUrl( + !this.amazonConnectContext.addAppsToWorkspace, + ); + if (this.amazonConnectContext.addAppsToWorkspace) { + this.createReceiptApp(appUrl); + } + } + + /** + * Creates the queue for the receipt quick connect. + * + * This queue is required so that an agent can send a receipt using a quick connect. + */ + private createReceiptQueue(): void { + console.log('Creating receipt quick connect queue...'); + this.receiptQueue = new CfnQueue(this.stack, 'C3ReceiptQueue', { + name: 'C3 Receipt Quick Connect Queue', + description: 'Queue for sending receipts in the C3 agent workspace.', + instanceArn: this.amazonConnectContext.instanceArn, + hoursOfOperationArn: this.hoursOfOperation.attrHoursOfOperationArn, + }); + } + + /** + * Creates a Amazon Connect flow for sending receipts. + * + * This flow is required to send receipts in the agent workspace. + */ + private createReceiptFlow(): void { + console.log('Creating flow C3ReceiptFlow...'); + const receiptFlowContent = getReceiptFlowContent( + this.sendReceiptFunction, + this.sendAgentMessageFunction, + ); + writeFileToExports('C3ReceiptFlow.json', receiptFlowContent); + this.receiptFlow = new CfnContactFlow(this.stack, 'C3ReceiptFlow', { + name: 'C3 Receipt', + description: 'Flow to send payment receipts in the agent workspace.', + content: receiptFlowContent, + instanceArn: this.amazonConnectContext.instanceArn, + type: 'QUEUE_TRANSFER', + }); + } + + /** + * Creates a quick connect to allow agents to send receipts. + * + * This quick connect is required to send receipts in the agent workspace. + */ + private createReceiptQuickConnect(): void { + console.log('Creating quick connect...'); + new CfnQuickConnect(this.stack, 'C3ReceiptQuickConnect', { + instanceArn: this.amazonConnectContext.instanceArn, + name: 'Receipt', + description: + 'Quick connect for sending receipts in the C3 agent workspace.', + quickConnectConfig: { + quickConnectType: 'QUEUE', + queueConfig: { + contactFlowArn: this.receiptFlow.attrContactFlowArn, + queueArn: this.receiptQueue.attrQueueArn, + }, + }, + }); + } + + /** + * Gets the URL to be used for the C3 Receipt app. + * + * @param customEmbed Whether to use a custom embed URL for the app. + * @returns The URL for the app. + */ + private getReceiptAppUrl(customEmbed: boolean): string { + const c3Context = this.stack.node.tryGetContext('c3') as C3Context; + const instanceId = this.amazonConnectContext.instanceArn.split('/')[1]; + const region = this.amazonConnectContext.instanceArn.split(':')[3]; + + // Add parameters to the URL for the specific features. + let configuredFeatureParams = ''; + if (customEmbed) { + configuredFeatureParams += '&customEmbed=true'; + } + + const appUrl = `https://${c3Context.vendorId}.${this.c3AppUrlFragment}/agent-workspace/receipt?contactCenter=amazon&instanceId=${instanceId}®ion=${region}&externalRoleArn=${this.externalRoleArn}${configuredFeatureParams}`; + writeFileToExports( + 'C3ReceiptAppUrl.txt', + `๐Ÿงพ Your C3 Receipt app URL is:\n\n๐ŸŒ ${appUrl}\n`, + ); + return appUrl; + } + + /** + * Creates a 3rd party application to be used for agent-assisted receipts and associates it with your Amazon Connect instance. + * + * @param appUrl The URL for the 3rd party application. + * This app is required in order for an agent to initiate a receipt while on a call with a customer. Once created, it will show as + * an app in the agent workspace. NOTE: You will also have to enable this app to viewed on the security profile for your agents. + */ + private createReceiptApp(appUrl: string): void { + console.log('Creating receipt application...'); + + // Create the app. + const stackLabelTitleCase = + this.stackLabel.charAt(0).toUpperCase() + this.stackLabel.slice(1); + const appLabel = this.stackLabel ? ` - ${stackLabelTitleCase}` : ''; + const application = new CfnApplication( + this.stack, + `C3ConnectReceiptApp${stackLabelTitleCase}`, + { + name: 'Receipt' + appLabel, // App name is unfortunately required to be unique to create. + namespace: `c3-receipt-${this.stackLabel}`, + description: 'Agent application for sending receipts with C3.', + permissions: ['User.Details.View', 'Contact.Details.View'], + applicationSourceConfig: { + externalUrlConfig: { + accessUrl: appUrl, + approvedOrigins: [], // Don't allow any other origins. + }, + }, + }, + ); + + // Workaround to delete the existing associations. Necessary when the naming format changes. + const skipAssociations = + this.stack.node.tryGetContext('options').skipAssociations; + if (skipAssociations) { + console.log('โš ๏ธ Skipping Amazon Connect associations! โš ๏ธ'); + return; + } + + // Associate the app with the Amazon Connect instance. + new CfnIntegrationAssociation( + this.stack, + `C3ConnectReceiptIntegrationApp`, + { + instanceId: this.amazonConnectContext.instanceArn, + integrationType: 'APPLICATION', + integrationArn: application.attrApplicationArn, + }, + ); + } +} diff --git a/lib/lambda/c3-send-receipt/index.js b/lib/lambda/c3-send-receipt/index.js index 9a00ffd..18bb619 100644 --- a/lib/lambda/c3-send-receipt/index.js +++ b/lib/lambda/c3-send-receipt/index.js @@ -7,12 +7,26 @@ export async function handler(event) { console.log(`EVENT: ${JSON.stringify(event)}`); // Get the contact attributes. - let contactAttributes = {}; - contactAttributes = event.Details.ContactData.Attributes; + const contactAttributes = event.Details.ContactData.Attributes; + const parameters = event.Details.Parameters; + const sendAll = parameters.SendAll === 'true'; + const emailAddress = contactAttributes.Email; - // Email the receipt. + // Send all the receipts, if sendAll is true. + if (sendAll) { + const transactionIds = JSON.parse(contactAttributes.TransactionIds); + for (const transactionId of transactionIds) { + try { + await sendReceiptEmail(transactionId, emailAddress); + } catch (error) { + console.error('Error sending receipt:', error); + } + } + return; + } + + // Otherwise, send the receipt for the current transaction. const transactionId = contactAttributes.TransactionId; - const emailAddress = contactAttributes.Email; await sendReceiptEmail(transactionId, emailAddress); } diff --git a/lib/models/features-context.ts b/lib/models/features-context.ts index df4f028..887b811 100644 --- a/lib/models/features-context.ts +++ b/lib/models/features-context.ts @@ -5,6 +5,7 @@ export interface FeaturesContext { agentAssistedLink: boolean; selfServiceIVR: boolean; subjectLookup: SubjectLookupMode; + receiptApp: boolean; } /** @@ -30,5 +31,12 @@ export function validateFeaturesContext( throw new Error( 'features.subjectLookup requires features.agentAssistedIVR or features.agentAssistedLink to be enabled.', ); + } else if ( + featuresContext.receiptApp && + !(featuresContext.agentAssistedIVR || featuresContext.agentAssistedLink) + ) { + throw new Error( + 'features.receiptApp requires features.agentAssistedIVR or features.agentAssistedLink to be enabled.', + ); } } diff --git a/package.json b/package.json index 2dbc6d3..9f8aa08 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "cdk": "cdk", "synth": "bash ./scripts/synth.sh", "deploy": "bash ./scripts/deploy.sh", - "display-url": "echo \"$(<./exports/C3WorkspaceAppUrl.txt )\"", + "display-urls": "echo \"$(<./exports/C3PaymentRequestAppUrl.txt )\" && echo \"\n\" && echo \"$(<./exports/C3ReceiptAppUrl.txt )\"", "insert-placeholders": "npm run style:fix && bash ./scripts/insert-placeholders.sh", "compress-files": "bash ./scripts/compress-files.sh", "postinstall": "npm --prefix ./lib/lambda/c3-utils-layer/lib/nodejs ci && npm --prefix ./lib/lambda/c3-create-payment-request ci && npm --prefix ./lib/lambda/c3-validate-entry ci && npm --prefix ./lib/lambda/c3-send-receipt ci && npm --prefix ./lib/lambda/c3-submit-payment ci && npm --prefix ./lib/lambda/c3-tokenize-transaction ci && npm --prefix ./lib/lambda/c3-subject-lookup ci && npm --prefix ./lib/lambda/c3-send-agent-message ci", diff --git a/scripts/deploy.sh b/scripts/deploy.sh index c12e79f..6a7f7a0 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -27,5 +27,5 @@ done # Run the CDK deploy command with the profile (if provided) cdk deploy $AWS_PROFILE -# Display the URL of the deployed application -npm run display-url +# Display the URLs of the deployed applications +npm run display-urls diff --git a/scripts/insert-placeholders.sh b/scripts/insert-placeholders.sh index bc19a27..2133b80 100755 --- a/scripts/insert-placeholders.sh +++ b/scripts/insert-placeholders.sh @@ -4,8 +4,9 @@ # they can be used in different environments. AGENT_ASSISTED_PAYMENT_IVR_FLOW_FILE="lib/connect/flows/c3-agent-assisted-payment-ivr-flow.json" -SUBJECT_LOOKUP_FLOW_FILE="lib/connect/flows/c3-subject-lookup-flow.json" PAYMENT_IVR_FLOW_MODULE_FILE="lib/connect/flows/modules/c3-payment-ivr-flow-module.json" +SUBJECT_LOOKUP_FLOW_FILE="lib/connect/flows/c3-subject-lookup-flow.json" +RECEIPT_FLOW_FILE="lib/connect/flows/c3-receipt-flow.json" # ---- LAMBDA FUNCTIONS ---- @@ -38,6 +39,7 @@ FUNCTION_NAME="C3SendAgentMessage" PLACEHOLDER="<>" sed -i '' "s|\(\"[^\"]*\": \)\".*${FUNCTION_NAME}.*\"|\1\"$PLACEHOLDER\"|g" "$AGENT_ASSISTED_PAYMENT_IVR_FLOW_FILE" sed -i '' "s|\(\"[^\"]*\": \)\".*${FUNCTION_NAME}.*\"|\1\"$PLACEHOLDER\"|g" "$SUBJECT_LOOKUP_FLOW_FILE" +sed -i '' "s|\(\"[^\"]*\": \)\".*${FUNCTION_NAME}.*\"|\1\"$PLACEHOLDER\"|g" "$RECEIPT_FLOW_FILE" # Replace the ARN of the C3SubjectLookup Lambda function FUNCTION_NAME="C3SubjectLookup" @@ -50,6 +52,11 @@ PLACEHOLDER="<>" sed -i '' "s|\(\"[^\"]*\": \)\".*${FUNCTION_NAME}.*\"|\1\"$PLACEHOLDER\"|g" "$AGENT_ASSISTED_PAYMENT_IVR_FLOW_FILE" sed -i '' "s|\(\"[^\"]*\": \)\".*${FUNCTION_NAME}.*\"|\1\"$PLACEHOLDER\"|g" "$PAYMENT_IVR_FLOW_MODULE_FILE" +# Replace the ARN of the C3SendReceipt Lambda function +FUNCTION_NAME="C3SendReceipt" +PLACEHOLDER="<>" +sed -i '' "s|\(\"[^\"]*\": \)\".*${FUNCTION_NAME}.*\"|\1\"$PLACEHOLDER\"|g" "$RECEIPT_FLOW_FILE" + # ---- SECURITY KEY ---- # Replace the security key ID @@ -73,6 +80,7 @@ PROSODY_TAG='' REPLACEMENT='>\\" rate=\\"<>\\">' sed -i '' "s|$PROSODY_TAG|$REPLACEMENT|g" "$AGENT_ASSISTED_PAYMENT_IVR_FLOW_FILE" sed -i '' "s|$PROSODY_TAG|$REPLACEMENT|g" "$PAYMENT_IVR_FLOW_MODULE_FILE" +sed -i '' "s|$PROSODY_TAG|$REPLACEMENT|g" "$RECEIPT_FLOW_FILE" # ---- RECEIPT QUEUE ID ---- diff --git a/scripts/synth.sh b/scripts/synth.sh index 00ffd4f..8a36792 100755 --- a/scripts/synth.sh +++ b/scripts/synth.sh @@ -27,5 +27,5 @@ done # Run the CDK synth command with the profile (if provided) cdk synth $AWS_PROFILE -# Display the URL of the application -npm run display-url +# Display the URLs of the applications +npm run display-urls From b8f636f22e20b8b247a1786f86a95f1ae93fd4b6 Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 23:28:52 -0600 Subject: [PATCH 12/17] docs: add description for receipt app parameter --- docs/GETTING-STARTED.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/GETTING-STARTED.md b/docs/GETTING-STARTED.md index e065458..06b93d3 100644 --- a/docs/GETTING-STARTED.md +++ b/docs/GETTING-STARTED.md @@ -74,6 +74,7 @@ In order to facilitate this process, you will need to provide some values to the | `agentAssistedLink` | **Currently unsupported**. This feature will be coming soon. | | `selfServiceIVR` | Determines whether or not to deploy resources necessary to support a self-service payment IVR. Defaults to `true`. If set to `false`, some resources will not be deployed.

For more information, see the [self-service payment IVR](./features/SELF_SERVICE_PAYMENT_IVR.md) documentation. | | `subjectLookup` | **Optional**. Additional feature for agent-assisted IVR payments. If set, this will allow the agent to pull details about the subject to pre-fill information in the payment request (contact name, contact email, and amount due). Valid options are `"required-fixed"`, `"required-editable"`, and `"optional-editable"`. Leave blank if you don't want to support subject lookup.

For more information, see the [subject lookup](./features/SUBJECT_LOOKUP.md) documentation. | +| `receiptApp` | Determines whether or not to deploy resources to allow agents to send a receipt. Defaults to `true`. If set to `false`, some resources will not be deployed, and agents will not be able to send a receipt to a customer if the email was not already provided. | ##### Options From 8b2c0340be9bd342267ce3dfc6acbf60529c2a5c Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 23:29:26 -0600 Subject: [PATCH 13/17] docs(salesforce): add steps for creating the receipt app --- docs/features/SALESFORCE_INTEGRATION.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/docs/features/SALESFORCE_INTEGRATION.md b/docs/features/SALESFORCE_INTEGRATION.md index 1b52544..73796ac 100644 --- a/docs/features/SALESFORCE_INTEGRATION.md +++ b/docs/features/SALESFORCE_INTEGRATION.md @@ -19,13 +19,13 @@ C3 for Amazon connect can be used within Salesforce to provide agents with a sea When you deployed resources to your AWS account through this project, a unique URL was generated for your agent workspace. After running `npm run synth` or `npm run deploy`, you will see this URL output in the console. It will look something like: ```bash -๐ŸŒ Your C3 Payment Request app URL is: +๐Ÿ’ฐ Your C3 Payment Request app URL is: -https://some-vendor.call2action.link/agent-workspace?contactCenter=amazon&instanceId=some-guid®ion=some-region&externalRoleArn=${Token[TOKEN.261]}&subjectLookup=required-editable&customEmbed=true +๐ŸŒhttps://some-vendor.call2action.link/agent-workspace/payment-request?contactCenter=amazon&instanceId=some-guid®ion=some-region&externalRoleArn=${Token[TOKEN.261]}&subjectLookup=required-editable&customEmbed=true ``` > [!TIP] -> You can also find this URL at any time by looking at the `exports/C3WorkspaceAppUrl.txt` file. +> You can also find this URL at any time by looking at the `exports/C3PaymentRequestAppUrl.txt` file. Replace the `${Token[TOKEN.261]}` value with the ARN of the IAM role that was created when you deployed the stack. Look in IAM for a role named "AmazonConnectExternalRole", copy the ARN, and replace the placeholder in the URL. @@ -73,6 +73,21 @@ Optionally, you can repeat the same steps on the "Mobile Navigation" tab to add Your app page is now ready for use! Verify that your agents can see the new app page in their navigation items. +### Create Receipt App + +If you enabled the receipt app feature, you will need to create a second Visualforce page and app page for the receipt app. Follow the same steps as above, but use the receipt app URL instead of the payment request app URL. + +```bash +๐Ÿงพ Your C3 Receipt app URL is: + +๐ŸŒhttps://some-vendor.call2action.link/agent-workspace/receipt?contactCenter=amazon&instanceId=some-guid®ion=some-region&externalRoleArn=${Token[TOKEN.261]}&customEmbed=true +``` + +> [!TIP] +> You can also find this URL at any time by looking at the `exports/C3ReceiptAppUrl.txt` file. + +Replace the `${Token[TOKEN.261]}` value with the ARN of the IAM role that was created when you deployed the stack. Look in IAM for a role named "AmazonConnectExternalRole", copy the ARN, and replace the placeholder in the URL. + ### Configure Amazon Connect Integration This step will vary depending on how you have Amazon Connect integrated with Salesforce. Please follow the appropriate guide below: From 576249efc2f89043d3cd776d5ec19354b8706f5d Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 23:35:21 -0600 Subject: [PATCH 14/17] chore: bump version number --- bin/c3-amazon-connect.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/c3-amazon-connect.ts b/bin/c3-amazon-connect.ts index 31e33c3..19fb01e 100644 --- a/bin/c3-amazon-connect.ts +++ b/bin/c3-amazon-connect.ts @@ -32,7 +32,7 @@ async function getMostRecentGitTag(): Promise { return stdout.trim(); } catch (error) { console.error('Error fetching the most recent git tag:', error); - return 'v2.2.0'; + return 'v3.0.0'; } } From d814acadc993cfe33bf53a5c25fc2eb38b7fe415 Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 23:35:31 -0600 Subject: [PATCH 15/17] style: fix formatting --- cdk.context.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdk.context.json b/cdk.context.json index e6486d4..edf7ff5 100644 --- a/cdk.context.json +++ b/cdk.context.json @@ -29,4 +29,4 @@ "logoUrl": "", "supportPhone": "", "supportEmail": "" -} \ No newline at end of file +} From a05302ae243cfc8d208f35c08fd44915b16899e4 Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 23:39:54 -0600 Subject: [PATCH 16/17] refactor: remove working copy text from receipt flow --- lib/connect/flows/c3-receipt-flow.json | 2 +- scripts/insert-placeholders.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/connect/flows/c3-receipt-flow.json b/lib/connect/flows/c3-receipt-flow.json index 08c275c..786eb7b 100644 --- a/lib/connect/flows/c3-receipt-flow.json +++ b/lib/connect/flows/c3-receipt-flow.json @@ -185,7 +185,7 @@ } }, "Annotations": [], - "name": "C3 Receipt Flow (Working Copy)", + "name": "C3 Receipt Flow", "description": "Flow to send payment receipts in the agent workspace.", "type": "queueTransfer", "status": "PUBLISHED", diff --git a/scripts/insert-placeholders.sh b/scripts/insert-placeholders.sh index 2133b80..0e75272 100755 --- a/scripts/insert-placeholders.sh +++ b/scripts/insert-placeholders.sh @@ -95,5 +95,6 @@ sed -i '' "s|$QUEUE_ID_PREFIX|$PLACEHOLDER|g" "$PAYMENT_IVR_FLOW_MODULE_FILE" sed -i '' "s| (Working Copy)||g" "$AGENT_ASSISTED_PAYMENT_IVR_FLOW_FILE" sed -i '' "s| (Working Copy)||g" "$PAYMENT_IVR_FLOW_MODULE_FILE" sed -i '' "s| (Working Copy)||g" "$SUBJECT_LOOKUP_FLOW_FILE" +sed -i '' "s| (Working Copy)||g" "$RECEIPT_FLOW_FILE" echo "โœ… Placeholders inserted!" From 80de411a4501735392ac89afa89116f8e94c0e8b Mon Sep 17 00:00:00 2001 From: Tyler Hendrickson <6372535+hendrickson-tyler@users.noreply.github.com> Date: Sun, 25 Aug 2024 23:43:09 -0600 Subject: [PATCH 17/17] refactor: replace speaking options in receipt flow --- lib/connect/content-transformations.ts | 11 +++++++++++ lib/features/receipt-app.ts | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/connect/content-transformations.ts b/lib/connect/content-transformations.ts index 08c8e1e..9b29d3a 100644 --- a/lib/connect/content-transformations.ts +++ b/lib/connect/content-transformations.ts @@ -193,11 +193,13 @@ export function getSubjectLookupFlowContent( * * @param sendReceiptLambdaArn The Lambda function that sends a receipt. * @param sendAgentMessageFunction The Lambda function that sends messages to the agent. + * @param ivrSpeakingContext The speaking context for the IVR. * @returns A string representing the content for the receipt flow. */ export function getReceiptFlowContent( sendReceiptLambdaFunction: Function, sendAgentMessageFunction: Function, + ivrSpeakingContext: IvrSpeakingContext, ): string { let transformedContent = JSON.stringify(receiptFlow); @@ -210,5 +212,14 @@ export function getReceiptFlowContent( /<>/g, sendAgentMessageFunction.functionArn, ); + + transformedContent = transformedContent.replace( + /<>/g, + ivrSpeakingContext.rate, + ); + transformedContent = transformedContent.replace( + /<>/g, + ivrSpeakingContext.volume, + ); return transformedContent; } diff --git a/lib/features/receipt-app.ts b/lib/features/receipt-app.ts index 69e4057..746a969 100644 --- a/lib/features/receipt-app.ts +++ b/lib/features/receipt-app.ts @@ -8,7 +8,7 @@ import { } from 'aws-cdk-lib/aws-connect'; import { Function } from 'aws-cdk-lib/aws-lambda'; import { getReceiptFlowContent } from '../connect/content-transformations'; -import { AmazonConnectContext, C3Context } from '../models'; +import { AmazonConnectContext, C3Context, OptionsContext } from '../models'; import { writeFileToExports } from '../helpers/file'; import { CfnApplication } from 'aws-cdk-lib/aws-appintegrations'; @@ -66,9 +66,13 @@ export class ReceiptApp { */ private createReceiptFlow(): void { console.log('Creating flow C3ReceiptFlow...'); + const optionsContext = this.stack.node.tryGetContext( + 'options', + ) as OptionsContext; const receiptFlowContent = getReceiptFlowContent( this.sendReceiptFunction, this.sendAgentMessageFunction, + optionsContext.ivrSpeaking, ); writeFileToExports('C3ReceiptFlow.json', receiptFlowContent); this.receiptFlow = new CfnContactFlow(this.stack, 'C3ReceiptFlow', {