Skip to content

Commit

Permalink
Merge pull request #7144 from SalesforceFoundation/feature/242__bgeWi…
Browse files Browse the repository at this point in the history
…dgetFixedValidations

Add a Validation to Prevent a Gift Entry User from Choosing the "Fixed" schedule recurring type for Elevate Recurring Gifts in Batch Gift Entry
  • Loading branch information
lparrott authored Nov 14, 2022
2 parents 3127098 + e4b4487 commit c7fd563
Show file tree
Hide file tree
Showing 13 changed files with 382 additions and 101 deletions.
4 changes: 3 additions & 1 deletion force-app/main/default/classes/ElevateBatchItem.cls
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public with sharing class ElevateBatchItem {
@AuraEnabled public String elevateBatchId {get; set;}
@AuraEnabled public String declineReason {get; set;}
@AuraEnabled public String cardLast4 {get; set;}
@AuraEnabled public String achLast4 {get; set;}
@AuraEnabled public String cardNetwork {get; set;}
@AuraEnabled public String cardExpirationMonth {get; set;}
@AuraEnabled public String cardExpirationYear {get; set;}
Expand All @@ -59,7 +60,8 @@ public with sharing class ElevateBatchItem {
this.elevateBatchId = createBatchItemResponse.elevateBatchId();
this.originalTransactionId = createBatchItemResponse.originalTransactionId();
this.declineReason = createBatchItemResponse.declineReason();
this.cardLast4 = createBatchItemResponse.last4();
this.cardLast4 = createBatchItemResponse.cardLast4();
this.achLast4 = createBatchItemResponse.achLast4();
this.status = createBatchItemResponse.status();
this.statusReason = createBatchItemResponse.statusReason();
this.cardNetwork = createBatchItemResponse.brand();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,14 @@ public class ElevateBatchItemCreateResponse {
return purchaseResponse?.authExpiresAt;
}

public String last4() {
public String cardLast4() {
return commitmentResponse != null ? commitmentResponse.cardData?.last4 : purchaseResponse.cardData?.last4;
}

public String achLast4() {
return commitmentResponse != null ? commitmentResponse.achData?.last4 : purchaseResponse.achData?.last4;
}

public String brand() {
return commitmentResponse != null ? commitmentResponse.cardData?.brand : purchaseResponse.cardData?.brand;
}
Expand Down
7 changes: 5 additions & 2 deletions force-app/main/default/lwc/geConstants/geConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ const CLICKED_DOWN = 'clicked-down';
const DOWN = 'down';
const UP = 'up';

const DEFAULT_NAME_ON_CARD = '[Not Provided]'
const DEFAULT_NAME_ON_CARD = '[Not Provided]';

const RECURRING_TYPE_FIXED = 'Fixed';

export {
COMMITMENT_INACTIVE_STATUS,
Expand All @@ -77,5 +79,6 @@ export {
CLICKED_DOWN,
DOWN,
UP,
DEFAULT_NAME_ON_CARD
DEFAULT_NAME_ON_CARD,
RECURRING_TYPE_FIXED
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import GeFormRenderer from 'c/geFormRenderer';
import GeLabelService from 'c/geLabelService';
import Settings from 'c/geSettings';
import GeGatewaySettings from 'c/geGatewaySettings';
const pubSub = require('c/pubsubNoPageRef');

import upsertDataImport from '@salesforce/apex/GE_GiftEntryController.upsertDataImport';
import retrieveDefaultSGERenderWrapper from '@salesforce/apex/GE_GiftEntryController.retrieveDefaultSGERenderWrapper';
Expand All @@ -15,9 +16,6 @@ import { mockCheckInputValidity } from 'lightning/input';
import { mockCheckComboboxValidity } from 'lightning/combobox';
import { mockGetIframeReply } from 'c/psElevateTokenHandler';

import donationImported from '@salesforce/schema/DataImport__c.DonationImported__c';
import { DEFAULT_FORM_FIELDS } from '../../utilTemplateBuilder/utilTemplateBuilder';

const mockWrapperWithNoNames = require('../../../../../../tests/__mocks__/apex/data/retrieveDefaultSGERenderWrapper.json');
const getRecordContact1Imported = require('./data/getRecordContact1Imported.json');
const dataImportObjectInfo = require('../../../../../../tests/__mocks__/apex/data/dataImportObjectDescribeInfo.json');
Expand All @@ -32,56 +30,6 @@ describe('c-ge-form-renderer', () => {
});

describe('render behavior', () => {
it('renders make recurring button, when in batch mode and feature is enabled', async () => {
retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);
const element = createElement('c-ge-form-renderer', {is: GeFormRenderer });

const DUMMY_BATCH_ID = 'a0T11000007F8WQEA0';

element.batchId = DUMMY_BATCH_ID;
document.body.appendChild(element);
await flushPromises();

// simulate getting back data for DUMMY_CONTACT_ID
getRecord.emit(dataImportBatchRecord, config => {
return config.recordId === DUMMY_BATCH_ID;
});

await flushPromises();

const button = element.shadowRoot.querySelectorAll('[data-id="recurringButton"]');
expect(button).toHaveLength(1);
});

it('make recurring button is disabled when imported gift is loaded into the form', async() => {
retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);
const element = createElement('c-ge-form-renderer', {is: GeFormRenderer });

const DUMMY_BATCH_ID = 'a0T11000007F8WQEA0';

element.batchId = DUMMY_BATCH_ID;
document.body.appendChild(element);
await flushPromises();

// simulate getting back data for DUMMY_CONTACT_ID
getRecord.emit(dataImportBatchRecord, config => {
return config.recordId === DUMMY_BATCH_ID;
});

await flushPromises();

const button = element.shadowRoot.querySelectorAll('[data-id="recurringButton"]');
expect(button).toHaveLength(1);

element.isMakeRecurringButtonDisabled = true;
await flushPromises();

const disabledButton = element.shadowRoot.querySelectorAll('[data-id="recurringButton"]');
expect(disabledButton[0].disabled).toBe(true);
});

it('when a form is saved with a possible validation rule error then processing of the donation should be halted',
async () => {

Expand Down Expand Up @@ -147,6 +95,178 @@ describe('c-ge-form-renderer', () => {
const spinner = element.shadowRoot.querySelector('lightning-spinner');
expect(spinner).toBeFalsy();
});
it('make recurring button is disabled when imported gift is loaded into the form', async() => {
retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);
const element = createElement('c-ge-form-renderer', {is: GeFormRenderer });

const DUMMY_BATCH_ID = 'a0T11000007F8WQEA0';

element.batchId = DUMMY_BATCH_ID;
document.body.appendChild(element);
await flushPromises();

// simulate getting back data for DUMMY_CONTACT_ID
getRecord.emit(dataImportBatchRecord, config => {
return config.recordId === DUMMY_BATCH_ID;
});

await flushPromises();

const button = element.shadowRoot.querySelectorAll('[data-id="recurringButton"]');
expect(button).toHaveLength(1);

element.isMakeRecurringButtonDisabled = true;
await flushPromises();

const disabledButton = element.shadowRoot.querySelectorAll('[data-id="recurringButton"]');
expect(disabledButton[0].disabled).toBe(true);
});

it('save button is not disabled when schedule recurring type is Fixed for non-Elevate RD', async() => {
retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);

const element = createElement('c-ge-form-renderer', {is: GeFormRenderer });
element.batchId = 'DUMMY_BATCH_ID';

Settings.isElevateCustomer = jest.fn(() => true);
element.Settings = Settings;

GeGatewaySettings.isValidElevatePaymentMethod = jest.fn(() => false);
element.GeGatewaySettings = GeGatewaySettings;

document.body.appendChild(element);
await flushPromises();

element.giftInView = {
fields: {
'Recurring_Donation_Recurring_Type__c': 'Fixed',
'Payment_Method__c': 'Credit Card'
}
};
await flushPromises();

const saveButton = element.shadowRoot.querySelector('[data-id="bgeSaveButton"]');
expect(saveButton.disabled).toBeFalsy();
});

it('save button is disabled when schedule recurring type is Fixed for Elevate RD and widget is present and not disabled', async() => {
retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);

const element = createElement('c-ge-form-renderer', {is: GeFormRenderer });
element.batchId = 'DUMMY_BATCH_ID';

Settings.isElevateCustomer = jest.fn(() => true);
element.Settings = Settings;

GeGatewaySettings.isValidElevatePaymentMethod = jest.fn(() => true);
element.GeGatewaySettings = GeGatewaySettings;

element.hasPaymentWidget = true;

document.body.appendChild(element);
await flushPromises();

element.giftInView = {
fields: {
'Recurring_Donation_Recurring_Type__c': 'Fixed',
'Payment_Method__c': 'Credit Card',
'Recurring_Donation_Elevate_Recurring_ID__c': 'DUMMY_RECURRING_ID'
}
};
await flushPromises();

const saveButton = element.shadowRoot.querySelector('[data-id="bgeSaveButton"]');
expect(saveButton.disabled).toBeTruthy();
});

it('save button is not disabled when schedule recurring type is Fixed for Elevate RD and widget is disabled.', async() => {
retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);

const element = createElement('c-ge-form-renderer', {is: GeFormRenderer });
element.batchId = 'DUMMY_BATCH_ID';

Settings.isElevateCustomer = jest.fn(() => true);
element.Settings = Settings;

GeGatewaySettings.isValidElevatePaymentMethod = jest.fn(() => true);
element.GeGatewaySettings = GeGatewaySettings;

element.hasPaymentWidget = true;

document.body.appendChild(element);
await flushPromises();

element.giftInView = {
fields: {
'Recurring_Donation_Recurring_Type__c': 'Fixed',
'Payment_Method__c': 'Credit Card'
}
};
await flushPromises();

pubSub.fireEvent({}, 'doNotChargeState', {isElevateWidgetDisabled: true});
await flushPromises();

const saveButton = element.shadowRoot.querySelector('[data-id="bgeSaveButton"]');
expect(saveButton.disabled).toBeFalsy();
});

it('save button is not disabled when schedule recurring type is Fixed for Elevate RD and widget is not on the form.', async() => {
retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);

const element = createElement('c-ge-form-renderer', {is: GeFormRenderer });
element.batchId = 'DUMMY_BATCH_ID';

Settings.isElevateCustomer = jest.fn(() => true);
element.Settings = Settings;

GeGatewaySettings.isValidElevatePaymentMethod = jest.fn(() => true);
element.GeGatewaySettings = GeGatewaySettings;

element.hasPaymentWidget = false;

document.body.appendChild(element);
await flushPromises();

element.giftInView = {
fields: {
'Recurring_Donation_Recurring_Type__c': 'Fixed',
'Payment_Method__c': 'Credit Card'
}
};
await flushPromises();

const saveButton = element.shadowRoot.querySelector('[data-id="bgeSaveButton"]');
expect(saveButton.disabled).toBeFalsy();
});

it('renders make recurring button, when in batch mode and feature is enabled', async () => {
retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);
const element = createElement('c-ge-form-renderer', {is: GeFormRenderer });

const DUMMY_BATCH_ID = 'a0T11000007F8WQEA0';

document.body.appendChild(element);
await flushPromises();

// simulate getting back data for DUMMY_CONTACT_ID
element.batchId = DUMMY_BATCH_ID;
await flushPromises();

getRecord.emit(dataImportBatchRecord, config => {
return config.recordId === DUMMY_BATCH_ID;
});
await flushPromises();

const button = element.shadowRoot.querySelectorAll('[data-id="recurringButton"]');
expect(button).toHaveLength(1);
});

it('does not render make recurring button, when in batch mode and feature is disabled', async () => {
retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
Expand Down Expand Up @@ -268,7 +388,6 @@ describe('c-ge-form-renderer', () => {
expect(sections).toHaveLength(4);
});


it('form when saving without filling anything in should result in a page level error for missing fields', async () => {
retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
// This error is specific to this mockRenderWrapperWithNoNames
Expand Down
7 changes: 3 additions & 4 deletions force-app/main/default/lwc/geFormRenderer/geFormRenderer.html
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
horizontal-align='center'
if:false={isPermissionError}>
<lightning-layout-item size='12'
if:true={showPaymentSaveNotice}>
if:true={isWidgetEnabled}>
<p class='slds-align_absolute-center slds-p-top_small'>
{CUSTOM_LABELS.geTextPaymentsSaveNotice}
</p>
Expand All @@ -148,7 +148,6 @@
title={saveActionLabel}
onclick={handleSave}
class='slds-m-left_x-small'
disabled={isUpdateActionDisabled}
data-qa-locator={qaLocatorSaveButton}>
</lightning-button>
</div>
Expand Down Expand Up @@ -227,7 +226,7 @@
horizontal-align='center'
if:false={isPermissionError}>
<lightning-layout-item size='12'
if:true={showPaymentSaveNotice}>
if:true={isWidgetEnabled}>
<p class='slds-align_absolute-center slds-p-top_small'>
{CUSTOM_LABELS.geTextPaymentsSaveNotice}
</p>
Expand All @@ -247,7 +246,7 @@
class='slds-m-left_x-small'
disabled={isUpdateActionDisabled}
data-qa-locator={qaLocatorSaveButton}
data-id="formSaveButton">
data-id="bgeSaveButton">
</lightning-button>
</div>
</lightning-layout-item>
Expand Down
Loading

0 comments on commit c7fd563

Please sign in to comment.