SSR-1064 payment method updates

This commit is contained in:
Matt Caimi 2024-02-08 11:12:18 -05:00
parent aefadce025
commit 553e6c03f6
7 changed files with 154 additions and 137 deletions

View file

@ -1,7 +1,9 @@
export const paymentMethods = {
const paymentMethods = Object.freeze({
NONE: null,
LATER: 'Later',
PAY_AT_TIME_OF_SERVICE: 'PayAtTimeOfService',
CREDIT_CARD: 'CreditCard',
PAYPAL: 'Paypal',
AFTERPAY: 'Afterpay'
};
});
export default paymentMethods;

View file

@ -3,37 +3,34 @@ import { getMountOptions } from '@/helpers/unit-test-helper.js';
import paymentMethodQuestion from '@/layouts/payment-method/payment-method-question/payment-method-question.vue';
const testConstants = {
cms: {
question: {
text: 'Choose a payment option'
},
answers: {
optionA: {
name: 'NameA',
text: 'TextA',
subText: 'SubTextA',
imageId: 'idA',
image: 'imageA',
subWidget: 'subWidgetA'
},
optionB: {
name: 'NameB',
text: 'TextB',
subText: 'SubTextB',
imageId: 'idB',
image: 'imageB',
subWidget: 'subWidgetB'
}
}
}
};
let cmsContent;
const mockCmsContent = {
QuestionText: 'Choose a payment option',
Answers: [
{
Name: 'NameA',
Text: 'TextA',
SubText: 'SubTextA',
ImageId: 'idA',
AnswerImageUrl: 'imageA',
SubWidgetName: 'subWidgetA'
},
{
Name: 'NameB',
Text: 'TextB',
SubText: 'SubTextB',
ImageId: 'idB',
AnswerImageUrl: 'imageB',
SubWidgetName: 'subWidgetB'
}
]
};
function generateDefaultProps() {
return {
modelValue: 'modelValue'
modelValue: 'modelValue',
cmsWidgetName: 'PaymentMethodWidget'
};
}
@ -42,7 +39,7 @@ function setupMocks(customMountOptions) {
const mockMixin = {
methods: {
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent[cmsFieldName])
}
};
@ -55,31 +52,8 @@ function setupMocks(customMountOptions) {
describe('Payment Method Question', () => {
beforeEach(() => {
cmsContent = {
PaymentMethodWidget: {
QuestionText: testConstants.cms.question,
Answers: [
{
Name: testConstants.cms.answers.optionA.name,
Text: testConstants.cms.answers.optionA.text,
SubText: testConstants.cms.answers.optionA.subText,
ImageId: testConstants.cms.answers.optionA.imageId,
AnswerImageUrl: testConstants.cms.answers.optionA.image,
SubWidgetName: testConstants.cms.answers.optionA.subWidget
},
{
Name: testConstants.cms.answers.optionB.name,
Text: testConstants.cms.answers.optionB.text,
SubText: testConstants.cms.answers.optionB.subText,
ImageId: testConstants.cms.answers.optionB.imageId,
AnswerImageUrl: testConstants.cms.answers.optionB.image,
SubWidgetName: testConstants.cms.answers.optionB.subWidget
}
]
}
};
cmsContent = mockCmsContent;
});
it('Should map cms content correctly', () => {
// Arrange
const props = generateDefaultProps();
@ -94,18 +68,18 @@ describe('Payment Method Question', () => {
// Assert
expect(mappedContent).toEqual([
{
buttonLabel: testConstants.cms.answers.optionA.text,
altText: testConstants.cms.answers.optionA.text,
buttonLabel: cmsContent.Answers[0].Text,
altText: cmsContent.Answers[0].Text,
groupName: 'payment-method',
value: testConstants.cms.answers.optionA.name,
buttonImage: testConstants.cms.answers.optionA.image
value: cmsContent.Answers[0].Name,
buttonImage: cmsContent.Answers[0].AnswerImageUrl
},
{
buttonLabel: testConstants.cms.answers.optionB.text,
altText: testConstants.cms.answers.optionB.text,
buttonLabel: cmsContent.Answers[1].Text,
altText: cmsContent.Answers[1].Text,
groupName: 'payment-method',
value: testConstants.cms.answers.optionB.name,
buttonImage: testConstants.cms.answers.optionB.image
value: cmsContent.Answers[1].Name,
buttonImage: cmsContent.Answers[1].AnswerImageUrl
}
]);
});

View file

@ -15,7 +15,9 @@
</template>
<script>
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import widgetFields from '@/constants/cms-widget-fields.js';
import paymentMethodListButton from './payment-method-list-button/payment-method-list-button.vue';
export default {
@ -25,8 +27,10 @@ export default {
},
props: {
modelValue: String,
validationRules: String
validationRules: String,
cmsWidgetName: String
},
emits: ['update:modelValue'],
data() {
return {
paymentMethodListButton
@ -34,33 +38,31 @@ export default {
},
computed: {
selectedMethod: {
get: function () {
get() {
return this.modelValue;
},
set: function (selectedMethod) {
set(selectedMethod) {
this.$emit('update:modelValue', selectedMethod);
},
}
},
paymentMethodQuestionText() {
return this.getCmsContent('PaymentMethodWidget', 'QuestionText');
return this.getCmsContent(this.cmsWidgetName, widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT);
},
paymentMethodAnswerData() {
const cmsData = this.getAnswersNullSafe('PaymentMethodWidget');
const cmsData = this.getAnswersNullSafe(this.cmsWidgetName);
return cmsData.map((answer) => {
return {
buttonLabel: answer.Text,
altText: answer.Text,
groupName: 'payment-method',
value: answer.Name,
buttonImage: answer.AnswerImageUrl
};
});
return cmsData.map((answer) => ({
buttonLabel: answer.Text,
altText: answer.Text,
groupName: 'payment-method',
value: answer.Name,
buttonImage: answer.AnswerImageUrl
}));
}
},
methods: {
getAnswersNullSafe(widgetName) {
const rawData = this.getCmsContent(widgetName, 'Answers');
const rawData = this.getCmsContent(widgetName, widgetFields.INPUT_QUESTION_WIDGET.ANSWERS);
if (!rawData) {
return [];
@ -72,11 +74,11 @@ export default {
};
</script>
<style lang="scss">
<style lang="scss" scoped>
.payment-method-question {
.question-text span {
:deep(.question-text span) {
text-align: left;
line-height: 24px;
line-height: 1.5rem;
}
}
</style>

View file

@ -0,0 +1,43 @@
// Components
import paymentMethod from '@/layouts/payment-method/payment-method.vue';
// Supporting Files
import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { useMainStore } from '@/store';
import paymentMethods from '@/constants/payment-method-constants';
function setupMocks() {
const mountOptions = getMountOptions();
const wrapper = shallowMount(paymentMethod, mountOptions);
return { wrapper };
}
describe('payment-method.vue', () => {
test('getting payment method when method is pay later', async () => {
// Arrange
const { wrapper } = setupMocks();
const payLaterPaymentMethod = paymentMethods.PAY_AT_TIME_OF_SERVICE;
useMainStore().savePaymentMethodChoice(payLaterPaymentMethod);
// Act
const paymethod = wrapper.vm.getPaymentMethodFromStore();
// Assert
expect(paymethod).toBe(payLaterPaymentMethod);
});
test('getting payment method when method is pay in advance', async () => {
// Arrange
const { wrapper } = setupMocks();
const payInAdvancePaymentMethod = paymentMethods.CREDIT_CARD;
useMainStore().savePaymentMethodChoice(payInAdvancePaymentMethod);
// Act
const paymethod = wrapper.vm.getPaymentMethodFromStore();
// Assert
expect(paymethod).not.toBe(payInAdvancePaymentMethod);
});
});

View file

@ -22,9 +22,9 @@
<hr class="my-5" />
<div>Pia Alert Placeholder</div>
<paymentMethodQuestion
v-if="!isPiaDisabled"
v-model="paymentMethodInternalModel"
validationRules="option-required" />
cmsWidgetName="PaymentMethodWidget"
:validationRules="rules.optionRequired" />
<div>Pia Disabled Placeholder</div>
<siteFooter
ref="siteFooter"
@ -51,15 +51,15 @@ import paymentMethodQuestion from '@/layouts/payment-method/payment-method-quest
import settleAllPromises from '@/helpers/layout-helper';
import { useMainStore } from '@/store';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { paymentMethods } from '@/constants/payment-method-constants';
import paymentMethods from '@/constants/payment-method-constants';
import globalRules from '@/constants/global-rules';
import { Form, defineRule } from 'vee-validate';
import { required } from '@/helpers/validation-rules';
import errorMessages from '@/constants/error-messages';
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
defineRule('option-required', required(errorMessages.OPTION_REQUIRED));
defineRule(globalRules.OPTION_REQUIRED, required(errorMessages.OPTION_REQUIRED));
export default {
name: 'payment-method',
@ -93,21 +93,24 @@ export default {
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.updateFooterButtonText(vm.customCtaCopy);
vm.updateFooterButtonText(vm.customCallToActionButtonCopy);
vm.$refs.reviewDropdown.initializeComponent(resultMap.reviewDropdownData);
});
},
data() {
return {
paymentMethodInternalModel: this.getPaymentMethodFromStore()
paymentMethodInternalModel: this.getPaymentMethodFromStore(),
rules: {
optionRequired: globalRules.OPTION_REQUIRED
}
};
},
computed: {
damageInfo() {
return useMainStore().order.damage;
},
customCtaCopy() {
customCallToActionButtonCopy() {
switch (this.paymentMethod) {
case paymentMethods.CREDIT_CARD:
return 'Continue to checkout';
@ -119,28 +122,12 @@ export default {
return null;
}
},
isPiaDisabled() {
// do we have this experiment in NextGen ISS?
/*
const piaExperience = this.getSettingValue(experimentSettings.PIA_EXPERIENCE);
const isEnabled = piaExperience === "PIA Optional" || piaExperience === "PIA Required";
return !isEnabled;
*/
return false;
},
paymentMethod() {
if (this.isPiaDisabled) {
return paymentMethods.LATER;
}
return this.paymentMethodInternalModel;
}
},
watch: {
customCtaCopy(newValue) {
customCallToActionButtonCopy(newValue) {
this.updateFooterButtonText(newValue);
}
},
@ -214,36 +201,19 @@ export default {
);
},
getPaymentMethodFromStore() {
const { piaType } = useMainStore().order.payment;
const isPia = useMainStore().order.payment.isPia && !!piaType;
const { payInAdvanceType } = useMainStore().order.payment;
const isPayInAdvance = useMainStore().order.payment.isPayInAdvance && !!payInAdvanceType;
return isPia ? piaType : paymentMethods.LATER;
return isPayInAdvance ? payInAdvanceType : paymentMethods.PAY_AT_TIME_OF_SERVICE;
},
updateFooterButtonText(newValue) {
this.$refs.siteFooter.updateButtonText(newValue);
},
async forwardButtonAction() {
// Multiple paths based on payment
console.log('forward button hit...');
await useMainStore().savePaymentMethodChoice(this.paymentMethod);
if (this.paymentMethod === paymentMethods.LATER) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
} else {
this.setupPia();
}
},
async setupPia() {
this.$refs.loadingModal.showModal();
// if we don't have a work order in delete substatus, set the flag and submit.
// we need a work order number for pia so we can pass it to safeliteHop.
this.$router.navigate(
this.navigationScenarios.CLICKED_PAY_NOW,
this.$route
);
}
}
};

View file

@ -13,7 +13,7 @@ import damageLocationsSelected from '@/constants/damage-locations-selected';
import coverageStatuses from '@/constants/coverage-statuses';
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants';
import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper';
import { paymentMethods } from '@/constants/payment-method-constants';
import paymentMethods from '@/constants/payment-method-constants';
const storeId = 'main';
@ -149,8 +149,8 @@ const getDefaultState = () => ({
claimNumber: null
},
parentAccountNumber: 0,
isPia: null,
piaType: null
isPayInAdvance: null,
payInAdvanceType: null
},
contactInfo: {
firstName: null,
@ -2141,10 +2141,10 @@ export const useMainStore = defineStore({
},
savePaymentMethodChoice(paymentMethod) {
const isPia = paymentMethod !== paymentMethods.LATER;
this.order.payment.isPia = isPia;
this.order.payment.piaType = isPia ? paymentMethod : null;
},
const isPayInAdvance = paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE;
this.order.payment.isPayInAdvance = isPayInAdvance;
this.order.payment.payInAdvanceType = isPayInAdvance ? paymentMethod : null;
}
},
persist: true

View file

@ -3,6 +3,7 @@ import { useMainStore } from '@/store/index.js';
import globalMethods from '@/global-methods.js';
import { getRandomString, getRandomGuid, getRandomInt, getRandomBoolean } from '@/helpers/data-generation.js';
import coverageStatuses from '@/constants/coverage-statuses.js';
import paymentMethods from '@/constants/payment-method-constants';
import { endpoints } from '@/constants/endpoints';
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
@ -2083,4 +2084,29 @@ describe('Store', () => {
expect(store.order.policy.policyLookupSuccessful).toBe(false);
});
});
describe('savePaymentMethodChoice method', () => {
it('isPayInAdvance saved as false when choice is to pay at time of servce', () => {
// Arrange
const paymentMethod = paymentMethods.PAY_AT_TIME_OF_SERVICE;
// Act
store.savePaymentMethodChoice(paymentMethod);
// Assert
expect(store.order.payment.isPayInAdvance).toEqual(false);
expect(store.order.payment.payInAdvanceType).toEqual(null);
});
it('isPayInAdvance saved as true when choice is other than to pay at time of servce', () => {
// Arrange
const paymentMethod = paymentMethods.CREDIT_CARD;
// Act
store.savePaymentMethodChoice(paymentMethod);
// Assert
expect(store.order.payment.isPayInAdvance).toEqual(true);
expect(store.order.payment.payInAdvanceType).toEqual(paymentMethod);
});
});
});