diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3b7b3ba7..987ff6a2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -15,6 +15,10 @@ updates: cdk: patterns: - 'aws-cdk*' + ignore: + # Ignore all Node types major updates to keep in sync with local version + - dependency-name: '@types/node' + update-types: ['version-update:semver-major'] # GitHub Actions - package-ecosystem: 'github-actions' diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 80cd9aca..ae9c4262 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -35,7 +35,8 @@ jobs: "amazonConnect": { "instanceArn": "placeholder", "securityKeyId": "placeholder", - "securityKeyCertificateContent": "-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n" + "securityKeyCertificateContent": "-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n", + "workspaceApp": true }, "c3": { "env": "dev", @@ -48,6 +49,9 @@ jobs: "selfServiceIVR": true, "subjectLookup": "required-editable" }, + "options": { + "codeSigning": true + }, "logoUrl": "placeholder", "supportPhone": "placeholder", "supportEmail": "placeholder" diff --git a/.gitignore b/.gitignore index 025aa97f..c2a6d17f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ !jest.config.js !release.config.js !lib/lambda/**/*.js +lib/lambda/subject-lookup-policy.js *.d.ts node_modules .context-values.json @@ -11,3 +12,4 @@ exports # CDK asset staging directory .cdk.staging cdk.out +lib/lambda/subject-lookup-policy.js diff --git a/.husky/pre-commit b/.husky/pre-commit index 6c7571c6..876d7309 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - npm run style:check diff --git a/bin/c3-amazon-connect.ts b/bin/c3-amazon-connect.ts index d8d4801f..b94df47d 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 'v1.2.1'; + return 'v1.3.0'; } } diff --git a/cdk.context.json b/cdk.context.json index b69d94b2..17932a10 100644 --- a/cdk.context.json +++ b/cdk.context.json @@ -3,7 +3,8 @@ "amazonConnect": { "instanceArn": "", "securityKeyId": "", - "securityKeyCertificateContent": "" + "securityKeyCertificateContent": "", + "workspaceApp": true }, "c3": { "env": "prod", @@ -16,6 +17,9 @@ "selfServiceIVR": true, "subjectLookup": "" }, + "options": { + "codeSigning": true + }, "logoUrl": "", "supportPhone": "", "supportEmail": "" diff --git a/docs/ALTERNATIVE_IMPORT.md b/docs/ALTERNATIVE_IMPORT.md index dc9f3585..34065c8d 100644 --- a/docs/ALTERNATIVE_IMPORT.md +++ b/docs/ALTERNATIVE_IMPORT.md @@ -7,8 +7,11 @@ If you are unable to use the standard `npm run deploy` process using the CDK, yo It might be necessary to use the alternative import method in the following instances: - Your user lacks the Amazon Elastic Container Registry (ECR) permissions required for the CDK to deploy. -- Your AWS account was set up through [Salesforce Service Cloud Voice](https://trailhead.salesforce.com/content/learn/modules/service-cloud-voice/service-voice-learn). - - This prevents even your _root_ user from having ECR permissions. +- Your AWS account was set up through [Salesforce Service Cloud Voice](https://trailhead.salesforce.com/content/learn/modules/service-cloud-voice/service-voice-learn) (specifically the _SVC with Amazon Connect_ SKU). + - 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. ## Process diff --git a/docs/GETTING-STARTED.md b/docs/GETTING-STARTED.md index d429f31a..774382aa 100644 --- a/docs/GETTING-STARTED.md +++ b/docs/GETTING-STARTED.md @@ -48,11 +48,12 @@ In order to facilitate this process, you will need to provide some values to the ##### Amazon Connect -| Value | Description | -| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `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`. | +| Value | Description | +| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `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. | ##### C3 @@ -71,6 +72,12 @@ In order to facilitate this process, you will need to provide some values to the | `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. | +##### Options + +| Value | Description | +| ------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `codeSigning` | Whether to support code signing for Lambda resources. This is recommended for security purposes, but may be disabled if necessary. | + ##### Other | Value | Description | @@ -145,7 +152,7 @@ C3 for Amazon Connect can also be used within Salesforce to facilitate payments. With the resources deployed and configured, you can now begin using the C3 Amazon Connect resources to provide a more seamless experience for your agents and customers. -For more information on how to use the features, please reference the [agent user manual](https://stonly.com/guide/en/c3-for-amazon-connect-4aD1PSTbrN/Steps/3598750). +For more information on how to use the features, please reference the [agent user manual](https://customerdynamics.stonly.com/kb/guide/en/c3-for-amazon-connect-4aD1PSTbrN/Steps/3598750). ### Test Cards and Bank Accounts diff --git a/docs/features/SALESFORCE_INTEGRATION.md b/docs/features/SALESFORCE_INTEGRATION.md index df742587..1b525444 100644 --- a/docs/features/SALESFORCE_INTEGRATION.md +++ b/docs/features/SALESFORCE_INTEGRATION.md @@ -1,5 +1,12 @@ # Salesforce Integration +## Overview + +C3 for Amazon connect can be used within Salesforce to provide agents with a seamless experience when handling customer interactions. The configuration process depends on how you have Amazon Connect integrated with your Salesforce instance. There are two integrations that are supported by this project: + +1. **[Amazon Connect CTI Adapter](https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000EJH4yUAH)**: The Amazon Connect CTI Adapter allows for the Amazon Connect Contact Control Panel (CCP) to be embedded within Salesforce as the softphone for your agents. +2. **[Salesforce Service Cloud Voice](https://aws.amazon.com/partners/amazon-connect-and-salesforce/)**: This integration is a managed package that provides a pre-built integration between Salesforce and Amazon Connect. It allows you to use [Salesforce Omni-Channel](https://www.salesforce.com/service/digital-customer-engagement-platform/) with Amazon Connect as your voice provider using the omni-channel softphone interface. + ## Installation > [!NOTE] @@ -9,25 +16,18 @@ #### Find Your Workspace URL -When you deployed resources to your AWS account through this project, a unique URL was generated for your agent workspace. Steps to find this URL are as follows: - -1. Open the AWS Amazon Connect console -2. Select your instance in the list -3. Select "Third-party applications" in the left-hand menu -4. Select the application named "Payment Request" -5. Copy the value under "Access URL" +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: -It should be a long URL that looks something like this, if you are using the dev or staging C3 environments: +```bash +🌐 Your C3 Payment Request app URL is: -```url -https://some-vendor.{{c3Environment}}.c2a.link/agent-workspace?contactCenter=amazon&instanceId=some-guid®ion=some-region&externalRoleArn=arn:aws:iam::000000000000:role/C3AmazonConnectStack-C3AgentAssistedIVRRole00000000-000000000000&subjectLookup=required-editable +https://some-vendor.call2action.link/agent-workspace?contactCenter=amazon&instanceId=some-guid®ion=some-region&externalRoleArn=${Token[TOKEN.261]}&subjectLookup=required-editable&customEmbed=true ``` -If you are using the production C3 environment, the URL will look like this: +> [!TIP] +> You can also find this URL at any time by looking at the `exports/C3WorkspaceAppUrl.txt` file. -```url -https://some-vendor.call2action.link/agent-workspace?contactCenter=amazon&instanceId=some-guid®ion=some-region&externalRoleArn=arn:aws:iam::000000000000:role/C3AmazonConnectStack-C3AgentAssistedIVRRole00000000-000000000000&subjectLookup=required-editable -``` +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. #### Create Visualforce Page @@ -40,7 +40,7 @@ Replace the content of the _Visualforce Markup_ tab with the following code: ```html @@ -75,6 +75,10 @@ Your app page is now ready for use! Verify that your agents can see the new app ### Configure Amazon Connect Integration +This step will vary depending on how you have Amazon Connect integrated with Salesforce. Please follow the appropriate guide below: + +#### CTI Adapter Configuration + #### Install CTI Adapter In order to integrate Amazon Connect into your Salesforce Lightning instance, you will need to install the Amazon Connect CTI Adapter. This adapter will allow you to connect your Amazon Connect instance to Salesforce and provide your agents with the ability to make and receive calls with the CCP interface within Salesforce. @@ -84,7 +88,7 @@ For detailed instructions on how to install the CTI Adapter, please reference th > [!IMPORTANT] > Please follow the directions closely. The CTI Adapter requires a number of configuration steps to be completed in order to function properly. -#### Enable CCP Softphone +##### Enable CCP Softphone Navigate back to the App Manager in the Salesforce _Service Setup_ page. Find the app that your agents will be using. As before, examples could be the _Service Console_ or _Sales Console_ app. Scroll to the far right of the table, click the dropdown arrow, and select "Edit". @@ -92,7 +96,7 @@ Select the "Utility Items" tab and click the "Add Utility Item" button. Search f Verify that your agents can see the new softphone option in their utility items at the bottom of the screen. -#### Enable Attribute Display in the CCP Softphone +##### Enable Attribute Display in the CCP Softphone Because the "Payment Request" app cannot directly communicate with Amazon Connect when embedded in Salesforce, agents will need to pass some necessary information from Salesforce to the Payment Request app. To display this information to the agent in the CCP interface, you will need to modify the CTI adapter that you installed. @@ -102,7 +106,7 @@ At the bottom of the page, find the "Attributes" section and hit "New". Add a ne ![Screenshot of a dialogue screen in Salesforce named "New AC CTI Attribute". Properties are populated with values required for the integration.](../images/salesforce-new-attribute.png 'Contact ID CTI Attribute') -### Set the Contact ID Attribute in Amazon Connect Flow +#### Set the Contact ID Attribute in Amazon Connect Flow In your initial contact flow, you will need to set the `ContactId` contact attribute _before_ you transfer the call to a queue. This attribute will be used by the Salesforce CTI adapter to display the contact ID in the CCP interface. @@ -118,8 +122,18 @@ Within the _Set contact attributes_ block, configure the following settings: Save the changes to your block, then save and publish your contact flow. +#### Service Cloud Voice Configuration + +#### Install Service Cloud Voice + +Follow the steps in the [Service Cloud Voice guide](https://help.salesforce.com/s/articleView?id=sf.voice_setup_enable.htm&type=5) to get set up with Service Cloud Voice. This will provision an AWS account and Amazon Connect instance for you. + +#### Configure Omni-Channel + +Ensure that the _Payment IVR_ (and _Subject Lookup_) quick connects are displaying in the Salesforce Omni-Channel widget. + ## Test the Integration Test the entire integration by making a call to your Amazon Connect inbound number and attempting to collect a payment through the app. -For more information on how to use C3 for Amazon Connect, please refer to the [agent user manual](https://stonly.com/guide/en/c3-for-amazon-connect-4aD1PSTbrN/Steps/3598750). +For more information on how to use C3 for Amazon Connect, please refer to the [agent user manual](https://customerdynamics.stonly.com/kb/guide/en/c3-for-amazon-connect-4aD1PSTbrN/Steps/3598750). diff --git a/docs/features/SUBJECT_LOOKUP.md b/docs/features/SUBJECT_LOOKUP.md index 46bbd4b4..b43b39cf 100644 --- a/docs/features/SUBJECT_LOOKUP.md +++ b/docs/features/SUBJECT_LOOKUP.md @@ -23,15 +23,19 @@ Agent lookup is facilitated through the use of a _quick connect_, _transfer to q Because the subject lookup process is specific to your organization, you will need to provide your own code in the Lambda function that is deployed with the stack to handle the lookup process. This Lambda function is named `C3SubjectLookup` and you can find the code at `lib/lambda/c3-subject-lookup/index.js`. Please read the comments in the code to understand how to implement your own lookup process. -If you need to grant your Lambda function to access any of your other AWS resources, you can add them to the empty, commented-out policy in `lib/features/subject-lookup.ts`. Look for this comment: +If you need to grant your Lambda function access to any of your other AWS resources, you can add them to the empty policy in `lib/lambda/subject-lookup-policy.ts`: ```typescript -// Update this with any additional permissions that the function needs for your subject lookup. -// const subjectLookupPolicy = new PolicyStatement({ -// actions: [], -// resources: [], -// }); -// this.subjectLookupFunction.addToRolePolicy(subjectLookupPolicy); +export const policyStatements: PolicyStatementProps[] = [ + { + actions: [ + // Add any actions required for your subject lookup here. + ], + resources: [ + // Add any resources required for your subject lookup here. + ], + }, +]; ``` Once you have updated the Lambda function, you can deploy the stack again to update the Lambda function: diff --git a/lib/c3-amazon-connect-stack.ts b/lib/c3-amazon-connect-stack.ts index dde99192..890fccb7 100644 --- a/lib/c3-amazon-connect-stack.ts +++ b/lib/c3-amazon-connect-stack.ts @@ -20,10 +20,13 @@ import { C3Context, C3PaymentGateway, FeaturesContext, + OptionsContext, validateAmazonConnectContext, validateC3Context, validateFeaturesContext, + validateOptionsContext, } from './models'; +import { writeFileToExports } from './helpers/file'; export class C3AmazonConnectStack extends Stack { private c3BaseUrl: string; @@ -34,6 +37,7 @@ export class C3AmazonConnectStack extends Stack { private amazonConnectContext: AmazonConnectContext; private c3Context: C3Context; private featuresContext: FeaturesContext; + private optionsContext: OptionsContext; private logoUrl: string; private supportPhone: string; private supportEmail: string; @@ -55,7 +59,9 @@ export class C3AmazonConnectStack extends Stack { this.setC3BaseUrl(); // Create resources needed for all features. - this.createCodeSigningConfig(); + if (this.optionsContext.codeSigning) { + this.createCodeSigningConfig(); + } this.createC3ApiKeySecret(); // Create resources needed for IVR payments. @@ -122,7 +128,10 @@ export class C3AmazonConnectStack extends Stack { this.featuresContext.agentAssistedIVR || this.featuresContext.agentAssistedLink ) { - this.create3rdPartyApp(); + const appUrl = this.getAppUrl(!this.amazonConnectContext.workspaceApp); + if (this.amazonConnectContext.workspaceApp) { + this.create3rdPartyApp(appUrl); + } } } @@ -141,6 +150,9 @@ export class C3AmazonConnectStack extends Stack { this.featuresContext = this.node.tryGetContext('features'); validateFeaturesContext(this.featuresContext); + this.optionsContext = this.node.tryGetContext('options'); + validateOptionsContext(this.optionsContext); + this.logoUrl = this.node.tryGetContext('logoUrl'); this.supportPhone = this.node.tryGetContext('supportPhone'); this.supportEmail = this.node.tryGetContext('supportEmail'); @@ -259,7 +271,9 @@ export class C3AmazonConnectStack extends Stack { SUPPORT_PHONE: this.supportPhone, SUPPORT_EMAIL: this.supportEmail, }, - codeSigningConfig: this.codeSigningConfig, + codeSigningConfig: this.optionsContext.codeSigning + ? this.codeSigningConfig + : undefined, }, ); @@ -291,7 +305,9 @@ export class C3AmazonConnectStack extends Stack { C3_PAYMENT_GATEWAY: this.c3Context.paymentGateway, CONNECT_SECURITY_KEY_ID: this.amazonConnectContext.securityKeyId, }, - codeSigningConfig: this.codeSigningConfig, + codeSigningConfig: this.optionsContext.codeSigning + ? this.codeSigningConfig + : undefined, }, ); @@ -340,7 +356,9 @@ export class C3AmazonConnectStack extends Stack { C3_BASE_URL: this.c3BaseUrl, C3_API_KEY_SECRET_ID: this.c3ApiKeySecret.secretName, }, - codeSigningConfig: this.codeSigningConfig, + codeSigningConfig: this.optionsContext.codeSigning + ? this.codeSigningConfig + : undefined, }); // Create the policy for getting secret values. @@ -366,7 +384,9 @@ export class C3AmazonConnectStack extends Stack { C3_BASE_URL: this.c3BaseUrl, C3_API_KEY_SECRET_ID: this.c3ApiKeySecret.secretName, }, - codeSigningConfig: this.codeSigningConfig, + codeSigningConfig: this.optionsContext.codeSigning + ? this.codeSigningConfig + : undefined, }); // Create the policy for getting secret values. @@ -380,32 +400,12 @@ export class C3AmazonConnectStack extends Stack { /** * Creates a 3rd party application to be used for agent-assisted payments 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 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(): void { + private create3rdPartyApp(appUrl: string): void { console.log('Creating 3rd party application...'); - const instanceId = this.amazonConnectContext.instanceArn.split('/')[1]; - - // Set params for IVR features. - const region = this.amazonConnectContext.instanceArn.split(':')[3]; - const externalRoleArn = - this.agentAssistedIVRResources?.iamRole?.roleArn || ''; - const agentAssistedIVRParams = externalRoleArn - ? `&externalRoleArn=${externalRoleArn}` - : ''; - - // Add parameters to the URL for the specific features. - let configuredFeatureParams = ''; - if (!this.featuresContext.agentAssistedIVR) { - configuredFeatureParams += '&noIvr=true'; - } - if (!this.featuresContext.agentAssistedLink) { - configuredFeatureParams += '&noLink=true'; - } - if (this.featuresContext.subjectLookup) { - configuredFeatureParams += `&subjectLookup=${this.featuresContext.subjectLookup}`; - } // Create the app. const stackLabelTitleCase = @@ -421,7 +421,7 @@ export class C3AmazonConnectStack extends Stack { permissions: ['User.Details.View', 'Contact.Details.View'], applicationSourceConfig: { externalUrlConfig: { - accessUrl: `https://${this.c3Context.vendorId}.${this.c3AppUrlFragment}/agent-workspace?contactCenter=amazon&instanceId=${instanceId}®ion=${region}${agentAssistedIVRParams}${configuredFeatureParams}`, + accessUrl: appUrl, approvedOrigins: [], // Don't allow any other origins. }, }, @@ -435,4 +435,44 @@ export class C3AmazonConnectStack extends Stack { integrationArn: application.attrApplicationArn, }); } + + /** + * Gets the URL to be used for the C3 Payment Request app. + * + * @param customEmbed Whether to use a custom embed URL for the app. + * @returns The URL for the app. + */ + private getAppUrl(customEmbed: boolean): string { + const instanceId = this.amazonConnectContext.instanceArn.split('/')[1]; + + // Set params for IVR features. + const region = this.amazonConnectContext.instanceArn.split(':')[3]; + const externalRoleArn = + this.agentAssistedIVRResources?.iamRole?.roleArn || ''; + const agentAssistedIVRParams = externalRoleArn + ? `&externalRoleArn=${externalRoleArn}` + : ''; + + // Add parameters to the URL for the specific features. + let configuredFeatureParams = ''; + if (!this.featuresContext.agentAssistedIVR) { + configuredFeatureParams += '&noIvr=true'; + } + if (!this.featuresContext.agentAssistedLink) { + configuredFeatureParams += '&noLink=true'; + } + if (this.featuresContext.subjectLookup) { + configuredFeatureParams += `&subjectLookup=${this.featuresContext.subjectLookup}`; + } + if (customEmbed) { + configuredFeatureParams += '&customEmbed=true'; + } + + const appUrl = `https://${this.c3Context.vendorId}.${this.c3AppUrlFragment}/agent-workspace?contactCenter=amazon&instanceId=${instanceId}®ion=${region}${agentAssistedIVRParams}${configuredFeatureParams}`; + writeFileToExports( + 'C3WorkspaceAppUrl.txt', + `🌐 Your C3 Payment Request app URL is:\n\n${appUrl}\n`, + ); + return appUrl; + } } 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 98d3f9ff..8a8acc45 100644 --- a/lib/connect/flows/c3-agent-assisted-payment-ivr-flow.json +++ b/lib/connect/flows/c3-agent-assisted-payment-ivr-flow.json @@ -7,20 +7,6 @@ "y": 677.6 }, "ActionMetadata": { - "Try Expiration Date Again": { - "position": { - "x": 2589.6, - "y": 28 - }, - "isFriendlyName": true - }, - "Try Routing Number Again": { - "position": { - "x": 2540, - "y": 870.4 - }, - "isFriendlyName": true - }, "5a505241-be5a-4437-8d66-785eb1b0beca": { "position": { "x": 6692, @@ -50,7 +36,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "1a126608-3ade-4597-811d-b345c8cef5a0", + "id": "822d4f1e-ced0-4336-b603-ae6b7709ee7e", "operator": { "name": "Equals", "value": "Equals", @@ -69,7 +55,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "03c43e38-8c70-4d4b-8a8a-75edcb546fff", + "id": "b7eda77f-7301-4682-a299-564b836e874d", "operator": { "name": "Equals", "value": "Equals", @@ -79,13 +65,6 @@ } ] }, - "Expiration Date Timeout": { - "position": { - "x": 2492.8, - "y": -591.2 - }, - "isFriendlyName": true - }, "Routing Number Timeout": { "position": { "x": 2411.2, @@ -102,26 +81,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "859d9da5-79c7-47d4-90be-7cb938669bea", - "operator": { - "name": "Equals", - "value": "Equals", - "shortDisplay": "=" - }, - "value": "Timeout" - } - ] - }, - "Expiration Date Timeout Check": { - "position": { - "x": 2625.6, - "y": -388 - }, - "isFriendlyName": true, - "conditions": [], - "conditionMetadata": [ - { - "id": "6c13caca-7110-489d-bd20-022f893314d7", + "id": "91e62c7e-a5d1-42bc-8030-a5c6a44398d4", "operator": { "name": "Equals", "value": "Equals", @@ -131,39 +91,6 @@ } ] }, - "Get Expiration Date": { - "position": { - "x": 2526.4, - "y": -187.2 - }, - "isFriendlyName": true, - "conditionMetadata": [], - "countryCodePrefix": "+1" - }, - "Report Card Number Entered": { - "position": { - "x": 2044.8, - "y": -172 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": { - "EventText": false - } - }, - "Get Routing Number": { - "position": { - "x": 2500.8, - "y": 646.4 - }, - "isFriendlyName": true, - "conditionMetadata": [], - "countryCodePrefix": "+1" - }, "Report Account Number Entered": { "position": { "x": 2090.4, @@ -209,21 +136,6 @@ }, "dynamicParams": ["EncryptedAccountNumber"] }, - "Report Expiration Entered": { - "position": { - "x": 3006.4, - "y": -184.8 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": { - "EventText": false - } - }, "Store Expiration Date": { "position": { "x": 2786.4, @@ -239,21 +151,6 @@ }, "dynamicParams": ["ExpirationDate"] }, - "Report Routing Number Entered": { - "position": { - "x": 3012.8, - "y": 614.4 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": { - "EventText": false - } - }, "Store Routing Number": { "position": { "x": 2779.2, @@ -269,29 +166,6 @@ }, "dynamicParams": ["RoutingNumber"] }, - "Record Token": { - "position": { - "x": 3776.8, - "y": 387.2 - }, - "isFriendlyName": true, - "dynamicParams": [] - }, - "Report Payment Tokenized": { - "position": { - "x": 3997.6, - "y": 384 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": { - "EventText": false - } - }, "Payment Success": { "position": { "x": 4898.4, @@ -322,44 +196,48 @@ "EventText": false } }, - "Email Receipt": { + "Check for Customer Email": { "position": { - "x": 5361.6, + "x": 5120, "y": 472 }, "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" + "conditions": [], + "conditionMetadata": [ + { + "id": "0b87f91f-cb5a-4fde-aece-f78760d44a79", + "operator": { + "name": "Contains", + "value": "Contains", + "shortDisplay": "contains" + }, + "value": "@" } - }, - "dynamicMetadata": {} + ] }, - "Report Receipt Email Error": { + "Check for Entered Info": { "position": { - "x": 5592, - "y": 569.6 + "x": -2976.8, + "y": 659.2 }, "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" + "conditions": [], + "conditionMetadata": [ + { + "id": "03c47790-50f3-4972-a50f-ff7833d3a227", + "operator": { + "name": "Is greater than", + "value": "GreaterThan", + "shortDisplay": ">" + }, + "value": "0" } - }, - "dynamicMetadata": { - "EventText": false - } - }, - "90dc6a63-2ae9-4c5f-b65f-75348779d0c6": { - "position": { - "x": 6472.8, - "y": 689.6 - } + ] }, - "Report Card Number Encryption Error": { + "Report Customer Transferred": { "position": { - "x": 1846.4, - "y": 50.4 + "x": -1353.6, + "y": 561.6 }, "isFriendlyName": true, "parameters": { @@ -371,25 +249,16 @@ "EventText": false } }, - "Report Account Number Encryption Error": { + "773c7dfc-3423-47e4-bf80-be55b0cd1947": { "position": { - "x": 1996.8, - "y": 875.2 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": { - "EventText": false + "x": -3140.8, + "y": 964.8 } }, - "Report Expiration Date Error": { + "Report Bank Account Selected": { "position": { - "x": 2881.6, - "y": 34.4 + "x": 1376, + "y": 584 }, "isFriendlyName": true, "parameters": { @@ -401,10 +270,10 @@ "EventText": false } }, - "Report Routing Number Error": { + "Report Bank Account Selected Again": { "position": { - "x": 2796, - "y": 848 + "x": 285.6, + "y": -236.8 }, "isFriendlyName": true, "parameters": { @@ -416,10 +285,10 @@ "EventText": false } }, - "Internal Error": { + "Agent Hold Error": { "position": { - "x": 1321.6, - "y": 1040.8 + "x": -1571.2, + "y": 764.8 }, "isFriendlyName": true }, @@ -430,43 +299,45 @@ }, "isFriendlyName": true }, - "Check for Customer Email": { + "Email Receipt": { "position": { - "x": 5120, + "x": 5361.6, "y": 472 }, "isFriendlyName": true, - "conditions": [], - "conditionMetadata": [ - { - "id": "ec56e904-05df-4ded-b8d9-e4e09055707b", - "operator": { - "name": "Contains", - "value": "Contains", - "shortDisplay": "contains" - }, - "value": "@" + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" } - ] + }, + "dynamicMetadata": {} }, - "Receipt Error": { + "Report Receipt Email Error": { "position": { - "x": 5805.6, - "y": 572.8 + "x": 5592, + "y": 569.6 }, - "isFriendlyName": true + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } }, - "Returning To Agent": { + "Receipt Error": { "position": { - "x": 6256.8, - "y": 695.2 + "x": 5804, + "y": 572 }, "isFriendlyName": true }, - "Report Payment Request Error": { + "Report Credit Card Selected Again": { "position": { - "x": -2365.6, - "y": 807.2 + "x": 218.4, + "y": -461.6 }, "isFriendlyName": true, "parameters": { @@ -478,37 +349,33 @@ "EventText": false } }, - "Create Payment Request": { + "Payment Method Timeout": { "position": { - "x": -2580, - "y": 581.6 + "x": 424.8, + "y": 160.8 }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } - }, - "dynamicMetadata": {} + "isFriendlyName": true }, - "Check for Entered Info": { + "Set Payment Method to Bank": { "position": { - "x": -2976.8, - "y": 659.2 + "x": 1055.2, + "y": 572.8 }, "isFriendlyName": true, - "conditions": [], - "conditionMetadata": [ - { - "id": "cfc58e76-ada3-4504-8ef1-6c74e8f06d8b", - "operator": { - "name": "Is greater than", - "value": "GreaterThan", - "shortDisplay": ">" - }, - "value": "0" - } - ] + "dynamicParams": [] + }, + "90dc6a63-2ae9-4c5f-b65f-75348779d0c6": { + "position": { + "x": 6472.8, + "y": 689.6 + } + }, + "Payment Request Error": { + "position": { + "x": -2152.8, + "y": 809.6 + }, + "isFriendlyName": true }, "Report No Payment Info Error": { "position": { @@ -525,20 +392,11 @@ "EventText": false } }, - "Record Payment Request ID": { - "position": { - "x": -2352.8, - "y": 510.4 - }, - "isFriendlyName": true, - "dynamicParams": [] - }, - "Payment Request Error": { + "33d2c563-289f-4358-9500-fc1552cc9523": { "position": { - "x": -2152.8, - "y": 809.6 - }, - "isFriendlyName": true + "x": -1293.6, + "y": 957.6 + } }, "No Payment Information": { "position": { @@ -547,29 +405,55 @@ }, "isFriendlyName": true }, - "c584fdb0-1a54-4203-a33d-ae533419b8dc": { + "Report Card Number Encryption Error": { "position": { - "x": -1581.6, - "y": 556.8 + "x": 1846.4, + "y": 50.4 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false } }, - "33d2c563-289f-4358-9500-fc1552cc9523": { + "Report Account Number Encryption Error": { "position": { - "x": -1293.6, - "y": 957.6 + "x": 1996.8, + "y": 875.2 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false } }, - "Agent Hold Error": { + "Report Expiration Date Error": { "position": { - "x": -1570.4, - "y": 766.4 + "x": 2881.6, + "y": 34.4 }, - "isFriendlyName": true + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } }, - "Report Customer Transferred": { + "Report Routing Number Error": { "position": { - "x": -1353.6, - "y": 561.6 + "x": 2796, + "y": 848 }, "isFriendlyName": true, "parameters": { @@ -581,56 +465,117 @@ "EventText": false } }, - "773c7dfc-3423-47e4-bf80-be55b0cd1947": { + "Get & Encrypt Card Number": { "position": { - "x": -3140.8, - "y": 964.8 - } + "x": 1558.4, + "y": -177.6 + }, + "isFriendlyName": true, + "conditionMetadata": [], + "countryCodePrefix": "+1" }, - "Agent Placed On Hold": { + "Get & Encrypt Account Number": { "position": { - "x": -1126.4, - "y": 561.6 + "x": 1635.2, + "y": 629.6 }, - "isFriendlyName": true + "isFriendlyName": true, + "conditionMetadata": [], + "countryCodePrefix": "+1" }, - "Speak Amount": { + "Returning To Agent": { "position": { - "x": -812.8, - "y": 557.6 + "x": 6256.8, + "y": 695.2 }, "isFriendlyName": true }, - "Input Not Recognized": { + "Internal Error": { "position": { - "x": 667.2, - "y": 88.8 + "x": 1320, + "y": 1038.4 }, "isFriendlyName": true }, - "Payment Method Timeout": { + "Expiration Date Timeout": { "position": { - "x": 424.8, - "y": 160.8 + "x": 2492.8, + "y": -591.2 }, "isFriendlyName": true }, - "Get & Encrypt Card Number": { + "Expiration Date Timeout Check": { "position": { - "x": 1558.4, - "y": -177.6 + "x": 2625.6, + "y": -388 + }, + "isFriendlyName": true, + "conditions": [], + "conditionMetadata": [ + { + "id": "3299690a-97dd-48c2-84aa-123574189646", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "Timeout" + } + ] + }, + "Report Card Number Entered": { + "position": { + "x": 2044.8, + "y": -172 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": { + "EventText": false + } + }, + "Get Routing Number": { + "position": { + "x": 2500.8, + "y": 646.4 }, "isFriendlyName": true, "conditionMetadata": [], "countryCodePrefix": "+1" }, - "Set Payment Method to Card": { + "Try Routing Number Again": { + "position": { + "x": 2540, + "y": 870.4 + }, + "isFriendlyName": true + }, + "Input Not Recognized": { + "position": { + "x": 666.4, + "y": 87.2 + }, + "isFriendlyName": true + }, + "Get Expiration Date": { "position": { - "x": 1037.6, - "y": -178.4 + "x": 2525.6, + "y": -188.8 }, "isFriendlyName": true, - "dynamicParams": [] + "conditionMetadata": [], + "countryCodePrefix": "+1" + }, + "Try Expiration Date Again": { + "position": { + "x": 2589.6, + "y": 28 + }, + "isFriendlyName": true }, "Report Credit Card Selected": { "position": { @@ -647,27 +592,37 @@ "EventText": false } }, - "Get & Encrypt Account Number": { + "Set Payment Method to Card": { "position": { - "x": 1635.2, - "y": 629.6 + "x": 1079.2, + "y": -175.2 }, "isFriendlyName": true, - "conditionMetadata": [], - "countryCodePrefix": "+1" + "dynamicParams": [] }, - "Set Payment Method to Bank": { + "Create Payment Request": { "position": { - "x": 1055.2, - "y": 572.8 + "x": -2580, + "y": 581.6 }, "isFriendlyName": true, - "dynamicParams": [] + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": {} }, - "Report Bank Account Selected": { + "c584fdb0-1a54-4203-a33d-ae533419b8dc": { "position": { - "x": 1376, - "y": 584 + "x": -1581.6, + "y": 556.8 + } + }, + "Report Payment Request Error": { + "position": { + "x": -2365.6, + "y": 807.2 }, "isFriendlyName": true, "parameters": { @@ -679,120 +634,139 @@ "EventText": false } }, - "Use Payment Method Again Timeout": { + "Record Payment Request ID": { "position": { - "x": -345.6, - "y": -348.8 + "x": -2353.6, + "y": 508.8 }, - "isFriendlyName": true + "isFriendlyName": true, + "dynamicParams": [] }, - "Check for Payment Token": { + "Use Card Again?": { "position": { - "x": -332.8, - "y": 561.6 + "x": -129.6, + "y": -83.2 }, "isFriendlyName": true, - "conditions": [], "conditionMetadata": [ { - "id": "1a12f504-dfc7-4467-a56e-ce020f024740", - "operator": { - "name": "Starts with", - "value": "StartsWith", - "shortDisplay": "starts with" - }, - "value": "VC" - }, - { - "id": "7cda8288-48cd-4c22-8a25-bc96e94a75b4", - "operator": { - "name": "Starts with", - "value": "StartsWith", - "shortDisplay": "starts with" - }, - "value": "BC" + "id": "0e49b6dc-6616-419c-bccf-c0303130e51e", + "value": "1" }, { - "id": "281e94a1-4320-485f-bf94-5525d8f3f73e", - "operator": { - "name": "Starts with", - "value": "StartsWith", - "shortDisplay": "starts with" - }, - "value": "BS" + "id": "5b6aaba4-775c-4da9-a03a-fccfe2fbb13f", + "value": "2" } ] }, - "Ask for Payment Method": { + "Use Bank Account Again?": { "position": { - "x": 382.4, - "y": 500 + "x": -75.2, + "y": 223.2 }, "isFriendlyName": true, "conditionMetadata": [ { - "id": "60feb465-d85e-4f52-9d76-a2fa6f764a5e", + "id": "fd0a0c6b-7489-4ba8-a2fd-d6ee418813e2", "value": "1" }, { - "id": "aa4e28cc-b2a5-4992-aa17-757a7c6037fa", + "id": "c6a4ff59-e138-4308-bd37-43ebecd3cbc4", "value": "2" } ] }, - "Use Bank Account Again?": { + "Use Payment Method Again Timeout": { "position": { - "x": -75.2, - "y": 223.2 + "x": -345.6, + "y": -348.8 + }, + "isFriendlyName": true + }, + "Agent Placed On Hold": { + "position": { + "x": -1126.4, + "y": 561.6 + }, + "isFriendlyName": true + }, + "Speak Amount": { + "position": { + "x": -812.8, + "y": 557.6 + }, + "isFriendlyName": true + }, + "Ask for Payment Method": { + "position": { + "x": 382.4, + "y": 500 }, "isFriendlyName": true, "conditionMetadata": [ { - "id": "d901a937-fdb2-4bbe-8922-034711ff5528", + "id": "ef5a3c37-6f52-43ee-b4ce-579a2103d23a", "value": "1" }, { - "id": "c86b55c2-2e57-44f8-a447-f58d6abc799a", + "id": "121f223b-b879-4f3e-8a41-fac3e35208bb", "value": "2" } ] }, - "Report Bank Account Selected Again": { + "Check Last Payment Method": { "position": { - "x": 285.6, - "y": -236.8 + "x": -291.2, + "y": 556 }, "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" + "conditions": [], + "conditionMetadata": [ + { + "id": "a0d9f6d1-b41d-4ec0-9d64-ddcc3d2568be", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "Card" + }, + { + "id": "b992a024-856f-4b3d-895f-8d8bcb26950d", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "Bank" } + ] + }, + "Redact Sensitive Contact Attributes": { + "position": { + "x": 6037.6, + "y": 699.2 }, - "dynamicMetadata": { - "EventText": false - } + "isFriendlyName": true, + "dynamicParams": [] }, - "Use Credit Card Again?": { + "Submit Payment": { "position": { - "x": -129.6, - "y": -83.2 + "x": 4213.6, + "y": 384.8 }, "isFriendlyName": true, - "conditionMetadata": [ - { - "id": "ce1b4034-72d1-43b6-80cb-09ed68861ecd", - "value": "1" - }, - { - "id": "f3feefb8-34cf-4614-977d-b53cf7aa487f", - "value": "2" + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" } - ] + }, + "dynamicMetadata": {} }, - "Report Credit Card Selected Again": { + "Report Payment Submission Error": { "position": { - "x": 218.4, - "y": -461.6 + "x": 4446.4, + "y": 623.2 }, "isFriendlyName": true, "parameters": { @@ -804,23 +778,39 @@ "EventText": false } }, - "Submit Payment": { + "Payment Submission Error": { "position": { - "x": 4213.6, - "y": 384.8 + "x": 4686.4, + "y": 619.2 + }, + "isFriendlyName": true + }, + "Payment Validation Error": { + "position": { + "x": 4684.8, + "y": 881.6 + }, + "isFriendlyName": true + }, + "Report Payment Tokenized": { + "position": { + "x": 3997.6, + "y": 384 }, "isFriendlyName": true, "parameters": { "LambdaFunctionARN": { - "displayName": "<>" + "displayName": "<>" } }, - "dynamicMetadata": {} + "dynamicMetadata": { + "EventText": false + } }, - "Report Payment Submission Error": { + "Report Expiration Entered": { "position": { - "x": 4436, - "y": 663.2 + "x": 3006.4, + "y": -184.8 }, "isFriendlyName": true, "parameters": { @@ -832,18 +822,20 @@ "EventText": false } }, - "Tokenize Transaction": { + "Report Routing Number Entered": { "position": { - "x": 3539.2, - "y": 382.4 + "x": 3012.8, + "y": 614.4 }, "isFriendlyName": true, "parameters": { "LambdaFunctionARN": { - "displayName": "<>" + "displayName": "<>" } }, - "dynamicMetadata": {} + "dynamicMetadata": { + "EventText": false + } }, "Report Tokenization Error": { "position": { @@ -860,35 +852,79 @@ "EventText": false } }, - "Redact Sensitive Contact Attributes": { + "Record Token": { "position": { - "x": 6037.6, - "y": 699.2 + "x": 3776.8, + "y": 387.2 }, "isFriendlyName": true, "dynamicParams": [] }, - "Payment Submission Error": { + "Tokenize Transaction": { "position": { - "x": 4680, - "y": 677.6 + "x": 3304.8, + "y": 383.2 }, - "isFriendlyName": true + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": {} }, - "Payment Validation Error": { + "Check for Tokenize Error": { "position": { - "x": 4684.8, - "y": 881.6 + "x": 3547.2, + "y": 372.8 }, - "isFriendlyName": true + "isFriendlyName": true, + "conditionMetadata": [ + { + "id": "7e6ab979-2475-41c0-abcb-8e525308021a", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "NULL" + } + ] }, - "Remove Failed Payment Token": { + "Remove Failed Payment Token and Method": { "position": { "x": 4981.6, "y": 835.2 }, "isFriendlyName": true, "dynamicParams": [] + }, + "Speak Validation Error": { + "position": { + "x": 3784, + "y": 696 + }, + "isFriendlyName": true + }, + "Report Validation Error": { + "position": { + "x": 4028.8, + "y": 700.8 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + }, + "LambdaInvocationAttributes": { + "EventText": { + "useDynamic": true + } + } + }, + "dynamicMetadata": { + "EventText": true + } } }, "Annotations": [], @@ -899,17 +935,23 @@ "hash": {} }, "Actions": [ + { + "Parameters": {}, + "Identifier": "5a505241-be5a-4437-8d66-785eb1b0beca", + "Type": "DisconnectParticipant", + "Transitions": {} + }, { "Parameters": { - "Text": "There was a problem with your expiration date. Please try again." + "Text": "Are you still there?" }, - "Identifier": "Try Expiration Date Again", + "Identifier": "Card Number Timeout", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Get & Encrypt Card Number", "Errors": [ { - "NextAction": "Get Expiration Date", + "NextAction": "Get & Encrypt Card Number", "ErrorType": "NoMatchingError" } ] @@ -917,37 +959,81 @@ }, { "Parameters": { - "Text": "There was a problem with your routing number. Please try again." + "Text": "Are you still there?" }, - "Identifier": "Try Routing Number Again", + "Identifier": "Account Number Timeout", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Routing Number", + "NextAction": "Get & Encrypt Account Number", "Errors": [ { - "NextAction": "Get Routing Number", + "NextAction": "Get & Encrypt Account Number", "ErrorType": "NoMatchingError" } ] } }, { - "Parameters": {}, - "Identifier": "5a505241-be5a-4437-8d66-785eb1b0beca", - "Type": "DisconnectParticipant", - "Transitions": {} + "Parameters": { + "ComparisonValue": "$.StoredCustomerInput" + }, + "Identifier": "Account Number Timeout Check", + "Type": "Compare", + "Transitions": { + "NextAction": "Store Encrypted Account Number", + "Conditions": [ + { + "NextAction": "Account Number Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } + } + ], + "Errors": [ + { + "NextAction": "Store Encrypted Account Number", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "ComparisonValue": "$.StoredCustomerInput" + }, + "Identifier": "Card Number Timeout Check", + "Type": "Compare", + "Transitions": { + "NextAction": "Store Encrypted Card Number", + "Conditions": [ + { + "NextAction": "Card Number Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } + } + ], + "Errors": [ + { + "NextAction": "Store Encrypted Card Number", + "ErrorType": "NoMatchingCondition" + } + ] + } }, { "Parameters": { "Text": "Are you still there?" }, - "Identifier": "Card Number Timeout", + "Identifier": "Routing Number Timeout", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Get Routing Number", "Errors": [ { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Get Routing Number", "ErrorType": "NoMatchingError" } ] @@ -955,15 +1041,104 @@ }, { "Parameters": { - "Text": "Are you still there?" + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Account Number Timeout", - "Type": "MessageParticipant", + "Identifier": "Routing Number Timeout Check", + "Type": "Compare", + "Transitions": { + "NextAction": "Store Routing Number", + "Conditions": [ + { + "NextAction": "Routing Number Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } + } + ], + "Errors": [ + { + "NextAction": "Store Routing Number", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "AccountNumberEntered" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Report Account Number Entered", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "Get Routing Number", + "Errors": [ + { + "NextAction": "Get Routing Number", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "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": { + "Attributes": { + "EncryptedAccountNumber": "$.StoredCustomerInput" + }, + "TargetContact": "Current" + }, + "Identifier": "Store Encrypted Account Number", + "Type": "UpdateContactAttributes", + "Transitions": { + "NextAction": "Report Account Number Entered", + "Errors": [ + { + "NextAction": "Report Account Number Encryption Error", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Attributes": { + "ExpirationDate": "$.StoredCustomerInput" + }, + "TargetContact": "Current" + }, + "Identifier": "Store Expiration Date", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Get & Encrypt Account Number", + "NextAction": "Report Expiration Entered", "Errors": [ { - "NextAction": "Get & Encrypt Account Number", + "NextAction": "Report Expiration Date Error", "ErrorType": "NoMatchingError" } ] @@ -971,65 +1146,53 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "Attributes": { + "RoutingNumber": "$.StoredCustomerInput" + }, + "TargetContact": "Current" }, - "Identifier": "Account Number Timeout Check", - "Type": "Compare", + "Identifier": "Store Routing Number", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Store Encrypted Account Number", - "Conditions": [ - { - "NextAction": "Account Number Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - } - ], + "NextAction": "Report Routing Number Entered", "Errors": [ { - "NextAction": "Store Encrypted Account Number", - "ErrorType": "NoMatchingCondition" + "NextAction": "Report Routing Number Error", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "Text": "Your payment was processed successfully." }, - "Identifier": "Card Number Timeout Check", - "Type": "Compare", + "Identifier": "Payment Success", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Store Encrypted Card Number", - "Conditions": [ - { - "NextAction": "Card Number Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - } - ], + "NextAction": "Check for Customer Email", "Errors": [ { - "NextAction": "Store Encrypted Card Number", - "ErrorType": "NoMatchingCondition" + "NextAction": "Check for Customer Email", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "Text": "Are you still there?" + "Attributes": { + "TransactionId": "$.External.TransactionId" + }, + "TargetContact": "Current" }, - "Identifier": "Expiration Date Timeout", - "Type": "MessageParticipant", + "Identifier": "Record Transaction ID", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Report Payment Processed", "Errors": [ { - "NextAction": "Get Expiration Date", + "NextAction": "Report Payment Processed", "ErrorType": "NoMatchingError" } ] @@ -1037,15 +1200,22 @@ }, { "Parameters": { - "Text": "Are you still there?" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "PaymentProcessed" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Routing Number Timeout", - "Type": "MessageParticipant", + "Identifier": "Report Payment Processed", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Get Routing Number", + "NextAction": "Payment Success", "Errors": [ { - "NextAction": "Get Routing Number", + "NextAction": "Payment Success", "ErrorType": "NoMatchingError" } ] @@ -1053,24 +1223,24 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "ComparisonValue": "$.Attributes.Email" }, - "Identifier": "Routing Number Timeout Check", + "Identifier": "Check for Customer Email", "Type": "Compare", "Transitions": { - "NextAction": "Store Routing Number", + "NextAction": "Redact Sensitive Contact Attributes", "Conditions": [ { - "NextAction": "Routing Number Timeout", + "NextAction": "Email Receipt", "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] + "Operator": "TextContains", + "Operands": ["@"] } } ], "Errors": [ { - "NextAction": "Store Routing Number", + "NextAction": "Redact Sensitive Contact Attributes", "ErrorType": "NoMatchingCondition" } ] @@ -1078,74 +1248,47 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "ComparisonValue": "$.Attributes.PaymentAmount" }, - "Identifier": "Expiration Date Timeout Check", + "Identifier": "Check for Entered Info", "Type": "Compare", "Transitions": { - "NextAction": "Store Expiration Date", + "NextAction": "Report No Payment Info Error", "Conditions": [ { - "NextAction": "Expiration Date Timeout", + "NextAction": "Create Payment Request", "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] + "Operator": "NumberGreaterThan", + "Operands": ["0"] } } ], "Errors": [ { - "NextAction": "Store Expiration Date", + "NextAction": "Report No Payment Info Error", "ErrorType": "NoMatchingCondition" } ] } }, - { - "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "5", - "Text": "Please enter your card's expiration date, followed by the pound key when complete.", - "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": { "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "CardNumberEntered" + "EventText": "IVRStarted" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Card Number Entered", + "Identifier": "Report Customer Transferred", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Agent Placed On Hold", "Errors": [ { - "NextAction": "Get Expiration Date", + "NextAction": "Agent Placed On Hold", "ErrorType": "NoMatchingError" } ] @@ -1153,29 +1296,12 @@ }, { "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "10", - "Text": "Please enter your bank's routing number, followed by the pound key when complete.", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "9" - } - } + "FlowLoggingBehavior": "Disabled" }, - "Identifier": "Get Routing Number", - "Type": "GetParticipantInput", + "Identifier": "773c7dfc-3423-47e4-bf80-be55b0cd1947", + "Type": "UpdateFlowLoggingBehavior", "Transitions": { - "NextAction": "Routing Number Timeout Check", - "Errors": [ - { - "NextAction": "Try Routing Number Again", - "ErrorType": "NoMatchingError" - } - ] + "NextAction": "Check for Entered Info" } }, { @@ -1183,38 +1309,19 @@ "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "AccountNumberEntered" + "EventText": "BankAccountSelected" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Account Number Entered", + "Identifier": "Report Bank Account Selected", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Get Routing Number", - "Errors": [ - { - "NextAction": "Get Routing Number", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "Attributes": { - "EncryptedCardNumber": "$.StoredCustomerInput" - }, - "TargetContact": "Current" - }, - "Identifier": "Store Encrypted Card Number", - "Type": "UpdateContactAttributes", - "Transitions": { - "NextAction": "Report Card Number Entered", + "NextAction": "Get & Encrypt Account Number", "Errors": [ { - "NextAction": "Report Card Number Encryption Error", + "NextAction": "Get & Encrypt Account Number", "ErrorType": "NoMatchingError" } ] @@ -1222,18 +1329,22 @@ }, { "Parameters": { - "Attributes": { - "EncryptedAccountNumber": "$.StoredCustomerInput" + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "BankAccountSelected" }, - "TargetContact": "Current" + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Store Encrypted Account Number", - "Type": "UpdateContactAttributes", + "Identifier": "Report Bank Account Selected Again", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Report Account Number Entered", + "NextAction": "Submit Payment", "Errors": [ { - "NextAction": "Report Account Number Encryption Error", + "NextAction": "Submit Payment", "ErrorType": "NoMatchingError" } ] @@ -1241,22 +1352,15 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "ExpirationDateEntered" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "Text": "There was an error placing the agent on hold. Unable to request payment." }, - "Identifier": "Report Expiration Entered", - "Type": "InvokeLambdaFunction", + "Identifier": "Agent Hold Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Tokenize Transaction", + "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", "Errors": [ { - "NextAction": "Tokenize Transaction", + "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", "ErrorType": "NoMatchingError" } ] @@ -1264,18 +1368,15 @@ }, { "Parameters": { - "Attributes": { - "ExpirationDate": "$.StoredCustomerInput" - }, - "TargetContact": "Current" + "Text": "A receipt has been sent to your email address, $.Attributes.['Email']." }, - "Identifier": "Store Expiration Date", - "Type": "UpdateContactAttributes", + "Identifier": "Receipt Success", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Report Expiration Entered", + "NextAction": "Redact Sensitive Contact Attributes", "Errors": [ { - "NextAction": "Report Expiration Date Error", + "NextAction": "Redact Sensitive Contact Attributes", "ErrorType": "NoMatchingError" } ] @@ -1283,41 +1384,42 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "RoutingNumberEntered" - }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Routing Number Entered", + "Identifier": "Email Receipt", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Tokenize Transaction", + "NextAction": "Receipt Success", "Errors": [ { - "NextAction": "Tokenize Transaction", + "NextAction": "Report Receipt Email Error", "ErrorType": "NoMatchingError" } ] } }, { - "Parameters": { - "Attributes": { - "RoutingNumber": "$.StoredCustomerInput" + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "ReceiptEmailError" }, - "TargetContact": "Current" + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Store Routing Number", - "Type": "UpdateContactAttributes", + "Identifier": "Report Receipt Email Error", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Report Routing Number Entered", + "NextAction": "Receipt Error", "Errors": [ { - "NextAction": "Report Routing Number Error", + "NextAction": "Receipt Error", "ErrorType": "NoMatchingError" } ] @@ -1325,18 +1427,15 @@ }, { "Parameters": { - "Attributes": { - "PaymentToken": "$.External.PaymentToken" - }, - "TargetContact": "Current" + "Text": "There was an error sending the receipt to your email address, $.Attributes.['Email']. Please contact customer support to receive a receipt for this transaction." }, - "Identifier": "Record Token", - "Type": "UpdateContactAttributes", + "Identifier": "Receipt Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Report Payment Tokenized", + "NextAction": "Redact Sensitive Contact Attributes", "Errors": [ { - "NextAction": "Report Payment Tokenized", + "NextAction": "Redact Sensitive Contact Attributes", "ErrorType": "NoMatchingError" } ] @@ -1347,13 +1446,13 @@ "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "PaymentTokenized" + "EventText": "CreditCardSelected" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Payment Tokenized", + "Identifier": "Report Credit Card Selected Again", "Type": "InvokeLambdaFunction", "Transitions": { "NextAction": "Submit Payment", @@ -1367,15 +1466,15 @@ }, { "Parameters": { - "Text": "Your payment was processed successfully." + "Text": "Are you still there?" }, - "Identifier": "Payment Success", + "Identifier": "Payment Method Timeout", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Check for Customer Email", + "NextAction": "Ask for Payment Method", "Errors": [ { - "NextAction": "Check for Customer Email", + "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingError" } ] @@ -1384,17 +1483,17 @@ { "Parameters": { "Attributes": { - "TransactionId": "$.External.TransactionId" + "PaymentMethod": "Bank" }, "TargetContact": "Current" }, - "Identifier": "Record Transaction ID", + "Identifier": "Set Payment Method to Bank", "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Report Payment Processed", + "NextAction": "Report Bank Account Selected", "Errors": [ { - "NextAction": "Report Payment Processed", + "NextAction": "Report Bank Account Selected", "ErrorType": "NoMatchingError" } ] @@ -1402,22 +1501,15 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "PaymentProcessed" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "PreviousContactParticipantState": "OffHold" }, - "Identifier": "Report Payment Processed", - "Type": "InvokeLambdaFunction", + "Identifier": "90dc6a63-2ae9-4c5f-b65f-75348779d0c6", + "Type": "UpdatePreviousContactParticipantState", "Transitions": { - "NextAction": "Payment Success", + "NextAction": "5a505241-be5a-4437-8d66-785eb1b0beca", "Errors": [ { - "NextAction": "Payment Success", + "NextAction": "5a505241-be5a-4437-8d66-785eb1b0beca", "ErrorType": "NoMatchingError" } ] @@ -1425,19 +1517,15 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "ResponseValidation": { - "ResponseType": "JSON" - } + "Text": "There was an error creating the payment request." }, - "Identifier": "Email Receipt", - "Type": "InvokeLambdaFunction", + "Identifier": "Payment Request Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Receipt Success", + "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", "Errors": [ { - "NextAction": "Report Receipt Email Error", + "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", "ErrorType": "NoMatchingError" } ] @@ -1448,35 +1536,41 @@ "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "ReceiptEmailError" + "EventText": "NoPaymentInfoError" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Receipt Email Error", + "Identifier": "Report No Payment Info Error", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Receipt Error", + "NextAction": "No Payment Information", "Errors": [ { - "NextAction": "Receipt Error", + "NextAction": "No Payment Information", "ErrorType": "NoMatchingError" } ] } }, + { + "Parameters": {}, + "Identifier": "33d2c563-289f-4358-9500-fc1552cc9523", + "Type": "DisconnectParticipant", + "Transitions": {} + }, { "Parameters": { - "PreviousContactParticipantState": "OffHold" + "Text": "There's no payment information for this customer. Please fill out the information in the C3 Payment Request app and try again." }, - "Identifier": "90dc6a63-2ae9-4c5f-b65f-75348779d0c6", - "Type": "UpdatePreviousContactParticipantState", + "Identifier": "No Payment Information", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "5a505241-be5a-4437-8d66-785eb1b0beca", + "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", "Errors": [ { - "NextAction": "5a505241-be5a-4437-8d66-785eb1b0beca", + "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", "ErrorType": "NoMatchingError" } ] @@ -1576,31 +1670,30 @@ }, { "Parameters": { - "Text": "We're sorry, an error has occured that prevents us from collecting the payment." - }, - "Identifier": "Internal Error", - "Type": "MessageParticipant", - "Transitions": { - "NextAction": "Returning To Agent", - "Errors": [ - { - "NextAction": "Returning To Agent", - "ErrorType": "NoMatchingError" + "StoreInput": "True", + "InputTimeLimitSeconds": "10", + "Text": "Please enter your card number followed by the pound key when complete.", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" + }, + "InputValidation": { + "CustomValidation": { + "MaximumLength": "20" } - ] - } - }, - { - "Parameters": { - "Text": "A receipt has been sent to your email address at $.Attributes.['Email']." + }, + "InputEncryption": { + "EncryptionKeyId": "<>", + "Key": "<>" + } }, - "Identifier": "Receipt Success", - "Type": "MessageParticipant", + "Identifier": "Get & Encrypt Card Number", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Card Number Timeout Check", "Errors": [ { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -1608,40 +1701,30 @@ }, { "Parameters": { - "ComparisonValue": "$.Attributes.Email" - }, - "Identifier": "Check for Customer Email", - "Type": "Compare", - "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", - "Conditions": [ - { - "NextAction": "Email Receipt", - "Condition": { - "Operator": "TextContains", - "Operands": ["@"] - } - } - ], - "Errors": [ - { - "NextAction": "Redact Sensitive Contact Attributes", - "ErrorType": "NoMatchingCondition" + "StoreInput": "True", + "InputTimeLimitSeconds": "10", + "Text": "Please enter your bank account number followed by the pound key when complete.", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" + }, + "InputValidation": { + "CustomValidation": { + "MaximumLength": "20" } - ] - } - }, - { - "Parameters": { - "Text": "There was an error sending the receipt to your email address at $.Attributes.['Email']. Please contact customer support to receive a receipt for this transaction." + }, + "InputEncryption": { + "EncryptionKeyId": "<>", + "Key": "<>" + } }, - "Identifier": "Receipt Error", - "Type": "MessageParticipant", + "Identifier": "Get & Encrypt Account Number", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Account Number Timeout Check", "Errors": [ { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -1665,22 +1748,15 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "PaymentRequestError" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "Text": "We're sorry, an error has occurred that prevents us from collecting the payment." }, - "Identifier": "Report Payment Request Error", - "Type": "InvokeLambdaFunction", + "Identifier": "Internal Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Payment Request Error", + "NextAction": "Returning To Agent", "Errors": [ { - "NextAction": "Payment Request Error", + "NextAction": "Returning To Agent", "ErrorType": "NoMatchingError" } ] @@ -1688,19 +1764,15 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "ResponseValidation": { - "ResponseType": "JSON" - } + "Text": "Are you still there?" }, - "Identifier": "Create Payment Request", - "Type": "InvokeLambdaFunction", + "Identifier": "Expiration Date Timeout", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Record Payment Request ID", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "Report Payment Request Error", + "NextAction": "Get Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -1708,24 +1780,24 @@ }, { "Parameters": { - "ComparisonValue": "$.Attributes.PaymentAmount" + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Check for Entered Info", + "Identifier": "Expiration Date Timeout Check", "Type": "Compare", "Transitions": { - "NextAction": "Report No Payment Info Error", + "NextAction": "Store Expiration Date", "Conditions": [ { - "NextAction": "Create Payment Request", + "NextAction": "Expiration Date Timeout", "Condition": { - "Operator": "NumberGreaterThan", - "Operands": ["0"] + "Operator": "Equals", + "Operands": ["Timeout"] } } ], "Errors": [ { - "NextAction": "Report No Payment Info Error", + "NextAction": "Store Expiration Date", "ErrorType": "NoMatchingCondition" } ] @@ -1736,19 +1808,19 @@ "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "NoPaymentInfoError" + "EventText": "CardNumberEntered" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report No Payment Info Error", + "Identifier": "Report Card Number Entered", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "No Payment Information", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "No Payment Information", + "NextAction": "Get Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -1756,18 +1828,26 @@ }, { "Parameters": { - "Attributes": { - "PaymentRequestId": "$.External.PaymentRequestId" + "StoreInput": "True", + "InputTimeLimitSeconds": "10", + "Text": "Please enter your bank's routing number, followed by the pound key when complete.", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" }, - "TargetContact": "Current" - }, - "Identifier": "Record Payment Request ID", - "Type": "UpdateContactAttributes", + "InputValidation": { + "CustomValidation": { + "MaximumLength": "9" + } + } + }, + "Identifier": "Get Routing Number", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "c584fdb0-1a54-4203-a33d-ae533419b8dc", + "NextAction": "Routing Number Timeout Check", "Errors": [ { - "NextAction": "Report Payment Request Error", + "NextAction": "Try Routing Number Again", "ErrorType": "NoMatchingError" } ] @@ -1775,15 +1855,15 @@ }, { "Parameters": { - "Text": "There was an error creating the payment request." + "Text": "There was a problem with your routing number. Please check your entry and try again." }, - "Identifier": "Payment Request Error", + "Identifier": "Try Routing Number Again", "Type": "MessageParticipant", "Transitions": { - "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", + "NextAction": "Get Routing Number", "Errors": [ { - "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", + "NextAction": "Get Routing Number", "ErrorType": "NoMatchingError" } ] @@ -1791,15 +1871,15 @@ }, { "Parameters": { - "Text": "There's no payment information for this contact. Please fill out the information in the C3 Payment Request app and try again." + "Text": "Your entry was not recognized. Please try again." }, - "Identifier": "No Payment Information", + "Identifier": "Input Not Recognized", "Type": "MessageParticipant", "Transitions": { - "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", + "NextAction": "Ask for Payment Method", "Errors": [ { - "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", + "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingError" } ] @@ -1807,37 +1887,42 @@ }, { "Parameters": { - "PreviousContactParticipantState": "AgentOnHold" + "StoreInput": "True", + "InputTimeLimitSeconds": "5", + "Text": "Please enter your card's expiration date in the format month-month-year-year, followed by the pound key when complete.", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" + }, + "InputValidation": { + "CustomValidation": { + "MaximumLength": "4" + } + } }, - "Identifier": "c584fdb0-1a54-4203-a33d-ae533419b8dc", - "Type": "UpdatePreviousContactParticipantState", + "Identifier": "Get Expiration Date", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Report Customer Transferred", + "NextAction": "Expiration Date Timeout Check", "Errors": [ { - "NextAction": "Agent Hold Error", + "NextAction": "Try Expiration Date Again", "ErrorType": "NoMatchingError" } ] } }, - { - "Parameters": {}, - "Identifier": "33d2c563-289f-4358-9500-fc1552cc9523", - "Type": "DisconnectParticipant", - "Transitions": {} - }, { "Parameters": { - "Text": "There was an error placing the agent on hold. Unable to request payment." + "Text": "There was a problem with your expiration date. Please check your entry and try again." }, - "Identifier": "Agent Hold Error", + "Identifier": "Try Expiration Date Again", "Type": "MessageParticipant", "Transitions": { - "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "33d2c563-289f-4358-9500-fc1552cc9523", + "NextAction": "Get Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -1848,45 +1933,19 @@ "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "IVRStarted" + "EventText": "CreditCardSelected" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Customer Transferred", + "Identifier": "Report Credit Card Selected", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Agent Placed On Hold", - "Errors": [ - { - "NextAction": "Agent Placed On Hold", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "FlowLoggingBehavior": "Disabled" - }, - "Identifier": "773c7dfc-3423-47e4-bf80-be55b0cd1947", - "Type": "UpdateFlowLoggingBehavior", - "Transitions": { - "NextAction": "Check for Entered Info" - } - }, - { - "Parameters": { - "Text": "To ensure the security of your information, the agent has been temporarily placed on hold." - }, - "Identifier": "Agent Placed On Hold", - "Type": "MessageParticipant", - "Transitions": { - "NextAction": "Speak Amount", + "NextAction": "Get & Encrypt Card Number", "Errors": [ { - "NextAction": "Speak Amount", + "NextAction": "Get & Encrypt Card Number", "ErrorType": "NoMatchingError" } ] @@ -1894,15 +1953,18 @@ }, { "Parameters": { - "Text": "A payment has been requested for the amount of $$.Attributes.PaymentAmount." + "Attributes": { + "PaymentMethod": "Card" + }, + "TargetContact": "Current" }, - "Identifier": "Speak Amount", - "Type": "MessageParticipant", + "Identifier": "Set Payment Method to Card", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Check for Payment Token", + "NextAction": "Report Credit Card Selected", "Errors": [ { - "NextAction": "Check for Payment Token", + "NextAction": "Report Credit Card Selected", "ErrorType": "NoMatchingError" } ] @@ -1910,15 +1972,19 @@ }, { "Parameters": { - "Text": "Your input was not recognized. Please try again." + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Input Not Recognized", - "Type": "MessageParticipant", + "Identifier": "Create Payment Request", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Ask for Payment Method", + "NextAction": "Record Payment Request ID", "Errors": [ { - "NextAction": "Ask for Payment Method", + "NextAction": "Report Payment Request Error", "ErrorType": "NoMatchingError" } ] @@ -1926,15 +1992,15 @@ }, { "Parameters": { - "Text": "Are you still there?" + "PreviousContactParticipantState": "AgentOnHold" }, - "Identifier": "Payment Method Timeout", - "Type": "MessageParticipant", + "Identifier": "c584fdb0-1a54-4203-a33d-ae533419b8dc", + "Type": "UpdatePreviousContactParticipantState", "Transitions": { - "NextAction": "Ask for Payment Method", + "NextAction": "Report Customer Transferred", "Errors": [ { - "NextAction": "Ask for Payment Method", + "NextAction": "Agent Hold Error", "ErrorType": "NoMatchingError" } ] @@ -1942,30 +2008,22 @@ }, { "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "10", - "Text": "Please enter your card number followed by the pound key when complete.", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "20" - } + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "PaymentRequestError" }, - "InputEncryption": { - "EncryptionKeyId": "<>", - "Key": "<>" + "ResponseValidation": { + "ResponseType": "JSON" } }, - "Identifier": "Get & Encrypt Card Number", - "Type": "GetParticipantInput", + "Identifier": "Report Payment Request Error", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Card Number Timeout Check", + "NextAction": "Payment Request Error", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "Payment Request Error", "ErrorType": "NoMatchingError" } ] @@ -1974,17 +2032,17 @@ { "Parameters": { "Attributes": { - "PaymentMethod": "Card" + "PaymentRequestId": "$.External.PaymentRequestId" }, "TargetContact": "Current" }, - "Identifier": "Set Payment Method to Card", + "Identifier": "Record Payment Request ID", "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Report Credit Card Selected", + "NextAction": "c584fdb0-1a54-4203-a33d-ae533419b8dc", "Errors": [ { - "NextAction": "Report Credit Card Selected", + "NextAction": "Report Payment Request Error", "ErrorType": "NoMatchingError" } ] @@ -1992,22 +2050,41 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "CreditCardSelected" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "StoreInput": "False", + "InputTimeLimitSeconds": "5", + "Text": "You previously paid with a credit or debit card.\n\nIf you would like to use this card again for this payment, press 1.\nTo use a different payment method, press 2." }, - "Identifier": "Report Credit Card Selected", - "Type": "InvokeLambdaFunction", + "Identifier": "Use Card Again?", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Ask for Payment Method", + "Conditions": [ + { + "NextAction": "Report Credit Card Selected Again", + "Condition": { + "Operator": "Equals", + "Operands": ["1"] + } + }, + { + "NextAction": "Ask for Payment Method", + "Condition": { + "Operator": "Equals", + "Operands": ["2"] + } + } + ], "Errors": [ { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Use Payment Method Again Timeout", + "ErrorType": "InputTimeLimitExceeded" + }, + { + "NextAction": "Ask for Payment Method", + "ErrorType": "NoMatchingCondition" + }, + { + "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingError" } ] @@ -2015,49 +2092,41 @@ }, { "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "10", - "Text": "Please enter your bank account number followed by the pound key when complete.", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "20" - } - }, - "InputEncryption": { - "EncryptionKeyId": "<>", - "Key": "<>" - } + "StoreInput": "False", + "InputTimeLimitSeconds": "5", + "Text": "You previously paid with a bank account.\n\nIf you would like to use this account again for this payment, press 1.\nTo use a different payment method, press 2." }, - "Identifier": "Get & Encrypt Account Number", + "Identifier": "Use Bank Account Again?", "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Account Number Timeout Check", - "Errors": [ + "NextAction": "Ask for Payment Method", + "Conditions": [ { - "NextAction": "Internal Error", - "ErrorType": "NoMatchingError" + "NextAction": "Report Bank Account Selected Again", + "Condition": { + "Operator": "Equals", + "Operands": ["1"] + } + }, + { + "NextAction": "Ask for Payment Method", + "Condition": { + "Operator": "Equals", + "Operands": ["2"] + } } - ] - } - }, - { - "Parameters": { - "Attributes": { - "PaymentMethod": "Bank" - }, - "TargetContact": "Current" - }, - "Identifier": "Set Payment Method to Bank", - "Type": "UpdateContactAttributes", - "Transitions": { - "NextAction": "Report Bank Account Selected", + ], "Errors": [ { - "NextAction": "Report Bank Account Selected", + "NextAction": "Use Payment Method Again Timeout", + "ErrorType": "InputTimeLimitExceeded" + }, + { + "NextAction": "Ask for Payment Method", + "ErrorType": "NoMatchingCondition" + }, + { + "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingError" } ] @@ -2065,22 +2134,15 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "BankAccountSelected" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "Text": "Are you still there?" }, - "Identifier": "Report Bank Account Selected", - "Type": "InvokeLambdaFunction", + "Identifier": "Use Payment Method Again Timeout", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get & Encrypt Account Number", + "NextAction": "Check Last Payment Method", "Errors": [ { - "NextAction": "Get & Encrypt Account Number", + "NextAction": "Check Last Payment Method", "ErrorType": "NoMatchingError" } ] @@ -2088,15 +2150,15 @@ }, { "Parameters": { - "Text": "Are you still there?" + "Text": "To ensure the security of your information, the agent has been temporarily placed on hold." }, - "Identifier": "Use Payment Method Again Timeout", + "Identifier": "Agent Placed On Hold", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Check for Payment Token", + "NextAction": "Speak Amount", "Errors": [ { - "NextAction": "Check for Payment Token", + "NextAction": "Speak Amount", "ErrorType": "NoMatchingError" } ] @@ -2104,39 +2166,16 @@ }, { "Parameters": { - "ComparisonValue": "$.Attributes.PaymentToken" + "Text": "A payment has been requested for the amount of $$.Attributes.PaymentAmount." }, - "Identifier": "Check for Payment Token", - "Type": "Compare", + "Identifier": "Speak Amount", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Ask for Payment Method", - "Conditions": [ - { - "NextAction": "Use Credit Card Again?", - "Condition": { - "Operator": "TextStartsWith", - "Operands": ["VC"] - } - }, - { - "NextAction": "Use Bank Account Again?", - "Condition": { - "Operator": "TextStartsWith", - "Operands": ["BC"] - } - }, - { - "NextAction": "Use Bank Account Again?", - "Condition": { - "Operator": "TextStartsWith", - "Operands": ["BS"] - } - } - ], + "NextAction": "Check Last Payment Method", "Errors": [ { - "NextAction": "Ask for Payment Method", - "ErrorType": "NoMatchingCondition" + "NextAction": "Check Last Payment Method", + "ErrorType": "NoMatchingError" } ] } @@ -2145,7 +2184,7 @@ "Parameters": { "StoreInput": "False", "InputTimeLimitSeconds": "5", - "Text": "To pay with a credit card, press 1.\nTo pay directly with your bank account, press 2." + "Text": "To pay with a credit or debit card, press 1.\nTo pay directly with your bank account, press 2." }, "Identifier": "Ask for Payment Method", "Type": "GetParticipantInput", @@ -2185,41 +2224,72 @@ }, { "Parameters": { - "StoreInput": "False", - "InputTimeLimitSeconds": "5", - "Text": "You previously paid with a bank account.\n\nIf you would like to use this account again for this payment, press 1.\nTo use a different payment method, press 2." + "ComparisonValue": "$.Attributes.PaymentMethod" }, - "Identifier": "Use Bank Account Again?", - "Type": "GetParticipantInput", + "Identifier": "Check Last Payment Method", + "Type": "Compare", "Transitions": { "NextAction": "Ask for Payment Method", "Conditions": [ { - "NextAction": "Report Bank Account Selected Again", + "NextAction": "Use Card Again?", "Condition": { "Operator": "Equals", - "Operands": ["1"] + "Operands": ["Card"] } }, { - "NextAction": "Ask for Payment Method", + "NextAction": "Use Bank Account Again?", "Condition": { "Operator": "Equals", - "Operands": ["2"] + "Operands": ["Bank"] } } ], "Errors": [ - { - "NextAction": "Use Payment Method Again Timeout", - "ErrorType": "InputTimeLimitExceeded" - }, { "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingCondition" - }, + } + ] + } + }, + { + "Parameters": { + "Attributes": { + "EncryptedCardNumber": "REDACTED", + "ExpirationDate": "REDACTED", + "EncryptedAccountNumber": "REDACTED" + }, + "TargetContact": "Current" + }, + "Identifier": "Redact Sensitive Contact Attributes", + "Type": "UpdateContactAttributes", + "Transitions": { + "NextAction": "Returning To Agent", + "Errors": [ { - "NextAction": "Ask for Payment Method", + "NextAction": "Returning To Agent", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Submit Payment", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "Record Transaction ID", + "Errors": [ + { + "NextAction": "Report Payment Submission Error", "ErrorType": "NoMatchingError" } ] @@ -2230,19 +2300,19 @@ "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "BankAccountSelected" + "EventText": "PaymentSubmissionError" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Bank Account Selected Again", + "Identifier": "Report Payment Submission Error", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Submit Payment", + "NextAction": "Payment Submission Error", "Errors": [ { - "NextAction": "Submit Payment", + "NextAction": "Payment Submission Error", "ErrorType": "NoMatchingError" } ] @@ -2250,41 +2320,15 @@ }, { "Parameters": { - "StoreInput": "False", - "InputTimeLimitSeconds": "5", - "Text": "You previously paid with a credit card.\n\nIf you would like to use this card again for this payment, press 1.\nTo use a different payment method, press 2." + "Text": "We're sorry, an error has occured preventing us from submitting your payment. You have not been charged." }, - "Identifier": "Use Credit Card Again?", - "Type": "GetParticipantInput", + "Identifier": "Payment Submission Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Ask for Payment Method", - "Conditions": [ - { - "NextAction": "Report Credit Card Selected Again", - "Condition": { - "Operator": "Equals", - "Operands": ["1"] - } - }, - { - "NextAction": "Ask for Payment Method", - "Condition": { - "Operator": "Equals", - "Operands": ["2"] - } - } - ], + "NextAction": "Remove Failed Payment Token and Method", "Errors": [ { - "NextAction": "Use Payment Method Again Timeout", - "ErrorType": "InputTimeLimitExceeded" - }, - { - "NextAction": "Ask for Payment Method", - "ErrorType": "NoMatchingCondition" - }, - { - "NextAction": "Ask for Payment Method", + "NextAction": "Remove Failed Payment Token and Method", "ErrorType": "NoMatchingError" } ] @@ -2292,22 +2336,15 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "LambdaInvocationAttributes": { - "EventText": "CreditCardSelected" - }, - "ResponseValidation": { - "ResponseType": "JSON" - } + "Text": "There was a problem validating your $.Attributes.PaymentMethod information." }, - "Identifier": "Report Credit Card Selected Again", - "Type": "InvokeLambdaFunction", + "Identifier": "Payment Validation Error", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Submit Payment", + "NextAction": "Remove Failed Payment Token and Method", "Errors": [ { - "NextAction": "Submit Payment", + "NextAction": "Remove Failed Payment Token and Method", "ErrorType": "NoMatchingError" } ] @@ -2315,19 +2352,22 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "PaymentTokenized" + }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Submit Payment", + "Identifier": "Report Payment Tokenized", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Record Transaction ID", + "NextAction": "Submit Payment", "Errors": [ { - "NextAction": "Report Payment Submission Error", + "NextAction": "Submit Payment", "ErrorType": "NoMatchingError" } ] @@ -2338,19 +2378,19 @@ "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", "LambdaInvocationAttributes": { - "EventText": "PaymentSubmissionError" + "EventText": "ExpirationDateEntered" }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Report Payment Submission Error", + "Identifier": "Report Expiration Entered", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Payment Submission Error", + "NextAction": "Tokenize Transaction", "Errors": [ { - "NextAction": "Payment Submission Error", + "NextAction": "Tokenize Transaction", "ErrorType": "NoMatchingError" } ] @@ -2358,19 +2398,22 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", + "LambdaFunctionARN": "<>", "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "RoutingNumberEntered" + }, "ResponseValidation": { "ResponseType": "JSON" } }, - "Identifier": "Tokenize Transaction", + "Identifier": "Report Routing Number Entered", "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Record Token", + "NextAction": "Tokenize Transaction", "Errors": [ { - "NextAction": "Report Tokenization Error", + "NextAction": "Tokenize Transaction", "ErrorType": "NoMatchingError" } ] @@ -2402,19 +2445,17 @@ { "Parameters": { "Attributes": { - "EncryptedCardNumber": "REDACTED", - "ExpirationDate": "REDACTED", - "EncryptedAccountNumber": "REDACTED" + "PaymentToken": "$.External.PaymentToken" }, "TargetContact": "Current" }, - "Identifier": "Redact Sensitive Contact Attributes", + "Identifier": "Record Token", "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Returning To Agent", + "NextAction": "Report Payment Tokenized", "Errors": [ { - "NextAction": "Returning To Agent", + "NextAction": "Report Payment Tokenized", "ErrorType": "NoMatchingError" } ] @@ -2422,15 +2463,19 @@ }, { "Parameters": { - "Text": "We're sorry, an error has occured preventing us from submitting your payment. You have not been charged." + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "ResponseValidation": { + "ResponseType": "JSON" + } }, - "Identifier": "Payment Submission Error", - "Type": "MessageParticipant", + "Identifier": "Tokenize Transaction", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Remove Failed Payment Token", + "NextAction": "Check for Tokenize Error", "Errors": [ { - "NextAction": "Remove Failed Payment Token", + "NextAction": "Report Tokenization Error", "ErrorType": "NoMatchingError" } ] @@ -2438,16 +2483,25 @@ }, { "Parameters": { - "Text": "There was a problem validating your $.Attributes.PaymentMethod information." + "ComparisonValue": "$.External.Error" }, - "Identifier": "Payment Validation Error", - "Type": "MessageParticipant", + "Identifier": "Check for Tokenize Error", + "Type": "Compare", "Transitions": { - "NextAction": "Remove Failed Payment Token", + "NextAction": "Speak Validation Error", + "Conditions": [ + { + "NextAction": "Record Token", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], "Errors": [ { - "NextAction": "Remove Failed Payment Token", - "ErrorType": "NoMatchingError" + "NextAction": "Speak Validation Error", + "ErrorType": "NoMatchingCondition" } ] } @@ -2455,11 +2509,12 @@ { "Parameters": { "Attributes": { - "PaymentToken": " " + "PaymentToken": "NULL", + "PaymentMethod": "NULL" }, "TargetContact": "Current" }, - "Identifier": "Remove Failed Payment Token", + "Identifier": "Remove Failed Payment Token and Method", "Type": "UpdateContactAttributes", "Transitions": { "NextAction": "Redact Sensitive Contact Attributes", @@ -2470,6 +2525,45 @@ } ] } + }, + { + "Parameters": { + "Text": "The payment failed because of the following error:\n\n$.External.Error" + }, + "Identifier": "Speak Validation Error", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Report Validation Error", + "Errors": [ + { + "NextAction": "Report Validation Error", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "LambdaInvocationAttributes": { + "EventText": "$.External.Error" + }, + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Report Validation Error", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "Remove Failed Payment Token and Method", + "Errors": [ + { + "NextAction": "Remove Failed Payment Token and Method", + "ErrorType": "NoMatchingError" + } + ] + } } ] } diff --git a/lib/connect/flows/c3-subject-lookup-flow.json b/lib/connect/flows/c3-subject-lookup-flow.json index 0d0385bb..4d2b7bf8 100644 --- a/lib/connect/flows/c3-subject-lookup-flow.json +++ b/lib/connect/flows/c3-subject-lookup-flow.json @@ -100,7 +100,7 @@ "name": "C3 Subject Lookup Flow", "description": "Flow to look up subject information in the agent workspace.", "type": "queueTransfer", - "status": "published", + "status": "PUBLISHED", "hash": {} }, "Actions": [ 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 1fc9315f..4f0e4716 100644 --- a/lib/connect/flows/modules/c3-payment-ivr-flow-module.json +++ b/lib/connect/flows/modules/c3-payment-ivr-flow-module.json @@ -7,133 +7,108 @@ "y": 229.6 }, "ActionMetadata": { - "Try Routing Number Again": { - "position": { - "x": 3880.8, - "y": 355.2 - }, - "isFriendlyName": true - }, - "Account Number Timeout": { + "Payment Success": { "position": { - "x": 2944, - "y": -92.8 + "x": 6239.2, + "y": -44.8 }, "isFriendlyName": true }, - "Account Number Timeout Check": { + "Record Transaction ID": { "position": { - "x": 3188.8, - "y": -72.8 + "x": 5782.4, + "y": -149.6 }, "isFriendlyName": true, - "conditions": [], - "conditionMetadata": [ - { - "id": "4c1c023a-67ed-47cf-a7db-97d4628997e1", - "operator": { - "name": "Equals", - "value": "Equals", - "shortDisplay": "=" - }, - "value": "Timeout" - } - ] + "dynamicParams": [] }, - "Routing Number Timeout": { + "Amount Choice Timeout": { "position": { - "x": 3752, - "y": -92 + "x": -682.4, + "y": -324.8 }, "isFriendlyName": true }, - "Get Routing Number": { + "Speak Minimum Payment": { "position": { - "x": 3841.6, - "y": 131.2 + "x": -170.4, + "y": -35.2 }, - "isFriendlyName": true, - "conditionMetadata": [], - "countryCodePrefix": "+1" + "isFriendlyName": true }, - "Expiration Date Timeout": { + "Payment Amount Timeout": { "position": { - "x": 3833.6, - "y": -1106.4 + "x": -153.6, + "y": -653.6 }, "isFriendlyName": true }, - "Routing Number Timeout Check": { + "Payment Too Large": { "position": { - "x": 3996, - "y": -147.2 + "x": 138.4, + "y": -688.8 }, - "isFriendlyName": true, - "conditions": [], - "conditionMetadata": [ - { - "id": "5e60df02-ccce-41ad-b972-0327d2602b56", - "operator": { - "name": "Equals", - "value": "Equals", - "shortDisplay": "=" - }, - "value": "Timeout" - } - ] + "isFriendlyName": true }, - "Try Expiration Date Again": { + "Payment Too Small": { "position": { - "x": 3930.4, - "y": -487.2 + "x": 378.4, + "y": -691.2 }, "isFriendlyName": true }, - "Card Number Timeout": { + "b2786200-e897-45bd-b888-0f53246f72ed": { "position": { - "x": 2892, - "y": -1114.4 - }, - "isFriendlyName": true + "x": -748.8, + "y": 534.4 + } }, - "Get Expiration Date": { + "Get Payment Amount": { "position": { - "x": 3867.2, - "y": -702.4 + "x": 60.8, + "y": -46.4 }, "isFriendlyName": true, "conditionMetadata": [], "countryCodePrefix": "+1" }, - "Card Number Timeout Check": { + "Amount Choice Input Not Recognized": { "position": { - "x": 3020.8, - "y": -892 + "x": -416, + "y": -337.6 + }, + "isFriendlyName": true + }, + "Email Receipt": { + "position": { + "x": 6702.4, + "y": -43.2 }, "isFriendlyName": true, - "conditions": [], - "conditionMetadata": [ - { - "id": "a2833b4c-7327-42a0-a470-ec6ff167dfb1", - "operator": { - "name": "Equals", - "value": "Equals", - "shortDisplay": "=" - }, - "value": "Timeout" + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" } - ] + }, + "dynamicMetadata": {} }, - "Expiration Date Timeout Check": { + "Routing Number Timeout": { "position": { - "x": 3968.8, - "y": -901.6 + "x": 3752, + "y": -92 + }, + "isFriendlyName": true + }, + "Routing Number Timeout Check": { + "position": { + "x": 3996, + "y": -147.2 }, "isFriendlyName": true, "conditions": [], "conditionMetadata": [ { - "id": "f2546136-e831-4c23-a8ea-66458a379a59", + "id": "6a0dd1cb-fe30-4f5d-ac76-28dfdcaabeb2", "operator": { "name": "Equals", "value": "Equals", @@ -158,210 +133,203 @@ }, "dynamicParams": ["EncryptedAccountNumber"] }, - "Store Encrypted Card Number": { - "position": { - "x": 3148, - "y": -687.2 - }, - "isFriendlyName": true, - "parameters": { - "Attributes": { - "EncryptedCardNumber": { - "useDynamic": true - } - } - }, - "dynamicParams": ["EncryptedCardNumber"] - }, - "Get & Encrypt Account Number": { + "Try Routing Number Again": { "position": { - "x": 2976, - "y": 114.4 + "x": 3879.2, + "y": 354.4 }, - "isFriendlyName": true, - "conditionMetadata": [], - "countryCodePrefix": "+1" + "isFriendlyName": true }, - "Get & Encrypt Card Number": { + "Get Routing Number": { "position": { - "x": 2899.2, - "y": -692.8 + "x": 3841.6, + "y": 131.2 }, "isFriendlyName": true, "conditionMetadata": [], "countryCodePrefix": "+1" }, - "b2786200-e897-45bd-b888-0f53246f72ed": { - "position": { - "x": -748.8, - "y": 534.4 - } - }, - "Payment Request Error": { - "position": { - "x": -992, - "y": 535.2 - }, - "isFriendlyName": true - }, - "Method Input Not Recognized": { + "Account Number Timeout": { "position": { - "x": 2427.2, - "y": -340 + "x": 2944, + "y": -92.8 }, "isFriendlyName": true }, - "Set Payment Method to Bank": { - "position": { - "x": 2748.8, - "y": 111.2 - }, - "isFriendlyName": true, - "dynamicParams": [] - }, - "Set Payment Method to Card": { + "Account Number Timeout Check": { "position": { - "x": 2675.2, - "y": -697.6 + "x": 3188.8, + "y": -72.8 }, "isFriendlyName": true, - "dynamicParams": [] + "conditions": [], + "conditionMetadata": [ + { + "id": "c1bcbe2e-103f-4b65-b385-d081eb30b07b", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "Timeout" + } + ] }, - "Payment Method Timeout": { + "Card Number Timeout": { "position": { - "x": 2208, - "y": -267.2 + "x": 2892, + "y": -1114.4 }, "isFriendlyName": true }, - "Email Receipt": { + "Expiration Date Timeout": { "position": { - "x": 6702.4, - "y": -43.2 - }, - "isFriendlyName": true, - "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" - } + "x": 3833.6, + "y": -1106.4 }, - "dynamicMetadata": {} + "isFriendlyName": true }, - "Ask for Payment Method": { + "Expiration Date Timeout Check": { "position": { - "x": 2230.4, - "y": -29.6 + "x": 3968.8, + "y": -901.6 }, "isFriendlyName": true, + "conditions": [], "conditionMetadata": [ { - "id": "c7c548e0-96c1-4e4d-9b15-c94d66730716", - "value": "1" - }, - { - "id": "d16f74ca-0bca-4c83-9323-b3b920e1bc63", - "value": "2" + "id": "1ab0ec91-a01c-422f-b8dd-3b1924b9d7af", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "Timeout" } ] }, - "Use Payment Method Again Timeout": { + "Try Expiration Date Again": { "position": { - "x": 1083.2, - "y": -928.8 + "x": 3928, + "y": -489.6 }, "isFriendlyName": true }, - "Store Routing Number": { + "Card Number Timeout Check": { "position": { - "x": 4120, - "y": 112 + "x": 3020.8, + "y": -892 }, "isFriendlyName": true, - "parameters": { - "Attributes": { - "RoutingNumber": { - "useDynamic": true - } + "conditions": [], + "conditionMetadata": [ + { + "id": "20511aec-fef6-47b4-bab3-d5a7643c76cd", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "Timeout" } + ] + }, + "Get Expiration Date": { + "position": { + "x": 3865.6, + "y": -704.8 }, - "dynamicParams": ["RoutingNumber"] + "isFriendlyName": true, + "conditionMetadata": [], + "countryCodePrefix": "+1" }, - "Store Expiration Date": { + "Store Encrypted Card Number": { "position": { - "x": 4127.2, - "y": -695.2 + "x": 3148, + "y": -687.2 }, "isFriendlyName": true, "parameters": { "Attributes": { - "ExpirationDate": { + "EncryptedCardNumber": { "useDynamic": true } } }, - "dynamicParams": ["ExpirationDate"] + "dynamicParams": ["EncryptedCardNumber"] }, - "Payment Success": { + "Payment Method Timeout": { "position": { - "x": 6239.2, - "y": -44.8 + "x": 2208, + "y": -267.2 }, "isFriendlyName": true }, - "Use Bank Account Again?": { + "Check for Minimum Payment": { "position": { - "x": 1353.6, - "y": -356.8 + "x": -723.2, + "y": 153.6 }, "isFriendlyName": true, + "conditions": [], "conditionMetadata": [ { - "id": "38703ff7-a6a5-4697-87ba-41478b8050f7", - "value": "1" + "id": "2a2693bb-f679-4c53-8506-e813c5626a56", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "PaymentAmountDue" }, { - "id": "ee3ca4a7-c9b8-4b26-a4eb-80061a359e80", - "value": "2" + "id": "0e2a16de-1d13-4cf0-8479-e484ae7eb4e9", + "operator": { + "name": "Is greater than", + "value": "GreaterThan", + "shortDisplay": ">" + }, + "value": "0" } ] }, - "Use Credit Card Again?": { + "Method Input Not Recognized": { + "position": { + "x": 2427.2, + "y": -340 + }, + "isFriendlyName": true + }, + "Get & Encrypt Card Number": { "position": { - "x": 1299.2, - "y": -663.2 + "x": 2899.2, + "y": -692.8 }, "isFriendlyName": true, - "conditionMetadata": [ - { - "id": "28d1b686-44d9-41bd-b721-fdc5a9bdb2be", - "value": "1" - }, - { - "id": "64bebdcb-69c9-4deb-bacc-ebe4c6e559da", - "value": "2" - } - ] + "conditionMetadata": [], + "countryCodePrefix": "+1" }, - "Record Token": { + "Set Payment Method to Card": { "position": { - "x": 5117.6, - "y": -128 + "x": 2674.4, + "y": -698.4 }, "isFriendlyName": true, "dynamicParams": [] }, - "Record Transaction ID": { + "Get & Encrypt Account Number": { "position": { - "x": 5782.4, - "y": -149.6 + "x": 2976, + "y": 114.4 }, "isFriendlyName": true, - "dynamicParams": [] + "conditionMetadata": [], + "countryCodePrefix": "+1" }, - "Record Payment Request ID": { + "Set Payment Method to Bank": { "position": { - "x": -1256.8, - "y": 152.8 + "x": 2748.8, + "y": 111.2 }, "isFriendlyName": true, "dynamicParams": [] @@ -373,68 +341,42 @@ }, "isFriendlyName": true }, - "Amount Choice Timeout": { + "Payment Request Error": { "position": { - "x": -682.4, - "y": -324.8 + "x": -992, + "y": 535.2 }, "isFriendlyName": true }, - "Amount Choice Input Not Recognized": { + "Record Payment Request ID": { "position": { - "x": -416, - "y": -337.6 + "x": -1256.8, + "y": 152.8 }, - "isFriendlyName": true + "isFriendlyName": true, + "dynamicParams": [] }, - "Check for Minimum Payment": { + "Prompt for Payment Amount Choice": { "position": { - "x": -723.2, - "y": 153.6 + "x": -479.2, + "y": -38.4 }, "isFriendlyName": true, - "conditions": [], "conditionMetadata": [ { - "id": "19d935d7-cd87-472b-a2b8-2d4864390105", - "operator": { - "name": "Equals", - "value": "Equals", - "shortDisplay": "=" - }, - "value": "PaymentAmountDue" + "id": "863244c7-a47d-4f61-b26f-324efd0c7bfc", + "value": "1" }, { - "id": "201dce28-dca4-4661-9318-d71a7f65de07", - "operator": { - "name": "Is greater than", - "value": "GreaterThan", - "shortDisplay": ">" - }, - "value": "0" + "id": "5d8ac1b7-60e4-48c6-8740-d8bf0984db89", + "value": "2" } ] }, - "Speak Minimum Payment": { - "position": { - "x": -170.4, - "y": -35.2 - }, - "isFriendlyName": true - }, - "Get Payment Amount": { - "position": { - "x": 60.8, - "y": -46.4 - }, - "isFriendlyName": true, - "conditionMetadata": [], - "countryCodePrefix": "+1" - }, - "Set Payment Amount to Entered Amount": { + "Set Payment Amount to Full Amount": { "position": { - "x": 452, - "y": -34.4 + "x": 468, + "y": 447.2 }, "isFriendlyName": true, "parameters": { @@ -446,27 +388,6 @@ }, "dynamicParams": ["PaymentAmount"] }, - "Payment Amount Timeout": { - "position": { - "x": -153.6, - "y": -653.6 - }, - "isFriendlyName": true - }, - "Payment Too Large": { - "position": { - "x": 138.4, - "y": -688.8 - }, - "isFriendlyName": true - }, - "Payment Too Small": { - "position": { - "x": 378.4, - "y": -691.2 - }, - "isFriendlyName": true - }, "Check Payment Amount": { "position": { "x": 9.6, @@ -476,7 +397,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "035358e9-3517-4248-85db-9f8bc64190d5", + "id": "11694515-2320-4234-a556-fc095b6d5bf0", "operator": { "name": "Equals", "value": "Equals", @@ -485,7 +406,7 @@ "value": "Timeout" }, { - "id": "155e1088-7284-40ea-a4af-a450b0fce7d1", + "id": "f0f41496-7306-4d29-9372-c79b0987234e", "operator": { "name": "Is greater than", "value": "GreaterThan", @@ -494,7 +415,7 @@ "value": "$.Attributes.PaymentAmountDue" }, { - "id": "632fcd39-3689-47e9-b89f-a68bff165029", + "id": "3384a423-17cf-47c6-b51d-f720522439ec", "operator": { "name": "Is less than", "value": "LessThan", @@ -504,74 +425,106 @@ } ] }, - "Check for Payment Token": { + "Set Payment Amount to Entered Amount": { "position": { - "x": 1096, - "y": -18.4 + "x": 452, + "y": -34.4 + }, + "isFriendlyName": true, + "parameters": { + "Attributes": { + "PaymentAmount": { + "useDynamic": true + } + } + }, + "dynamicParams": ["PaymentAmount"] + }, + "Use Card Again?": { + "position": { + "x": 1292, + "y": -718.4 }, "isFriendlyName": true, - "conditions": [], "conditionMetadata": [ { - "id": "0107a09a-d891-4759-8405-af2776e74527", - "operator": { - "name": "Starts with", - "value": "StartsWith", - "shortDisplay": "starts with" - }, - "value": "VC" + "id": "9d2af156-eb08-43cd-a43d-7ae0699f73ad", + "value": "1" }, { - "id": "f10a6346-9d6f-4197-a11a-71f37e14194e", - "operator": { - "name": "Starts with", - "value": "StartsWith", - "shortDisplay": "starts with" - }, - "value": "BC" + "id": "89fd0350-6ef9-470d-bb0e-a7ede4ef19bd", + "value": "2" + } + ] + }, + "Use Bank Account Again?": { + "position": { + "x": 1412, + "y": -396 + }, + "isFriendlyName": true, + "conditionMetadata": [ + { + "id": "0bae15f9-b680-4798-876e-53e01cb1b31f", + "value": "1" }, { - "id": "62539558-4e03-4f7c-8d46-8d2e1fdca78b", - "operator": { - "name": "Starts with", - "value": "StartsWith", - "shortDisplay": "starts with" - }, - "value": "BS" + "id": "007a707c-6494-41aa-977c-60e5cafbb61b", + "value": "2" } ] }, - "Prompt for Payment Amount Choice": { + "Use Payment Method Again Timeout": { "position": { - "x": -479.2, - "y": -38.4 + "x": 1083.2, + "y": -928.8 + }, + "isFriendlyName": true + }, + "Ask for Payment Method": { + "position": { + "x": 2230.4, + "y": -29.6 }, "isFriendlyName": true, "conditionMetadata": [ { - "id": "172664b6-023a-4e64-aeec-7c4a14d3f765", + "id": "0a4bf1c2-4954-4b02-939c-293ae7766b75", "value": "1" }, { - "id": "fb9686d6-8145-4f4a-b4cb-ddea571814d8", + "id": "74c3b239-b13c-4701-b465-f5e80443a7e1", "value": "2" } ] }, - "Set Payment Amount to Full Amount": { + "Check Last Payment Method": { "position": { - "x": 468, - "y": 447.2 + "x": 1000, + "y": -67.2 }, "isFriendlyName": true, - "parameters": { - "Attributes": { - "PaymentAmount": { - "useDynamic": true - } + "conditions": [], + "conditionMetadata": [ + { + "id": "f2a6d094-e104-4aa2-b62d-12ec76411785", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "Card" + }, + { + "id": "1d01efbd-19e6-466f-95a7-367df5ac6ee1", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "Bank" } - }, - "dynamicParams": ["PaymentAmount"] + ] }, "Create Payment Request": { "position": { @@ -588,10 +541,17 @@ }, "87859db2-400d-410b-8818-05c8ae4869aa": { "position": { - "x": -1628.8, - "y": 480 + "x": -1630.4, + "y": 477.6 } }, + "Payment Submission Error": { + "position": { + "x": 6013.6, + "y": 99.2 + }, + "isFriendlyName": true + }, "Submit Payment": { "position": { "x": 5556, @@ -605,18 +565,42 @@ }, "dynamicMetadata": {} }, - "Tokenize Transaction": { + "Store Routing Number": { "position": { - "x": 4880, - "y": -132.8 + "x": 4120, + "y": 112 }, "isFriendlyName": true, "parameters": { - "LambdaFunctionARN": { - "displayName": "<>" + "Attributes": { + "RoutingNumber": { + "useDynamic": true + } + } + }, + "dynamicParams": ["RoutingNumber"] + }, + "Store Expiration Date": { + "position": { + "x": 4127.2, + "y": -695.2 + }, + "isFriendlyName": true, + "parameters": { + "Attributes": { + "ExpirationDate": { + "useDynamic": true + } } }, - "dynamicMetadata": {} + "dynamicParams": ["ExpirationDate"] + }, + "Payment Validation Error": { + "position": { + "x": 6022.4, + "y": 340.8 + }, + "isFriendlyName": true }, "a3ea896e-4f43-4677-8edd-159f677dc41e": { "position": { @@ -624,20 +608,6 @@ "y": 192.8 } }, - "Receipt Success": { - "position": { - "x": 6922.4, - "y": -128 - }, - "isFriendlyName": true - }, - "Receipt Error": { - "position": { - "x": 7143.2, - "y": 55.2 - }, - "isFriendlyName": true - }, "Check for Customer Email": { "position": { "x": 6460.8, @@ -647,7 +617,7 @@ "conditions": [], "conditionMetadata": [ { - "id": "be10b27c-2317-4c85-9268-1e9afacc1da6", + "id": "931df5f9-5b2b-4e34-a744-36fe5e9d0bc6", "operator": { "name": "Contains", "value": "Contains", @@ -657,24 +627,24 @@ } ] }, - "Internal Error": { + "Receipt Success": { "position": { - "x": 2660, - "y": 525.6 + "x": 6921.6, + "y": -129.6 }, "isFriendlyName": true }, - "Payment Submission Error": { + "Receipt Error": { "position": { - "x": 6016, - "y": 158.4 + "x": 7143.2, + "y": 55.2 }, "isFriendlyName": true }, - "Payment Validation Error": { + "Internal Error": { "position": { - "x": 6020.8, - "y": 337.6 + "x": 2659.2, + "y": 524 }, "isFriendlyName": true }, @@ -686,13 +656,59 @@ "isFriendlyName": true, "dynamicParams": [] }, - "Remove Failed Payment Token": { + "Record Token": { + "position": { + "x": 5190.4, + "y": -132 + }, + "isFriendlyName": true, + "dynamicParams": [] + }, + "Tokenize Transaction": { + "position": { + "x": 4592.8, + "y": -138.4 + }, + "isFriendlyName": true, + "parameters": { + "LambdaFunctionARN": { + "displayName": "<>" + } + }, + "dynamicMetadata": {} + }, + "Remove Failed Payment Token and Method": { "position": { - "x": 6335.2, - "y": 253.6 + "x": 6333.6, + "y": 252.8 }, "isFriendlyName": true, "dynamicParams": [] + }, + "Check for Tokenize Error": { + "position": { + "x": 4880.8, + "y": -136.8 + }, + "isFriendlyName": true, + "conditionMetadata": [ + { + "id": "0ebb618b-eab1-4919-9313-9ec860f63162", + "operator": { + "name": "Equals", + "value": "Equals", + "shortDisplay": "=" + }, + "value": "NULL" + } + ] + }, + "Speak Validation Error": { + "position": { + "x": 5128.8, + "y": 178.4 + }, + "isFriendlyName": true } }, "Annotations": [], @@ -704,15 +720,15 @@ "Actions": [ { "Parameters": { - "Text": "There was a problem with your routing number. Please try again." + "Text": "Your payment was processed successfully." }, - "Identifier": "Try Routing Number Again", + "Identifier": "Payment Success", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Routing Number", + "NextAction": "Check for Customer Email", "Errors": [ { - "NextAction": "Get Routing Number", + "NextAction": "Check for Customer Email", "ErrorType": "NoMatchingError" } ] @@ -720,15 +736,18 @@ }, { "Parameters": { - "Text": "Are you still there?" + "Attributes": { + "TransactionId": "$.External.TransactionId" + }, + "TargetContact": "Current" }, - "Identifier": "Account Number Timeout", - "Type": "MessageParticipant", + "Identifier": "Record Transaction ID", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Get & Encrypt Account Number", + "NextAction": "Payment Success", "Errors": [ { - "NextAction": "Get & Encrypt Account Number", + "NextAction": "Payment Success", "ErrorType": "NoMatchingError" } ] @@ -736,40 +755,31 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "Text": "Are you still there?" }, - "Identifier": "Account Number Timeout Check", - "Type": "Compare", + "Identifier": "Amount Choice Timeout", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Store Encrypted Account Number", - "Conditions": [ - { - "NextAction": "Account Number Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - } - ], + "NextAction": "Prompt for Payment Amount Choice", "Errors": [ { - "NextAction": "Store Encrypted Account Number", - "ErrorType": "NoMatchingCondition" + "NextAction": "Prompt for Payment Amount Choice", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "Text": "Are you still there?" + "Text": "You are permitted to make a partial payment of at least $$.Attributes.PaymentMinimumPayment." }, - "Identifier": "Routing Number Timeout", + "Identifier": "Speak Minimum Payment", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Routing Number", + "NextAction": "Get Payment Amount", "Errors": [ { - "NextAction": "Get Routing Number", + "NextAction": "Get Payment Amount", "ErrorType": "NoMatchingError" } ] @@ -777,26 +787,15 @@ }, { "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "10", - "Text": "Please enter your bank's routing number, followed by the pound key when complete.", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "9" - } - } + "Text": "Are you still there?" }, - "Identifier": "Get Routing Number", - "Type": "GetParticipantInput", + "Identifier": "Payment Amount Timeout", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Routing Number Timeout Check", + "NextAction": "Speak Minimum Payment", "Errors": [ { - "NextAction": "Try Routing Number Again", + "NextAction": "Speak Minimum Payment", "ErrorType": "NoMatchingError" } ] @@ -804,15 +803,15 @@ }, { "Parameters": { - "Text": "Are you still there?" + "Text": "The entered amount of $$.StoredCustomerInput exceeds the total amount due of $$.Attributes.PaymentAmountDue. Please try again with a smaller amount." }, - "Identifier": "Expiration Date Timeout", + "Identifier": "Payment Too Large", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Speak Minimum Payment", "Errors": [ { - "NextAction": "Get Expiration Date", + "NextAction": "Speak Minimum Payment", "ErrorType": "NoMatchingError" } ] @@ -820,40 +819,48 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "Text": "The entered amount of $$.StoredCustomerInput is less than the minimum payment of $$.Attributes.PaymentMinimumPayment. Please try again with a larger amount." }, - "Identifier": "Routing Number Timeout Check", - "Type": "Compare", + "Identifier": "Payment Too Small", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Store Routing Number", - "Conditions": [ - { - "NextAction": "Routing Number Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - } - ], + "NextAction": "Speak Minimum Payment", "Errors": [ { - "NextAction": "Store Routing Number", - "ErrorType": "NoMatchingCondition" + "NextAction": "Speak Minimum Payment", + "ErrorType": "NoMatchingError" } ] } }, + { + "Parameters": {}, + "Identifier": "b2786200-e897-45bd-b888-0f53246f72ed", + "Type": "EndFlowModuleExecution", + "Transitions": {} + }, { "Parameters": { - "Text": "There was a problem with your expiration date. Please try again." + "StoreInput": "True", + "InputTimeLimitSeconds": "5", + "Text": "Please enter the amount you would like to pay in whole dollars, followed by the pound key.", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" + }, + "InputValidation": { + "CustomValidation": { + "MaximumLength": "20" + } + } }, - "Identifier": "Try Expiration Date Again", - "Type": "MessageParticipant", + "Identifier": "Get Payment Amount", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Check Payment Amount", "Errors": [ { - "NextAction": "Get Expiration Date", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -861,15 +868,15 @@ }, { "Parameters": { - "Text": "Are you still there?" + "Text": "Your entry was not recognized. Please try again." }, - "Identifier": "Card Number Timeout", + "Identifier": "Amount Choice Input Not Recognized", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Prompt for Payment Amount Choice", "Errors": [ { - "NextAction": "Get & Encrypt Card Number", + "NextAction": "Prompt for Payment Amount Choice", "ErrorType": "NoMatchingError" } ] @@ -877,26 +884,19 @@ }, { "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "5", - "Text": "Please enter your card's expiration date, followed by the pound key when complete.", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "4" - } + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "ResponseValidation": { + "ResponseType": "JSON" } }, - "Identifier": "Get Expiration Date", - "Type": "GetParticipantInput", + "Identifier": "Email Receipt", + "Type": "InvokeLambdaFunction", "Transitions": { - "NextAction": "Expiration Date Timeout Check", + "NextAction": "Receipt Success", "Errors": [ { - "NextAction": "Try Expiration Date Again", + "NextAction": "Receipt Error", "ErrorType": "NoMatchingError" } ] @@ -904,25 +904,16 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "Text": "Are you still there?" }, - "Identifier": "Card Number Timeout Check", - "Type": "Compare", + "Identifier": "Routing Number Timeout", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Store Encrypted Card Number", - "Conditions": [ - { - "NextAction": "Card Number Timeout", - "Condition": { - "Operator": "Equals", - "Operands": ["Timeout"] - } - } - ], + "NextAction": "Get Routing Number", "Errors": [ { - "NextAction": "Store Encrypted Card Number", - "ErrorType": "NoMatchingCondition" + "NextAction": "Get Routing Number", + "ErrorType": "NoMatchingError" } ] } @@ -931,13 +922,13 @@ "Parameters": { "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Expiration Date Timeout Check", + "Identifier": "Routing Number Timeout Check", "Type": "Compare", "Transitions": { - "NextAction": "Store Expiration Date", + "NextAction": "Store Routing Number", "Conditions": [ { - "NextAction": "Expiration Date Timeout", + "NextAction": "Routing Number Timeout", "Condition": { "Operator": "Equals", "Operands": ["Timeout"] @@ -946,27 +937,8 @@ ], "Errors": [ { - "NextAction": "Store Expiration Date", - "ErrorType": "NoMatchingCondition" - } - ] - } - }, - { - "Parameters": { - "Attributes": { - "EncryptedAccountNumber": "$.StoredCustomerInput" - }, - "TargetContact": "Current" - }, - "Identifier": "Store Encrypted Account Number", - "Type": "UpdateContactAttributes", - "Transitions": { - "NextAction": "Get Routing Number", - "Errors": [ - { - "NextAction": "Internal Error", - "ErrorType": "NoMatchingError" + "NextAction": "Store Routing Number", + "ErrorType": "NoMatchingCondition" } ] } @@ -974,14 +946,14 @@ { "Parameters": { "Attributes": { - "EncryptedCardNumber": "$.StoredCustomerInput" + "EncryptedAccountNumber": "$.StoredCustomerInput" }, "TargetContact": "Current" }, - "Identifier": "Store Encrypted Card Number", + "Identifier": "Store Encrypted Account Number", "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Get Expiration Date", + "NextAction": "Get Routing Number", "Errors": [ { "NextAction": "Internal Error", @@ -992,30 +964,15 @@ }, { "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "10", - "Text": "Please enter your bank account number followed by the pound key when complete.", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "20" - } - }, - "InputEncryption": { - "EncryptionKeyId": "<>", - "Key": "<>" - } + "Text": "There was a problem with your bank routing number. Please check your entry and try again." }, - "Identifier": "Get & Encrypt Account Number", - "Type": "GetParticipantInput", + "Identifier": "Try Routing Number Again", + "Type": "MessageParticipant", "Transitions": { - "NextAction": "Account Number Timeout Check", + "NextAction": "Get Routing Number", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "Get Routing Number", "ErrorType": "NoMatchingError" } ] @@ -1025,50 +982,40 @@ "Parameters": { "StoreInput": "True", "InputTimeLimitSeconds": "10", - "Text": "Please enter your card number followed by the pound key when complete.", + "Text": "Please enter your bank's routing number, followed by the pound key when complete.", "DTMFConfiguration": { "DisableCancelKey": "False", "InputTerminationSequence": "#" }, "InputValidation": { "CustomValidation": { - "MaximumLength": "20" + "MaximumLength": "25" } - }, - "InputEncryption": { - "EncryptionKeyId": "<>", - "Key": "<>" } }, - "Identifier": "Get & Encrypt Card Number", + "Identifier": "Get Routing Number", "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Card Number Timeout Check", + "NextAction": "Routing Number Timeout Check", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "Try Routing Number Again", "ErrorType": "NoMatchingError" } ] } }, - { - "Parameters": {}, - "Identifier": "b2786200-e897-45bd-b888-0f53246f72ed", - "Type": "EndFlowModuleExecution", - "Transitions": {} - }, { "Parameters": { - "Text": "There was an error creating the payment request." + "Text": "Are you still there?" }, - "Identifier": "Payment Request Error", + "Identifier": "Account Number Timeout", "Type": "MessageParticipant", "Transitions": { - "NextAction": "b2786200-e897-45bd-b888-0f53246f72ed", + "NextAction": "Get & Encrypt Account Number", "Errors": [ { - "NextAction": "b2786200-e897-45bd-b888-0f53246f72ed", + "NextAction": "Get & Encrypt Account Number", "ErrorType": "NoMatchingError" } ] @@ -1076,48 +1023,35 @@ }, { "Parameters": { - "Text": "Your input was not recognized. Please try again." + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Method Input Not Recognized", - "Type": "MessageParticipant", + "Identifier": "Account Number Timeout Check", + "Type": "Compare", "Transitions": { - "NextAction": "Ask for Payment Method", - "Errors": [ + "NextAction": "Store Encrypted Account Number", + "Conditions": [ { - "NextAction": "Ask for Payment Method", - "ErrorType": "NoMatchingError" + "NextAction": "Account Number Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } } - ] - } - }, - { - "Parameters": { - "Attributes": { - "PaymentMethod": "Bank" - }, - "TargetContact": "Current" - }, - "Identifier": "Set Payment Method to Bank", - "Type": "UpdateContactAttributes", - "Transitions": { - "NextAction": "Get & Encrypt Account Number", + ], "Errors": [ { - "NextAction": "Get & Encrypt Account Number", - "ErrorType": "NoMatchingError" + "NextAction": "Store Encrypted Account Number", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "Attributes": { - "PaymentMethod": "Card" - }, - "TargetContact": "Current" + "Text": "Are you still there?" }, - "Identifier": "Set Payment Method to Card", - "Type": "UpdateContactAttributes", + "Identifier": "Card Number Timeout", + "Type": "MessageParticipant", "Transitions": { "NextAction": "Get & Encrypt Card Number", "Errors": [ @@ -1132,33 +1066,13 @@ "Parameters": { "Text": "Are you still there?" }, - "Identifier": "Payment Method Timeout", + "Identifier": "Expiration Date Timeout", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Ask for Payment Method", - "Errors": [ - { - "NextAction": "Ask for Payment Method", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "ResponseValidation": { - "ResponseType": "JSON" - } - }, - "Identifier": "Email Receipt", - "Type": "InvokeLambdaFunction", - "Transitions": { - "NextAction": "Receipt Success", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "Receipt Error", + "NextAction": "Get Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -1166,57 +1080,40 @@ }, { "Parameters": { - "StoreInput": "False", - "InputTimeLimitSeconds": "5", - "Text": "To pay with a credit card, press 1.\nTo pay directly with your bank account, press 2." + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Ask for Payment Method", - "Type": "GetParticipantInput", + "Identifier": "Expiration Date Timeout Check", + "Type": "Compare", "Transitions": { - "NextAction": "Method Input Not Recognized", + "NextAction": "Store Expiration Date", "Conditions": [ { - "NextAction": "Set Payment Method to Card", - "Condition": { - "Operator": "Equals", - "Operands": ["1"] - } - }, - { - "NextAction": "Set Payment Method to Bank", + "NextAction": "Expiration Date Timeout", "Condition": { "Operator": "Equals", - "Operands": ["2"] + "Operands": ["Timeout"] } } ], "Errors": [ { - "NextAction": "Payment Method Timeout", - "ErrorType": "InputTimeLimitExceeded" - }, - { - "NextAction": "Method Input Not Recognized", + "NextAction": "Store Expiration Date", "ErrorType": "NoMatchingCondition" - }, - { - "NextAction": "Method Input Not Recognized", - "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "Text": "Are you still there?" + "Text": "There was a problem with your expiration date. Please check your entry and try again." }, - "Identifier": "Use Payment Method Again Timeout", + "Identifier": "Try Expiration Date Again", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Check for Payment Token", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "Check for Payment Token", + "NextAction": "Get Expiration Date", "ErrorType": "NoMatchingError" } ] @@ -1224,37 +1121,51 @@ }, { "Parameters": { - "Attributes": { - "RoutingNumber": "$.StoredCustomerInput" - }, - "TargetContact": "Current" + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Store Routing Number", - "Type": "UpdateContactAttributes", + "Identifier": "Card Number Timeout Check", + "Type": "Compare", "Transitions": { - "NextAction": "Tokenize Transaction", + "NextAction": "Store Encrypted Card Number", + "Conditions": [ + { + "NextAction": "Card Number Timeout", + "Condition": { + "Operator": "Equals", + "Operands": ["Timeout"] + } + } + ], "Errors": [ { - "NextAction": "Internal Error", - "ErrorType": "NoMatchingError" + "NextAction": "Store Encrypted Card Number", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "Attributes": { - "ExpirationDate": "$.StoredCustomerInput" + "StoreInput": "True", + "InputTimeLimitSeconds": "5", + "Text": "Please enter your card's expiration date in the format month-month-year-year, followed by the pound key when complete.", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" }, - "TargetContact": "Current" + "InputValidation": { + "CustomValidation": { + "MaximumLength": "25" + } + } }, - "Identifier": "Store Expiration Date", - "Type": "UpdateContactAttributes", + "Identifier": "Get Expiration Date", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Tokenize Transaction", + "NextAction": "Expiration Date Timeout Check", "Errors": [ { - "NextAction": "Internal Error", + "NextAction": "Try Expiration Date Again", "ErrorType": "NoMatchingError" } ] @@ -1262,15 +1173,18 @@ }, { "Parameters": { - "Text": "Your payment was processed successfully." + "Attributes": { + "EncryptedCardNumber": "$.StoredCustomerInput" + }, + "TargetContact": "Current" }, - "Identifier": "Payment Success", - "Type": "MessageParticipant", + "Identifier": "Store Encrypted Card Number", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Check for Customer Email", + "NextAction": "Get Expiration Date", "Errors": [ { - "NextAction": "Check for Customer Email", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -1278,39 +1192,13 @@ }, { "Parameters": { - "StoreInput": "False", - "InputTimeLimitSeconds": "5", - "Text": "You previously paid with a bank account.\n\nIf you would like to use this account again for this payment, press 1.\nTo use a different payment method, press 2." + "Text": "Are you still there?" }, - "Identifier": "Use Bank Account Again?", - "Type": "GetParticipantInput", + "Identifier": "Payment Method Timeout", + "Type": "MessageParticipant", "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" - }, + "Errors": [ { "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingError" @@ -1320,39 +1208,45 @@ }, { "Parameters": { - "StoreInput": "False", - "InputTimeLimitSeconds": "5", - "Text": "You previously paid with a credit card.\n\nIf you would like to use this card again for this payment, press 1.\nTo use a different payment method, press 2." + "ComparisonValue": "$.Attributes.PaymentMinimumPayment" }, - "Identifier": "Use Credit Card Again?", - "Type": "GetParticipantInput", + "Identifier": "Check for Minimum Payment", + "Type": "Compare", "Transitions": { "NextAction": "Ask for Payment Method", "Conditions": [ { - "NextAction": "Submit Payment", + "NextAction": "Ask for Payment Method", "Condition": { "Operator": "Equals", - "Operands": ["1"] + "Operands": ["PaymentAmountDue"] } }, { - "NextAction": "Ask for Payment Method", + "NextAction": "Prompt for Payment Amount Choice", "Condition": { - "Operator": "Equals", - "Operands": ["2"] + "Operator": "NumberGreaterThan", + "Operands": ["0"] } } ], "Errors": [ - { - "NextAction": "Use Payment Method Again Timeout", - "ErrorType": "InputTimeLimitExceeded" - }, { "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingCondition" - }, + } + ] + } + }, + { + "Parameters": { + "Text": "Your entry was not recognized. Please try again." + }, + "Identifier": "Method Input Not Recognized", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Ask for Payment Method", + "Errors": [ { "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingError" @@ -1362,18 +1256,30 @@ }, { "Parameters": { - "Attributes": { - "PaymentToken": "$.External.PaymentToken" + "StoreInput": "True", + "InputTimeLimitSeconds": "10", + "Text": "Please enter your card number followed by the pound key when complete.", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" }, - "TargetContact": "Current" + "InputValidation": { + "CustomValidation": { + "MaximumLength": "25" + } + }, + "InputEncryption": { + "EncryptionKeyId": "<>", + "Key": "<>" + } }, - "Identifier": "Record Token", - "Type": "UpdateContactAttributes", + "Identifier": "Get & Encrypt Card Number", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Submit Payment", + "NextAction": "Card Number Timeout Check", "Errors": [ { - "NextAction": "Submit Payment", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -1382,17 +1288,48 @@ { "Parameters": { "Attributes": { - "TransactionId": "$.External.TransactionId" + "PaymentMethod": "Card" }, "TargetContact": "Current" }, - "Identifier": "Record Transaction ID", + "Identifier": "Set Payment Method to Card", "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Payment Success", + "NextAction": "Get & Encrypt Card Number", "Errors": [ { - "NextAction": "Payment Success", + "NextAction": "Get & Encrypt Card Number", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "StoreInput": "True", + "InputTimeLimitSeconds": "10", + "Text": "Please enter your bank account number followed by the pound key when complete.", + "DTMFConfiguration": { + "DisableCancelKey": "False", + "InputTerminationSequence": "#" + }, + "InputValidation": { + "CustomValidation": { + "MaximumLength": "25" + } + }, + "InputEncryption": { + "EncryptionKeyId": "<>", + "Key": "<>" + } + }, + "Identifier": "Get & Encrypt Account Number", + "Type": "GetParticipantInput", + "Transitions": { + "NextAction": "Account Number Timeout Check", + "Errors": [ + { + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -1401,17 +1338,17 @@ { "Parameters": { "Attributes": { - "PaymentRequestId": "$.External.PaymentRequestId" + "PaymentMethod": "Bank" }, "TargetContact": "Current" }, - "Identifier": "Record Payment Request ID", + "Identifier": "Set Payment Method to Bank", "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Speak Amount", + "NextAction": "Get & Encrypt Account Number", "Errors": [ { - "NextAction": "Payment Request Error", + "NextAction": "Get & Encrypt Account Number", "ErrorType": "NoMatchingError" } ] @@ -1435,15 +1372,15 @@ }, { "Parameters": { - "Text": "Are you still there?" + "Text": "There was an error creating the payment request." }, - "Identifier": "Amount Choice Timeout", + "Identifier": "Payment Request Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Prompt for Payment Amount Choice", + "NextAction": "b2786200-e897-45bd-b888-0f53246f72ed", "Errors": [ { - "NextAction": "Prompt for Payment Amount Choice", + "NextAction": "b2786200-e897-45bd-b888-0f53246f72ed", "ErrorType": "NoMatchingError" } ] @@ -1451,15 +1388,18 @@ }, { "Parameters": { - "Text": "Your input was not recognized. Please try again." + "Attributes": { + "PaymentRequestId": "$.External.PaymentRequestId" + }, + "TargetContact": "Current" }, - "Identifier": "Amount Choice Input Not Recognized", - "Type": "MessageParticipant", + "Identifier": "Record Payment Request ID", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Prompt for Payment Amount Choice", + "NextAction": "Speak Amount", "Errors": [ { - "NextAction": "Prompt for Payment Amount Choice", + "NextAction": "Payment Request Error", "ErrorType": "NoMatchingError" } ] @@ -1467,74 +1407,41 @@ }, { "Parameters": { - "ComparisonValue": "$.Attributes.PaymentMinimumPayment" + "StoreInput": "False", + "InputTimeLimitSeconds": "5", + "Text": "To pay the amount in full, press 1.\nTo pay a partial amount, press 2." }, - "Identifier": "Check for Minimum Payment", - "Type": "Compare", + "Identifier": "Prompt for Payment Amount Choice", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Ask for Payment Method", + "NextAction": "Amount Choice Input Not Recognized", "Conditions": [ { - "NextAction": "Ask for Payment Method", + "NextAction": "Set Payment Amount to Full Amount", "Condition": { "Operator": "Equals", - "Operands": ["PaymentAmountDue"] + "Operands": ["1"] } }, { - "NextAction": "Prompt for Payment Amount Choice", + "NextAction": "Speak Minimum Payment", "Condition": { - "Operator": "NumberGreaterThan", - "Operands": ["0"] + "Operator": "Equals", + "Operands": ["2"] } } ], "Errors": [ { - "NextAction": "Ask for Payment Method", - "ErrorType": "NoMatchingCondition" - } - ] - } - }, - { - "Parameters": { - "Text": "You are permitted to make a partial payment of at least $$.Attributes.PaymentMinimumPayment." - }, - "Identifier": "Speak Minimum Payment", - "Type": "MessageParticipant", - "Transitions": { - "NextAction": "Get Payment Amount", - "Errors": [ + "NextAction": "Amount Choice Timeout", + "ErrorType": "InputTimeLimitExceeded" + }, { - "NextAction": "Get Payment Amount", - "ErrorType": "NoMatchingError" - } - ] - } - }, - { - "Parameters": { - "StoreInput": "True", - "InputTimeLimitSeconds": "5", - "Text": "Please enter the amount you would like to pay in whole dollars, followed by the pound key.", - "DTMFConfiguration": { - "DisableCancelKey": "False", - "InputTerminationSequence": "#" - }, - "InputValidation": { - "CustomValidation": { - "MaximumLength": "20" - } - } - }, - "Identifier": "Get Payment Amount", - "Type": "GetParticipantInput", - "Transitions": { - "NextAction": "Check Payment Amount", - "Errors": [ + "NextAction": "Amount Choice Input Not Recognized", + "ErrorType": "NoMatchingCondition" + }, { - "NextAction": "Internal Error", + "NextAction": "Amount Choice Input Not Recognized", "ErrorType": "NoMatchingError" } ] @@ -1543,14 +1450,14 @@ { "Parameters": { "Attributes": { - "PaymentAmount": "$.StoredCustomerInput" + "PaymentAmount": "$.Customer.Attributes.PaymentAmountDue" }, "TargetContact": "Current" }, - "Identifier": "Set Payment Amount to Entered Amount", + "Identifier": "Set Payment Amount to Full Amount", "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Check for Payment Token", + "NextAction": "Check Last Payment Method", "Errors": [ { "NextAction": "Internal Error", @@ -1561,47 +1468,57 @@ }, { "Parameters": { - "Text": "Are you still there?" + "ComparisonValue": "$.StoredCustomerInput" }, - "Identifier": "Payment Amount Timeout", - "Type": "MessageParticipant", + "Identifier": "Check Payment Amount", + "Type": "Compare", "Transitions": { - "NextAction": "Speak Minimum Payment", - "Errors": [ + "NextAction": "Set Payment Amount to Entered Amount", + "Conditions": [ { - "NextAction": "Speak Minimum Payment", - "ErrorType": "NoMatchingError" + "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"] + } } - ] - } - }, - { - "Parameters": { - "Text": "The entered amount of $$.StoredCustomerInput exceeds the total amount due of $$.Attributes.PaymentAmountDue. Please try again with a smaller amount." - }, - "Identifier": "Payment Too Large", - "Type": "MessageParticipant", - "Transitions": { - "NextAction": "Speak Minimum Payment", + ], "Errors": [ { - "NextAction": "Speak Minimum Payment", - "ErrorType": "NoMatchingError" + "NextAction": "Set Payment Amount to Entered Amount", + "ErrorType": "NoMatchingCondition" } ] } }, { "Parameters": { - "Text": "The entered amount of $$.StoredCustomerInput is less than the minimum payment of $$.Attributes.PaymentMinimumPayment. Please try again with a larger amount." + "Attributes": { + "PaymentAmount": "$.StoredCustomerInput" + }, + "TargetContact": "Current" }, - "Identifier": "Payment Too Small", - "Type": "MessageParticipant", + "Identifier": "Set Payment Amount to Entered Amount", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Speak Minimum Payment", + "NextAction": "Check Last Payment Method", "Errors": [ { - "NextAction": "Speak Minimum Payment", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -1609,78 +1526,100 @@ }, { "Parameters": { - "ComparisonValue": "$.StoredCustomerInput" + "StoreInput": "False", + "InputTimeLimitSeconds": "5", + "Text": "You previously paid with a credit or debit card.\n\nIf you would like to use this card again for this payment, press 1.\nTo use a different payment method, press 2." }, - "Identifier": "Check Payment Amount", - "Type": "Compare", + "Identifier": "Use Card Again?", + "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Set Payment Amount to Entered Amount", + "NextAction": "Ask for Payment Method", "Conditions": [ { - "NextAction": "Payment Amount Timeout", + "NextAction": "Submit Payment", "Condition": { "Operator": "Equals", - "Operands": ["Timeout"] - } - }, - { - "NextAction": "Payment Too Large", - "Condition": { - "Operator": "NumberGreaterThan", - "Operands": ["$.Attributes.PaymentAmountDue"] + "Operands": ["1"] } }, { - "NextAction": "Payment Too Small", + "NextAction": "Ask for Payment Method", "Condition": { - "Operator": "NumberLessThan", - "Operands": ["$.Attributes.PaymentMinimumPayment"] + "Operator": "Equals", + "Operands": ["2"] } } ], "Errors": [ { - "NextAction": "Set Payment Amount to Entered Amount", + "NextAction": "Use Payment Method Again Timeout", + "ErrorType": "InputTimeLimitExceeded" + }, + { + "NextAction": "Ask for Payment Method", "ErrorType": "NoMatchingCondition" + }, + { + "NextAction": "Ask for Payment Method", + "ErrorType": "NoMatchingError" } ] } }, { "Parameters": { - "ComparisonValue": "$.Attributes.PaymentToken" + "StoreInput": "False", + "InputTimeLimitSeconds": "5", + "Text": "You previously paid with a bank account.\n\nIf you would like to use this account again for this payment, press 1.\nTo use a different payment method, press 2." }, - "Identifier": "Check for Payment Token", - "Type": "Compare", + "Identifier": "Use Bank Account Again?", + "Type": "GetParticipantInput", "Transitions": { "NextAction": "Ask for Payment Method", "Conditions": [ { - "NextAction": "Use Credit Card Again?", - "Condition": { - "Operator": "TextStartsWith", - "Operands": ["VC"] - } - }, - { - "NextAction": "Use Bank Account Again?", + "NextAction": "Submit Payment", "Condition": { - "Operator": "TextStartsWith", - "Operands": ["BC"] + "Operator": "Equals", + "Operands": ["1"] } }, { - "NextAction": "Use Bank Account Again?", + "NextAction": "Ask for Payment Method", "Condition": { - "Operator": "TextStartsWith", - "Operands": ["BS"] + "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": { + "Text": "Are you still there?" + }, + "Identifier": "Use Payment Method Again Timeout", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Check Last Payment Method", + "Errors": [ + { + "NextAction": "Check Last Payment Method", + "ErrorType": "NoMatchingError" } ] } @@ -1689,22 +1628,22 @@ "Parameters": { "StoreInput": "False", "InputTimeLimitSeconds": "5", - "Text": "To pay the amount in full, press 1.\nTo pay a partial amount, press 2." + "Text": "To pay with a credit or debit card, press 1.\nTo pay directly with your bank account, press 2." }, - "Identifier": "Prompt for Payment Amount Choice", + "Identifier": "Ask for Payment Method", "Type": "GetParticipantInput", "Transitions": { - "NextAction": "Amount Choice Input Not Recognized", + "NextAction": "Method Input Not Recognized", "Conditions": [ { - "NextAction": "Set Payment Amount to Full Amount", + "NextAction": "Set Payment Method to Card", "Condition": { "Operator": "Equals", "Operands": ["1"] } }, { - "NextAction": "Speak Minimum Payment", + "NextAction": "Set Payment Method to Bank", "Condition": { "Operator": "Equals", "Operands": ["2"] @@ -1713,15 +1652,15 @@ ], "Errors": [ { - "NextAction": "Amount Choice Timeout", + "NextAction": "Payment Method Timeout", "ErrorType": "InputTimeLimitExceeded" }, { - "NextAction": "Amount Choice Input Not Recognized", + "NextAction": "Method Input Not Recognized", "ErrorType": "NoMatchingCondition" }, { - "NextAction": "Amount Choice Input Not Recognized", + "NextAction": "Method Input Not Recognized", "ErrorType": "NoMatchingError" } ] @@ -1729,19 +1668,32 @@ }, { "Parameters": { - "Attributes": { - "PaymentAmount": "$.Customer.Attributes.PaymentAmountDue" - }, - "TargetContact": "Current" + "ComparisonValue": "$.Attributes.PaymentMethod" }, - "Identifier": "Set Payment Amount to Full Amount", - "Type": "UpdateContactAttributes", + "Identifier": "Check Last Payment Method", + "Type": "Compare", "Transitions": { - "NextAction": "Check for Payment Token", + "NextAction": "Ask for Payment Method", + "Conditions": [ + { + "NextAction": "Use Card Again?", + "Condition": { + "Operator": "Equals", + "Operands": ["Card"] + } + }, + { + "NextAction": "Use Bank Account Again?", + "Condition": { + "Operator": "Equals", + "Operands": ["Bank"] + } + } + ], "Errors": [ { - "NextAction": "Internal Error", - "ErrorType": "NoMatchingError" + "NextAction": "Ask for Payment Method", + "ErrorType": "NoMatchingCondition" } ] } @@ -1776,6 +1728,22 @@ "NextAction": "Create Payment Request" } }, + { + "Parameters": { + "Text": "We're sorry, an error has occured preventing us from submitting your payment. You have not been charged." + }, + "Identifier": "Payment Submission Error", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Remove Failed Payment Token and Method", + "Errors": [ + { + "NextAction": "Remove Failed Payment Token and Method", + "ErrorType": "NoMatchingError" + } + ] + } + }, { "Parameters": { "LambdaFunctionARN": "<>", @@ -1798,41 +1766,37 @@ }, { "Parameters": { - "LambdaFunctionARN": "<>", - "InvocationTimeLimitSeconds": "8", - "ResponseValidation": { - "ResponseType": "JSON" - } + "Attributes": { + "RoutingNumber": "$.StoredCustomerInput" + }, + "TargetContact": "Current" }, - "Identifier": "Tokenize Transaction", - "Type": "InvokeLambdaFunction", + "Identifier": "Store Routing Number", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Record Token", + "NextAction": "Tokenize Transaction", "Errors": [ { - "NextAction": "Payment Validation Error", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] } }, - { - "Parameters": {}, - "Identifier": "a3ea896e-4f43-4677-8edd-159f677dc41e", - "Type": "EndFlowModuleExecution", - "Transitions": {} - }, { "Parameters": { - "Text": "A receipt has been sent to your email address at $.Attributes.['Email']." + "Attributes": { + "ExpirationDate": "$.StoredCustomerInput" + }, + "TargetContact": "Current" }, - "Identifier": "Receipt Success", - "Type": "MessageParticipant", + "Identifier": "Store Expiration Date", + "Type": "UpdateContactAttributes", "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Tokenize Transaction", "Errors": [ { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Internal Error", "ErrorType": "NoMatchingError" } ] @@ -1840,20 +1804,26 @@ }, { "Parameters": { - "Text": "There was an error sending the receipt to your email address at $.Attributes.['Email']. Please contact customer support to receive a receipt for this transaction." + "Text": "There was a problem validating your $.Attributes.PaymentMethod information." }, - "Identifier": "Receipt Error", + "Identifier": "Payment Validation Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Remove Failed Payment Token and Method", "Errors": [ { - "NextAction": "Redact Sensitive Contact Attributes", + "NextAction": "Remove Failed Payment Token and Method", "ErrorType": "NoMatchingError" } ] } }, + { + "Parameters": {}, + "Identifier": "a3ea896e-4f43-4677-8edd-159f677dc41e", + "Type": "EndFlowModuleExecution", + "Transitions": {} + }, { "Parameters": { "ComparisonValue": "$.Attributes.Email" @@ -1881,9 +1851,9 @@ }, { "Parameters": { - "Text": "We're sorry, an error has occured that prevents us from collecting the payment." + "Text": "A receipt has been sent to your email address, $.Attributes.['Email']." }, - "Identifier": "Internal Error", + "Identifier": "Receipt Success", "Type": "MessageParticipant", "Transitions": { "NextAction": "Redact Sensitive Contact Attributes", @@ -1897,15 +1867,15 @@ }, { "Parameters": { - "Text": "We're sorry, an error has occured preventing us from submitting your payment. You have not been charged." + "Text": "There was an error sending the receipt to your email address, $.Attributes.['Email']. Please contact customer support to receive a receipt for this transaction." }, - "Identifier": "Payment Submission Error", + "Identifier": "Receipt Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Remove Failed Payment Token", + "NextAction": "Redact Sensitive Contact Attributes", "Errors": [ { - "NextAction": "Remove Failed Payment Token", + "NextAction": "Redact Sensitive Contact Attributes", "ErrorType": "NoMatchingError" } ] @@ -1913,15 +1883,15 @@ }, { "Parameters": { - "Text": "There was a problem validating your $.Attributes.PaymentMethod information." + "Text": "We're sorry, an error has occurred that prevents us from collecting the payment." }, - "Identifier": "Payment Validation Error", + "Identifier": "Internal Error", "Type": "MessageParticipant", "Transitions": { - "NextAction": "Remove Failed Payment Token", + "NextAction": "Redact Sensitive Contact Attributes", "Errors": [ { - "NextAction": "Remove Failed Payment Token", + "NextAction": "Redact Sensitive Contact Attributes", "ErrorType": "NoMatchingError" } ] @@ -1951,11 +1921,51 @@ { "Parameters": { "Attributes": { - "PaymentToken": " " + "PaymentToken": "$.External.PaymentToken" + }, + "TargetContact": "Current" + }, + "Identifier": "Record Token", + "Type": "UpdateContactAttributes", + "Transitions": { + "NextAction": "Submit Payment", + "Errors": [ + { + "NextAction": "Submit Payment", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "LambdaFunctionARN": "<>", + "InvocationTimeLimitSeconds": "8", + "ResponseValidation": { + "ResponseType": "JSON" + } + }, + "Identifier": "Tokenize Transaction", + "Type": "InvokeLambdaFunction", + "Transitions": { + "NextAction": "Check for Tokenize Error", + "Errors": [ + { + "NextAction": "Payment Validation Error", + "ErrorType": "NoMatchingError" + } + ] + } + }, + { + "Parameters": { + "Attributes": { + "PaymentToken": "NULL", + "PaymentMethod": "NULL" }, "TargetContact": "Current" }, - "Identifier": "Remove Failed Payment Token", + "Identifier": "Remove Failed Payment Token and Method", "Type": "UpdateContactAttributes", "Transitions": { "NextAction": "Redact Sensitive Contact Attributes", @@ -1966,6 +1976,47 @@ } ] } + }, + { + "Parameters": { + "ComparisonValue": "$.External.Error" + }, + "Identifier": "Check for Tokenize Error", + "Type": "Compare", + "Transitions": { + "NextAction": "Speak Validation Error", + "Conditions": [ + { + "NextAction": "Record Token", + "Condition": { + "Operator": "Equals", + "Operands": ["NULL"] + } + } + ], + "Errors": [ + { + "NextAction": "Speak Validation Error", + "ErrorType": "NoMatchingCondition" + } + ] + } + }, + { + "Parameters": { + "Text": "The payment failed because of the following error:\n\n$.External.Error" + }, + "Identifier": "Speak Validation Error", + "Type": "MessageParticipant", + "Transitions": { + "NextAction": "Remove Failed Payment Token and Method", + "Errors": [ + { + "NextAction": "Remove Failed Payment Token and Method", + "ErrorType": "NoMatchingError" + } + ] + } } ], "Settings": { diff --git a/lib/features/agent-assisted-payment-ivr.ts b/lib/features/agent-assisted-payment-ivr.ts index ecdc221e..4c5ac0d0 100644 --- a/lib/features/agent-assisted-payment-ivr.ts +++ b/lib/features/agent-assisted-payment-ivr.ts @@ -13,7 +13,6 @@ import { Role, } from 'aws-cdk-lib/aws-iam'; import { Code, CodeSigningConfig, Function } from 'aws-cdk-lib/aws-lambda'; -import { existsSync, mkdirSync, writeFileSync } from 'fs'; import { join } from 'path'; import { @@ -22,7 +21,8 @@ import { } from '../helpers/lambda'; import { getSelfServicePaymentIVRFlowContent } from '../connect/content-transformations'; import { Secret } from 'aws-cdk-lib/aws-secretsmanager'; -import { AmazonConnectContext, C3Context } from '../models'; +import { AmazonConnectContext, C3Context, OptionsContext } from '../models'; +import { writeFileToExports } from '../helpers/file'; /** * Class for creating the necessary resources to facilitate agent-assisted payments collected through IVR. @@ -73,6 +73,9 @@ export class AgentAssistedPaymentIVR { // Create function. const c3Context = this.stack.node.tryGetContext('c3') as C3Context; + const optionsContext = this.stack.node.tryGetContext( + 'options', + ) as OptionsContext; this.sendAgentMessageFunction = new Function( this.stack, 'C3SendAgentMessage', @@ -87,7 +90,9 @@ export class AgentAssistedPaymentIVR { C3_BASE_URL: this.c3BaseUrl, C3_API_KEY_SECRET_ID: this.c3ApiKeySecret.secretName, }, - codeSigningConfig: this.codeSigningConfig, + codeSigningConfig: optionsContext.codeSigning + ? this.codeSigningConfig + : undefined, }, ); @@ -115,11 +120,8 @@ export class AgentAssistedPaymentIVR { this.amazonConnectContext.securityKeyId, this.amazonConnectContext.securityKeyCertificateContent, ); - if (!existsSync('./exports')) { - mkdirSync('./exports'); - } - writeFileSync( - './exports/C3AgentAssistedPaymentIVRFlow', + writeFileToExports( + 'C3AgentAssistedPaymentIVRFlow.json', c3PaymentFlowContent, ); this.ivrPaymentFlow = new CfnContactFlow( diff --git a/lib/features/self-service-payment-ivr.ts b/lib/features/self-service-payment-ivr.ts index 25e461f1..b4951b6a 100644 --- a/lib/features/self-service-payment-ivr.ts +++ b/lib/features/self-service-payment-ivr.ts @@ -1,9 +1,9 @@ import { Stack } from 'aws-cdk-lib'; import { getPaymentIVRFlowModuleContent } from '../connect/content-transformations'; import { CfnContactFlowModule } from 'aws-cdk-lib/aws-connect'; -import { existsSync, mkdirSync, writeFileSync } from 'fs'; import { Function } from 'aws-cdk-lib/aws-lambda'; import { AmazonConnectContext } from '../models'; +import { writeFileToExports } from '../helpers/file'; /** * Class for creating the necessary resources to facilitate self-service payments collected through IVR. @@ -41,11 +41,8 @@ export class SelfServicePaymentIVR { this.amazonConnectContext.securityKeyId, this.amazonConnectContext.securityKeyCertificateContent, ); - if (!existsSync('./exports')) { - mkdirSync('./exports'); - } - writeFileSync( - './exports/C3PaymentIVRFlowModule', + writeFileToExports( + 'C3PaymentIVRFlowModule.json', paymentIVRFlowModuleContent, ); new CfnContactFlowModule(this.stack, 'C3PaymentIVRFlowModule', { diff --git a/lib/features/subject-lookup.ts b/lib/features/subject-lookup.ts index 60f24373..65b799a8 100644 --- a/lib/features/subject-lookup.ts +++ b/lib/features/subject-lookup.ts @@ -6,7 +6,6 @@ import { CfnQuickConnect, } from 'aws-cdk-lib/aws-connect'; import { Code, CodeSigningConfig, Function } from 'aws-cdk-lib/aws-lambda'; -import { existsSync, mkdirSync, writeFileSync } from 'fs'; import { join } from 'path'; import { @@ -14,8 +13,10 @@ import { commonLambdaProps, } from '../helpers/lambda'; import { getSubjectLookupFlowContent } from '../connect/content-transformations'; -import { AmazonConnectContext } from '../models'; +import { AmazonConnectContext, OptionsContext } from '../models'; import { PolicyStatement } from 'aws-cdk-lib/aws-iam'; +import { writeFileToExports } from '../helpers/file'; +import { policyStatements } from '../lambda/subject-lookup-policy'; /** * Class for creating the necessary resources to facilitate subject lookup in agent-assisted payment scenarios. @@ -52,20 +53,30 @@ export class SubjectLookup { */ private createSubjectLookupFunction(): void { console.log('Creating function C3SubjectLookup...'); + const optionsContext = this.stack.node.tryGetContext( + 'options', + ) as OptionsContext; this.subjectLookupFunction = new Function(this.stack, 'C3SubjectLookup', { ...commonLambdaProps, description: 'Gets the details about a subject to pre-fill in the C3 workspace.', code: Code.fromAsset(join(__dirname, '../lambda/c3-subject-lookup')), - codeSigningConfig: this.codeSigningConfig, + codeSigningConfig: optionsContext.codeSigning + ? this.codeSigningConfig + : undefined, }); - // Update this with any additional permissions that the function needs for your subject lookup. - // const subjectLookupPolicy = new PolicyStatement({ - // actions: [], - // resources: [], - // }); - // this.subjectLookupFunction.addToRolePolicy(subjectLookupPolicy); + // Add any custom policy statements to the Lambda role. + for (const policyStatement of policyStatements) { + if ( + !policyStatement.actions?.length || + !policyStatement.resources?.length + ) { + continue; // Skip empty policy statements. + } + const subjectLookupPolicy = new PolicyStatement(policyStatement); + this.subjectLookupFunction.addToRolePolicy(subjectLookupPolicy); + } } /** @@ -95,10 +106,7 @@ export class SubjectLookup { this.subjectLookupFunction, this.sendAgentMessageFunction, ); - if (!existsSync('./exports')) { - mkdirSync('./exports'); - } - writeFileSync('./exports/C3SubjectLookupFlow', subjectLookupFlowContent); + writeFileToExports('C3SubjectLookupFlow.json', subjectLookupFlowContent); this.subjectLookupFlow = new CfnContactFlow( this.stack, 'C3SubjectLookupFlow', diff --git a/lib/helpers/file.ts b/lib/helpers/file.ts new file mode 100644 index 00000000..dc3f2135 --- /dev/null +++ b/lib/helpers/file.ts @@ -0,0 +1,16 @@ +import { existsSync, mkdirSync, writeFileSync } from 'fs'; + +/** + * Writes a file to the ./exports directory. + * + * @param fileName The name of the file to write (including extension). + * @param content The content to write to the file. + */ +export function writeFileToExports(fileName: string, content: string) { + // If the ./exports directory doesn't exist, create it. + if (!existsSync('./exports')) { + mkdirSync('./exports'); + } + + writeFileSync(`./exports/${fileName}`, content); +} diff --git a/lib/lambda/c3-create-payment-request/index.js b/lib/lambda/c3-create-payment-request/index.js index a31dbd88..4f3c882c 100644 --- a/lib/lambda/c3-create-payment-request/index.js +++ b/lib/lambda/c3-create-payment-request/index.js @@ -38,6 +38,13 @@ export async function handler(event) { } // Create the payment request. + const metadata = { + safeSelect: { + id: contactAttributes.SubjectId, + lookupBy: 'externalId', + customField: 'balance', + }, + }; const paymentRequestBody = { // Environment vendorId: process.env.C3_VENDOR_ID, @@ -57,6 +64,7 @@ export async function handler(event) { minimumPayment: contactAttributes.PaymentMinimumPayment, }, }, + metaData: JSON.stringify(metadata), }; const paymentRequestResponse = await fetch( diff --git a/lib/lambda/c3-subject-lookup/package-lock.json b/lib/lambda/c3-subject-lookup/package-lock.json index 693f8d1c..acbc6674 100644 --- a/lib/lambda/c3-subject-lookup/package-lock.json +++ b/lib/lambda/c3-subject-lookup/package-lock.json @@ -4,1194 +4,7 @@ "requires": true, "packages": { "": { - "name": "c3-subject-lookup", - "dependencies": { - "@aws-sdk/client-secrets-manager": "^3.624.0" - } - }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "dependencies": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-secrets-manager": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.624.0.tgz", - "integrity": "sha512-sW4eT+OVhfMTTB9Ke5tAz8/1gZmJ4G40z9Pvm4fJYRopIMIkHSeSQKTo5urX0APYZ3fdKs2Hxo22MKIZAO4kmw==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.624.0", - "@aws-sdk/client-sts": "3.624.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.624.0.tgz", - "integrity": "sha512-EX6EF+rJzMPC5dcdsu40xSi2To7GSvdGQNIpe97pD9WvZwM9tRNQnNM4T6HA4gjV1L6Jwk8rBlG/CnveXtLEMw==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.624.0.tgz", - "integrity": "sha512-Ki2uKYJKKtfHxxZsiMTOvJoVRP6b2pZ1u3rcUb2m/nVgBPUfLdl8ZkGpqE29I+t5/QaS/sEdbn6cgMUZwl+3Dg==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.624.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.624.0.tgz", - "integrity": "sha512-k36fLZCb2nfoV/DKK3jbRgO/Yf7/R80pgYfMiotkGjnZwDmRvNN08z4l06L9C+CieazzkgRxNUzyppsYcYsQaw==", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.624.0", - "@aws-sdk/core": "3.624.0", - "@aws-sdk/credential-provider-node": "3.624.0", - "@aws-sdk/middleware-host-header": "3.620.0", - "@aws-sdk/middleware-logger": "3.609.0", - "@aws-sdk/middleware-recursion-detection": "3.620.0", - "@aws-sdk/middleware-user-agent": "3.620.0", - "@aws-sdk/region-config-resolver": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@aws-sdk/util-user-agent-browser": "3.609.0", - "@aws-sdk/util-user-agent-node": "3.614.0", - "@smithy/config-resolver": "^3.0.5", - "@smithy/core": "^2.3.2", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/hash-node": "^3.0.3", - "@smithy/invalid-dependency": "^3.0.3", - "@smithy/middleware-content-length": "^3.0.5", - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.14", - "@smithy/util-defaults-mode-node": "^3.0.14", - "@smithy/util-endpoints": "^2.0.5", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.624.0.tgz", - "integrity": "sha512-WyFmPbhRIvtWi7hBp8uSFy+iPpj8ccNV/eX86hwF4irMjfc/FtsGVIAeBXxXM/vGCjkdfEzOnl+tJ2XACD4OXg==", - "dependencies": { - "@smithy/core": "^2.3.2", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/signature-v4": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", - "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.622.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", - "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.624.0.tgz", - "integrity": "sha512-mMoNIy7MO2WTBbdqMyLpbt6SZpthE6e0GkRYpsd0yozPt0RZopcBhEh+HG1U9Y1PVODo+jcMk353vAi61CfnhQ==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.624.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.624.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.624.0.tgz", - "integrity": "sha512-vYyGK7oNpd81BdbH5IlmQ6zfaQqU+rPwsKTDDBeLRjshtrGXOEpfoahVpG9PX0ibu32IOWp4ZyXBNyVrnvcMOw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.620.1", - "@aws-sdk/credential-provider-http": "3.622.0", - "@aws-sdk/credential-provider-ini": "3.624.0", - "@aws-sdk/credential-provider-process": "3.620.1", - "@aws-sdk/credential-provider-sso": "3.624.0", - "@aws-sdk/credential-provider-web-identity": "3.621.0", - "@aws-sdk/types": "3.609.0", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.620.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", - "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.624.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.624.0.tgz", - "integrity": "sha512-A02bayIjU9APEPKr3HudrFHEx0WfghoSPsPopckDkW7VBqO4wizzcxr75Q9A3vNX+cwg0wCN6UitTNe6pVlRaQ==", - "dependencies": { - "@aws-sdk/client-sso": "3.624.0", - "@aws-sdk/token-providers": "3.614.0", - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.621.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", - "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.621.0" - } - }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", - "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", - "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", - "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.620.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", - "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@aws-sdk/util-endpoints": "3.614.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", - "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", - "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.614.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", - "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", - "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "@smithy/util-endpoints": "^2.0.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.568.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.568.0.tgz", - "integrity": "sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.609.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", - "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/types": "^3.3.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.614.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", - "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", - "dependencies": { - "@aws-sdk/types": "3.609.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@smithy/abort-controller": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", - "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", - "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", - "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", - "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", - "dependencies": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.14", - "@smithy/middleware-serde": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.0.tgz", - "integrity": "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==", - "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", - "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", - "dependencies": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/hash-node": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", - "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", - "dependencies": { - "@smithy/types": "^3.3.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/invalid-dependency": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", - "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", - "integrity": "sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==", - "dependencies": { - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-endpoint": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", - "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", - "dependencies": { - "@smithy/middleware-serde": "^3.0.3", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/url-parser": "^3.0.3", - "@smithy/util-middleware": "^3.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-retry": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", - "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", - "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/protocol-http": "^4.1.0", - "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-retry": "^3.0.3", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-serde": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", - "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-stack": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", - "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-config-provider": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", - "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", - "dependencies": { - "@smithy/property-provider": "^3.1.3", - "@smithy/shared-ini-file-loader": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", - "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", - "dependencies": { - "@smithy/abort-controller": "^3.1.1", - "@smithy/protocol-http": "^4.1.0", - "@smithy/querystring-builder": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/property-provider": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", - "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/protocol-http": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", - "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/querystring-builder": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", - "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", - "dependencies": { - "@smithy/types": "^3.3.0", - "@smithy/util-uri-escape": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/querystring-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", - "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/service-error-classification": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", - "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", - "dependencies": { - "@smithy/types": "^3.3.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/shared-ini-file-loader": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", - "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.1.0.tgz", - "integrity": "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.3", - "@smithy/util-uri-escape": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/smithy-client": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", - "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", - "dependencies": { - "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-stack": "^3.0.3", - "@smithy/protocol-http": "^4.1.0", - "@smithy/types": "^3.3.0", - "@smithy/util-stream": "^3.1.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", - "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/url-parser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", - "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", - "dependencies": { - "@smithy/querystring-parser": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-body-length-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", - "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/util-body-length-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", - "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", - "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", - "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", - "dependencies": { - "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", - "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", - "dependencies": { - "@smithy/config-resolver": "^3.0.5", - "@smithy/credential-provider-imds": "^3.2.0", - "@smithy/node-config-provider": "^3.1.4", - "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.12", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-endpoints": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", - "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", - "dependencies": { - "@smithy/node-config-provider": "^3.1.4", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-middleware": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", - "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", - "dependencies": { - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-retry": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", - "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", - "dependencies": { - "@smithy/service-error-classification": "^3.0.3", - "@smithy/types": "^3.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-stream": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", - "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", - "dependencies": { - "@smithy/fetch-http-handler": "^3.2.4", - "@smithy/node-http-handler": "^3.1.4", - "@smithy/types": "^3.3.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/bowser": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" - }, - "node_modules/fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - }, - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - } - ], - "dependencies": { - "strnum": "^1.0.5" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/strnum": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" - }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } + "name": "c3-subject-lookup" } } } diff --git a/lib/lambda/c3-subject-lookup/package.json b/lib/lambda/c3-subject-lookup/package.json index b5962a0d..33cc08ce 100644 --- a/lib/lambda/c3-subject-lookup/package.json +++ b/lib/lambda/c3-subject-lookup/package.json @@ -7,7 +7,5 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, - "dependencies": { - "@aws-sdk/client-secrets-manager": "^3.624.0" - } + "dependencies": {} } diff --git a/lib/lambda/c3-tokenize-transaction/gateways/zift.js b/lib/lambda/c3-tokenize-transaction/gateways/zift.js index 2db35b30..5262f4dc 100644 --- a/lib/lambda/c3-tokenize-transaction/gateways/zift.js +++ b/lib/lambda/c3-tokenize-transaction/gateways/zift.js @@ -2,6 +2,7 @@ import { GetSecretValueCommand, SecretsManagerClient, } from '@aws-sdk/client-secrets-manager'; +import { TokenizeErrors } from '../tokenize-errors.js'; const ZIFT_URL = process.env.C3_ENV === 'prod' @@ -78,7 +79,12 @@ export class Zift { throw new Error(response.statusText); } else if (jsonBody.responseType === 'exception') { console.error('Exception from Zift:', jsonBody.responseMessage); - throw new Error(jsonBody.responseMessage); + const normalizedErrorMessage = this.#normalizeErrorMessage( + jsonBody.responseMessage, + paymentMethod, + ); + console.debug('Normalized error message:', normalizedErrorMessage); + throw new Error(normalizedErrorMessage); } else if (!jsonBody.token) { console.error('No token from Zift:', body); throw new Error('No token from Zift'); @@ -129,4 +135,27 @@ export class Zift { ); } } + + /** + * Attempts to map the error message from Zift to a more user-friendly error message. + * + * @param {string} message The error message from Zift. + * @param {'Card' | 'Bank'} paymentMethod The payment method. Either 'Card' or 'Bank'. + * @returns + */ + #normalizeErrorMessage(message, paymentMethod) { + switch (message) { + case 'accountNumber is invalid.': + return paymentMethod === 'Card' + ? TokenizeErrors.InvalidCardNumber + : TokenizeErrors.InvalidAccountNumber; + case 'accountAccessory is not well-formatted.': + return paymentMethod === 'Card' + ? TokenizeErrors.InvalidExpirationDate + : TokenizeErrors.InvalidRoutingNumber; + default: + // Return the Zift message for any other scenario. + return message; + } + } } diff --git a/lib/lambda/c3-tokenize-transaction/index.js b/lib/lambda/c3-tokenize-transaction/index.js index 6a9debd8..dd16226d 100644 --- a/lib/lambda/c3-tokenize-transaction/index.js +++ b/lib/lambda/c3-tokenize-transaction/index.js @@ -102,25 +102,33 @@ export async function handler(event) { const decryptedData = await decryptData(encryptedData, keyring); console.log('Successfully decrypted data.'); - // Tokenize the payment information. - const paymentGateway = new PaymentGateway(process.env.C3_PAYMENT_GATEWAY); - let paymentToken; - console.log('Tokenizing payment information...'); - if (paymentMethod === 'Card') { - paymentToken = await paymentGateway.tokenizeCard( - decryptedData, - expirationDate, - ); - } else { - paymentToken = await paymentGateway.tokenizeBankAccount( - decryptedData, - routingNumber, - ); + try { + // Tokenize the payment information. + const paymentGateway = new PaymentGateway(process.env.C3_PAYMENT_GATEWAY); + let paymentToken; + console.log('Tokenizing payment information...'); + if (paymentMethod === 'Card') { + paymentToken = await paymentGateway.tokenizeCard( + decryptedData, + expirationDate, + ); + } else { + paymentToken = await paymentGateway.tokenizeBankAccount( + decryptedData, + routingNumber, + ); + } + return { + PaymentToken: paymentToken, + Error: 'NULL', + }; + } catch (tokenizeError) { + // Return the error message to the flow. + return { + PaymentToken: 'NULL', + Error: tokenizeError.message, + }; } - - return { - PaymentToken: paymentToken, - }; } /** diff --git a/lib/lambda/c3-tokenize-transaction/tokenize-errors.js b/lib/lambda/c3-tokenize-transaction/tokenize-errors.js new file mode 100644 index 00000000..d7f655db --- /dev/null +++ b/lib/lambda/c3-tokenize-transaction/tokenize-errors.js @@ -0,0 +1,12 @@ +/** + * The standard errors that can occur during tokenization. + */ +export const TokenizeErrors = { + InsufficientFunds: 'InsufficientFunds', + + InvalidAccountNumber: 'InvalidAccountNumber', + InvalidRoutingNumber: 'InvalidRoutingNumber', + + InvalidCardNumber: 'InvalidCardNumber', + InvalidExpirationDate: 'InvalidExpirationDate', +}; diff --git a/lib/lambda/subject-lookup-policy.ts b/lib/lambda/subject-lookup-policy.ts new file mode 100644 index 00000000..94fc23e4 --- /dev/null +++ b/lib/lambda/subject-lookup-policy.ts @@ -0,0 +1,15 @@ +import { PolicyStatementProps } from 'aws-cdk-lib/aws-iam'; + +/** + * IAM policy statements for the subject lookup Lambda function. + */ +export const policyStatements: PolicyStatementProps[] = [ + { + actions: [ + // Add any actions required for your subject lookup here. + ], + resources: [ + // Add any resources required for your subject lookup here. + ], + }, +]; diff --git a/lib/models/amazon-connect-context.ts b/lib/models/amazon-connect-context.ts index 5b8ed3ea..ed8fe440 100644 --- a/lib/models/amazon-connect-context.ts +++ b/lib/models/amazon-connect-context.ts @@ -2,6 +2,7 @@ export interface AmazonConnectContext { instanceArn: string; securityKeyId: string; securityKeyCertificateContent: string; + workspaceApp: boolean; } /** diff --git a/lib/models/context.ts b/lib/models/context.ts index 9eaaa7f5..6f38a2d2 100644 --- a/lib/models/context.ts +++ b/lib/models/context.ts @@ -1,6 +1,7 @@ import { AmazonConnectContext } from './amazon-connect-context'; import { C3Context } from './c3-context'; import { FeaturesContext } from './features-context'; +import { OptionsContext } from './options-context'; export interface Context { stackLabel: string; @@ -10,4 +11,5 @@ export interface Context { supportPhone: string; supportEmail: string; features: FeaturesContext; + options: OptionsContext; } diff --git a/lib/models/index.ts b/lib/models/index.ts index b1332c55..36e77e56 100644 --- a/lib/models/index.ts +++ b/lib/models/index.ts @@ -3,3 +3,4 @@ export * from './amazon-connect-context'; export * from './c3-context'; export * from './context'; export * from './features-context'; +export * from './options-context'; diff --git a/lib/models/options-context.ts b/lib/models/options-context.ts new file mode 100644 index 00000000..921b7b78 --- /dev/null +++ b/lib/models/options-context.ts @@ -0,0 +1,14 @@ +export interface OptionsContext { + codeSigning: boolean; +} + +/** + * Validates the options context variables. Throws an error if any of the required variables are missing. + * + * @param optionsContext The options context variables. + */ +export function validateOptionsContext(optionsContext: OptionsContext): void { + if (!optionsContext) { + throw new Error('Option context variables are required.'); + } +} diff --git a/package.json b/package.json index 154bba0f..4b157b37 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,9 @@ "watch": "tsc -w", "test": "jest", "cdk": "cdk", - "synth": "npm ci && npm run build && cdk synth", - "deploy": "npm ci && npm run build && cdk deploy", + "synth": "npm ci && npm run build && cdk synth && npm run display-url", + "deploy": "npm ci && npm run build && cdk deploy && npm run display-url", + "display-url": "echo \"$(<./exports/C3WorkspaceAppUrl.txt )\"", "insert-placeholders": "npm run style:fix && ./scripts/insert-placeholders.sh", "postinstall": "npm --prefix ./lib/lambda/c3-create-payment-request ci && npm --prefix ./lib/lambda/c3-email-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", "prepare": "husky" diff --git a/test/c3-amazon-connect.test.ts b/test/c3-amazon-connect.test.ts index 82624cba..fb0cb457 100644 --- a/test/c3-amazon-connect.test.ts +++ b/test/c3-amazon-connect.test.ts @@ -15,6 +15,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', + workspaceApp: true, }, c3: { env: C3Environment.Prod, @@ -27,6 +28,9 @@ const mockContext: Context = { selfServiceIVR: true, subjectLookup: SubjectLookupMode.RequiredEditable, }, + options: { + codeSigning: true, + }, logoUrl: 'placeholder', supportPhone: 'placeholder', supportEmail: 'placeholder', diff --git a/test/features/agent-assisted-ivr.test.ts b/test/features/agent-assisted-ivr.test.ts index a3498ff9..a08208d0 100644 --- a/test/features/agent-assisted-ivr.test.ts +++ b/test/features/agent-assisted-ivr.test.ts @@ -15,6 +15,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', + workspaceApp: true, }, c3: { env: C3Environment.Prod, @@ -27,6 +28,9 @@ const mockContext: Context = { selfServiceIVR: false, subjectLookup: SubjectLookupMode.Disabled, }, + options: { + codeSigning: true, + }, logoUrl: 'placeholder', supportPhone: 'placeholder', supportEmail: 'placeholder', diff --git a/test/features/agent-assisted-link.test.ts b/test/features/agent-assisted-link.test.ts index 98c6361c..e713b87e 100644 --- a/test/features/agent-assisted-link.test.ts +++ b/test/features/agent-assisted-link.test.ts @@ -15,6 +15,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', + workspaceApp: true, }, c3: { env: C3Environment.Prod, @@ -27,6 +28,9 @@ const mockContext: Context = { selfServiceIVR: false, subjectLookup: SubjectLookupMode.Disabled, }, + options: { + codeSigning: true, + }, logoUrl: 'placeholder', supportPhone: 'placeholder', supportEmail: 'placeholder', diff --git a/test/features/self-service-ivr.test.ts b/test/features/self-service-ivr.test.ts index dfb3decb..7412aef6 100644 --- a/test/features/self-service-ivr.test.ts +++ b/test/features/self-service-ivr.test.ts @@ -15,6 +15,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', + workspaceApp: true, }, c3: { env: C3Environment.Prod, @@ -27,6 +28,9 @@ const mockContext: Context = { selfServiceIVR: true, subjectLookup: SubjectLookupMode.Disabled, }, + options: { + codeSigning: true, + }, logoUrl: 'placeholder', supportPhone: 'placeholder', supportEmail: 'placeholder', diff --git a/test/features/subject-lookup.test.ts b/test/features/subject-lookup.test.ts index 10332d25..a2906565 100644 --- a/test/features/subject-lookup.test.ts +++ b/test/features/subject-lookup.test.ts @@ -15,6 +15,7 @@ const mockContext: Context = { securityKeyId: 'placeholder', securityKeyCertificateContent: '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', + workspaceApp: true, }, c3: { env: C3Environment.Prod, @@ -27,6 +28,9 @@ const mockContext: Context = { selfServiceIVR: false, subjectLookup: SubjectLookupMode.OptionalEditable, }, + options: { + codeSigning: true, + }, logoUrl: 'placeholder', supportPhone: 'placeholder', supportEmail: 'placeholder', diff --git a/test/options/code-signing.test.ts b/test/options/code-signing.test.ts new file mode 100644 index 00000000..a8f85790 --- /dev/null +++ b/test/options/code-signing.test.ts @@ -0,0 +1,63 @@ +import { App } from 'aws-cdk-lib'; +import { C3AmazonConnectStack } from '../../lib/c3-amazon-connect-stack'; +import { Template } from 'aws-cdk-lib/assertions'; +import { + C3Environment, + C3PaymentGateway, + Context, + SubjectLookupMode, +} from '../../lib/models'; + +const mockContext: Context = { + stackLabel: 'dev', + amazonConnect: { + instanceArn: 'placeholder', + securityKeyId: 'placeholder', + securityKeyCertificateContent: + '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', + workspaceApp: true, + }, + c3: { + env: C3Environment.Prod, + vendorId: 'placeholder', + paymentGateway: C3PaymentGateway.Zift, + }, + features: { + agentAssistedIVR: true, + agentAssistedLink: true, + selfServiceIVR: true, + subjectLookup: SubjectLookupMode.RequiredEditable, + }, + options: { + codeSigning: false, + }, + logoUrl: 'placeholder', + supportPhone: 'placeholder', + supportEmail: 'placeholder', +}; + +describe('C3AmazonConnectStack', () => { + const app = new App({ + context: mockContext, + }); + const stack = new C3AmazonConnectStack(app, 'MyTestStack'); + const template = Template.fromStack(stack); + + // Lambda functions + describe('Lambda functions', () => { + it('Has code signing disabled', () => { + template.resourcePropertiesCountIs( + 'AWS::Lambda::Function', + { + CodeSigningConfigArn: { + 'Fn::GetAtt': [ + 'C3CodeSigningConfigFA211695', // FIXME: This identifier at the end always changes + 'CodeSigningConfigArn', + ], + }, + }, + 0, + ); + }); + }); +}); diff --git a/test/options/workspace-app.test.ts b/test/options/workspace-app.test.ts new file mode 100644 index 00000000..7459a063 --- /dev/null +++ b/test/options/workspace-app.test.ts @@ -0,0 +1,73 @@ +import { App } from 'aws-cdk-lib'; +import { C3AmazonConnectStack } from '../../lib/c3-amazon-connect-stack'; +import { Template } from 'aws-cdk-lib/assertions'; +import { + C3Environment, + C3PaymentGateway, + Context, + SubjectLookupMode, +} from '../../lib/models'; + +const mockContext: Context = { + stackLabel: 'dev', + amazonConnect: { + instanceArn: 'placeholder', + securityKeyId: 'placeholder', + securityKeyCertificateContent: + '-----BEGIN CERTIFICATE-----\\n-----END CERTIFICATE-----\\n', + workspaceApp: true, + }, + c3: { + env: C3Environment.Prod, + vendorId: 'placeholder', + paymentGateway: C3PaymentGateway.Zift, + }, + features: { + agentAssistedIVR: true, + agentAssistedLink: false, + selfServiceIVR: false, + subjectLookup: SubjectLookupMode.Disabled, + }, + options: { + codeSigning: true, + }, + logoUrl: 'placeholder', + supportPhone: 'placeholder', + supportEmail: 'placeholder', +}; + +const NUMBER_OF_LAMBDAS = 5; + +// Verify created resources for agent-assisted IVR. +describe('Workspace app', () => { + // 3rd party apps + describe('3rd party apps', () => { + it('Has 1 3rd party app when flag is true', () => { + const app = new App({ + context: mockContext, + }); + const stack = new C3AmazonConnectStack(app, 'MyTestStack'); + const template = Template.fromStack(stack); + + // template.resourceCountIs('AWS::Connect::Application', 1); + template.resourceCountIs( + 'AWS::Connect::IntegrationAssociation', + NUMBER_OF_LAMBDAS + 1, + ); + }); + + it('Has no 3rd party apps when flag is false', () => { + mockContext.amazonConnect.workspaceApp = false; + const app = new App({ + context: mockContext, + }); + const stack = new C3AmazonConnectStack(app, 'MyTestStack'); + const template = Template.fromStack(stack); + // template.resourceCountIs('AWS::Connect::Application', 0); + template.resourceCountIs( + 'AWS::Connect::IntegrationAssociation', + NUMBER_OF_LAMBDAS, + ); + }); + }); +});