Merge pull request #3276 from Safelite/feature/CASH-2961.1
CASH-2961: Pass PIA authorization amount
This commit is contained in:
commit
19e92dc8f2
10 changed files with 228 additions and 28 deletions
|
|
@ -48,6 +48,7 @@ const queryStrings = {
|
|||
FROM_HERITAGE: "fromheritage",
|
||||
PHONE_NUMBER: "phonenumber",
|
||||
OFFER_QUOTE: "offerquote",
|
||||
PIA_AUTH_AMOUNT_ADJUST: "piaauthamountadjust",
|
||||
};
|
||||
|
||||
export { queryStrings };
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ const storeActions = {
|
|||
SAVE_CCTOKEN: "saveCCToken",
|
||||
SAVE_PAYPAL_TOKEN: "savePaypalToken",
|
||||
SAVE_NEXTGEN_SETTLED_AMOUNT: "saveNextGenSettledAmount",
|
||||
SAVE_AUTHORIZATION_AMOUNT: "saveAuthorizationAmount",
|
||||
SAVE_IS_RECAL_ACK_OPT_IN: "saveIsRecalAckOptIn",
|
||||
SAVE_IS_RECAL_ACKNOWLEDGED_FOR_SCHEDULING: "saveIsRecalAcknowledgedForScheduling",
|
||||
SAVE_IS_OEM_GLASS_SELECTED: "saveIsOemGlassSelected",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ const storeMutations = {
|
|||
UPDATE_CCTOKEN: "updateCCToken",
|
||||
UPDATE_PAYPAL_TOKEN: "updatePaypalToken",
|
||||
UPDATE_NEXTGEN_SETTLED_AMOUNT: "updateNextGenSettledAmount",
|
||||
UPDATE_AUTHORIZATION_AMOUNT: "updateAuthorizationAmount",
|
||||
|
||||
// VEHICLE MUTATIONS
|
||||
UPDATE_YEAR: "updateYear",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ import { storeActions } from "@/constants/store-actions";
|
|||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { deepClone } from "@/helpers/object-helper";
|
||||
import { partNumberStrings } from "@/constants/part-number-strings";
|
||||
import { applicationConfig } from "@/constants/application-config";
|
||||
import { queryStrings } from "@/constants/query-strings";
|
||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||
import { peekQueryFromStash } from "@/router/methods/helpers/querystring-stash";
|
||||
|
||||
export function getDisplayAmountDue(lineItemsObject, includeTax = true) {
|
||||
return getAmountDue(lineItemsObject, includeTax).toLocaleString("en-US", {
|
||||
|
|
@ -56,6 +60,35 @@ export function getAmountDue(lineItemsObject, includeTax = true) {
|
|||
return ((amountDue * 100) / 100).toFixed(2);
|
||||
}
|
||||
|
||||
function getPiaAuthAmountAdjustment() {
|
||||
if (applicationConfig.CURRENT_ENVIRONMENT === "Prod") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const adjustParam =
|
||||
peekQueryFromStash(queryStrings.PIA_AUTH_AMOUNT_ADJUST) ??
|
||||
getQuerystringParameter(queryStrings.PIA_AUTH_AMOUNT_ADJUST);
|
||||
|
||||
if (adjustParam == null || adjustParam === "") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const adjustment = parseFloat(adjustParam);
|
||||
return Number.isFinite(adjustment) ? adjustment : 0;
|
||||
}
|
||||
|
||||
export function getPiaAuthorizationAmount(lineItemsObject) {
|
||||
const amountDue = parseFloat(getAmountDue(lineItemsObject));
|
||||
const adjustment = getPiaAuthAmountAdjustment();
|
||||
|
||||
if (adjustment === 0) {
|
||||
return amountDue.toFixed(2);
|
||||
}
|
||||
|
||||
const adjustedAmount = Math.max(0.01, amountDue + adjustment);
|
||||
return adjustedAmount.toFixed(2);
|
||||
}
|
||||
|
||||
export function getSubTotal(lineItemsObject) {
|
||||
// this is amountDue without sales tax
|
||||
return getAmountDue(lineItemsObject, false);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,22 @@
|
|||
import {
|
||||
getDisplayAmountDue,
|
||||
getAmountDue,
|
||||
getPiaAuthorizationAmount,
|
||||
getSubTotal,
|
||||
getSalesTax,
|
||||
} from "@/helpers/pricing-helper.js";
|
||||
import { applicationConfig } from "@/constants/application-config";
|
||||
|
||||
jest.mock("@/helpers/querystring-helper", () => ({
|
||||
getQuerystringParameter: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("@/router/methods/helpers/querystring-stash", () => ({
|
||||
peekQueryFromStash: jest.fn(),
|
||||
}));
|
||||
|
||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||
import { peekQueryFromStash } from "@/router/methods/helpers/querystring-stash";
|
||||
|
||||
const lineItems = {
|
||||
glassParts: [],
|
||||
|
|
@ -61,4 +74,30 @@ describe("pricing-helper", () => {
|
|||
expect(result).toBe("3.00");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getPiaAuthorizationAmount", () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
peekQueryFromStash.mockReturnValue(null);
|
||||
getQuerystringParameter.mockReturnValue(null);
|
||||
applicationConfig.CURRENT_ENVIRONMENT = "QA";
|
||||
});
|
||||
|
||||
it("returns amount due when no adjustment is configured", () => {
|
||||
expect(getPiaAuthorizationAmount(lineItems)).toBe("53.00");
|
||||
});
|
||||
|
||||
it("ignores adjustment in production", () => {
|
||||
applicationConfig.CURRENT_ENVIRONMENT = "Prod";
|
||||
peekQueryFromStash.mockReturnValue("-5");
|
||||
|
||||
expect(getPiaAuthorizationAmount(lineItems)).toBe("53.00");
|
||||
});
|
||||
|
||||
it("applies non-production query string adjustment", () => {
|
||||
peekQueryFromStash.mockReturnValue("-5");
|
||||
|
||||
expect(getPiaAuthorizationAmount(lineItems)).toBe("48.00");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ import { endpoints } from "../../constants/endpoints";
|
|||
import { AppointmentTypeStrings } from "../../constants/schedule-constants";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { getAmountDue } from "@/helpers/pricing-helper.js";
|
||||
import { getAmountDue, getPiaAuthorizationAmount } from "@/helpers/pricing-helper.js";
|
||||
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
||||
import { createAdyenCheckout } from "@/helpers/adyen-helper";
|
||||
import { Dropin } from "@adyen/adyen-web/auto";
|
||||
|
|
@ -364,14 +364,22 @@ export default {
|
|||
);
|
||||
}
|
||||
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
||||
this.amountDue,
|
||||
false
|
||||
);
|
||||
await this.savePiaPaymentAmounts();
|
||||
|
||||
await this.saveAndSubmitWorkOrder();
|
||||
},
|
||||
async savePiaPaymentAmounts() {
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
||||
this.piaAuthorizationAmount,
|
||||
false
|
||||
);
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_AUTHORIZATION_AMOUNT,
|
||||
this.piaAuthorizationAmount,
|
||||
false
|
||||
);
|
||||
},
|
||||
async handleFailedPayment(result) {
|
||||
console.log(`Result =`);
|
||||
console.log(result);
|
||||
|
|
@ -555,8 +563,12 @@ export default {
|
|||
return getAmountDue(this.$store.getters.order.lineItems);
|
||||
},
|
||||
|
||||
piaAuthorizationAmount() {
|
||||
return getPiaAuthorizationAmount(this.$store.getters.order.lineItems);
|
||||
},
|
||||
|
||||
adyenPriceTotal() {
|
||||
return Math.round(this.amountDue * 100);
|
||||
return Math.round(parseFloat(this.piaAuthorizationAmount) * 100);
|
||||
},
|
||||
|
||||
// Cart info
|
||||
|
|
|
|||
|
|
@ -14,12 +14,7 @@ import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
|||
import { Form } from "vee-validate";
|
||||
import { paymentMethods } from "@/constants/payment-method-constants";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import {
|
||||
getDisplayAmountDue,
|
||||
getAmountDue,
|
||||
getSubTotal,
|
||||
getSalesTax,
|
||||
} from "@/helpers/pricing-helper.js";
|
||||
import { getPiaAuthorizationAmount } from "@/helpers/pricing-helper.js";
|
||||
// iframeResizer IS loaded into the page and necessary for the package to
|
||||
// to auto scale the iFrame this page is loaded in
|
||||
// Do not remove despite showing as "unused" CASH-309
|
||||
|
|
@ -103,11 +98,7 @@ export default {
|
|||
const payerId = getQuerystringParameter(queryStrings.PAYERID);
|
||||
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_PAYPAL_TOKEN, token, false);
|
||||
baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
||||
this.getAmountDue(),
|
||||
false
|
||||
);
|
||||
this.savePiaPaymentAmounts();
|
||||
|
||||
await this.saveAndSubmitWorkOrder();
|
||||
},
|
||||
|
|
@ -160,16 +151,22 @@ export default {
|
|||
console.log(ccToken);
|
||||
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_CCTOKEN, ccToken, false);
|
||||
baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
||||
this.getAmountDue(),
|
||||
false
|
||||
);
|
||||
this.savePiaPaymentAmounts();
|
||||
await this.saveAndSubmitWorkOrder();
|
||||
}
|
||||
},
|
||||
getAmountDue() {
|
||||
return getAmountDue(store.getters.order.lineItems);
|
||||
savePiaPaymentAmounts() {
|
||||
const authorizationAmount = getPiaAuthorizationAmount(store.getters.order.lineItems);
|
||||
baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
||||
authorizationAmount,
|
||||
false
|
||||
);
|
||||
baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_AUTHORIZATION_AMOUNT,
|
||||
authorizationAmount,
|
||||
false
|
||||
);
|
||||
},
|
||||
async saveAndSubmitWorkOrder() {
|
||||
// Final work order submit after returning from PIA.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { routeData } from "@/router/constants/routes";
|
|||
import { createAdyenCheckout, getSessionInfo } from "@/helpers/adyen-helper";
|
||||
import { mapAdyenToFmgPaymentMethod, generateCcToken } from "@/helpers/adyen-helper";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { getAmountDue } from "@/helpers/pricing-helper";
|
||||
import { getPiaAuthorizationAmount } from "@/helpers/pricing-helper";
|
||||
import store from "@/store";
|
||||
import { storeActions } from "@/constants/store-actions";
|
||||
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
||||
|
|
@ -49,7 +49,7 @@ export async function adyenReturnBeforeEnter(to, from) {
|
|||
|
||||
// TODO once afterpay info is returned, create cc token and submit order.
|
||||
const paymentMethod = mapAdyenToFmgPaymentMethod(sessionInfo?.paymentMethod);
|
||||
const amountDue = getAmountDue(store.getters.order.lineItems);
|
||||
const authorizationAmount = getPiaAuthorizationAmount(store.getters.order.lineItems);
|
||||
const ccToken = generateCcToken(sessionInfo);
|
||||
|
||||
ccToken.authCode = "831001";
|
||||
|
|
@ -68,7 +68,13 @@ export async function adyenReturnBeforeEnter(to, from) {
|
|||
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_NEXTGEN_SETTLED_AMOUNT,
|
||||
amountDue,
|
||||
authorizationAmount,
|
||||
false
|
||||
);
|
||||
|
||||
await baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_AUTHORIZATION_AMOUNT,
|
||||
authorizationAmount,
|
||||
false
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ const getDefaultState = () => {
|
|||
inactivePromos: null,
|
||||
paypalToken: null,
|
||||
nextGenSettledAmount: 0,
|
||||
authorizationAmount: null,
|
||||
ccToken: {
|
||||
subscriptionId: null,
|
||||
expMonth: null,
|
||||
|
|
@ -488,6 +489,9 @@ export const mutations = {
|
|||
updateNextGenSettledAmount(state, nextGenSettledAmount) {
|
||||
state.order.payment.nextGenSettledAmount = nextGenSettledAmount;
|
||||
},
|
||||
updateAuthorizationAmount(state, authorizationAmount) {
|
||||
state.order.payment.authorizationAmount = authorizationAmount;
|
||||
},
|
||||
updateInsuranceVerifiedStatus(state, isVerified) {
|
||||
state.order.payment.insuranceCoverage.isVerified = isVerified;
|
||||
},
|
||||
|
|
@ -2893,6 +2897,9 @@ export const actions = {
|
|||
order.payment.piaType == paymentMethods.APPLE_PAY ? true : false,
|
||||
paypalToken: order.payment.paypalToken,
|
||||
nextGenSettledAmount: order.payment.nextGenSettledAmount,
|
||||
...(order.payment.authorizationAmount > 0
|
||||
? { authorizationAmount: order.payment.authorizationAmount }
|
||||
: {}),
|
||||
ccToken: {
|
||||
subscriptionId: order.payment.ccToken.subscriptionId,
|
||||
expMonth: order.payment.ccToken.expMonth,
|
||||
|
|
@ -3047,6 +3054,10 @@ export const actions = {
|
|||
context.commit(storeMutations.UPDATE_NEXTGEN_SETTLED_AMOUNT, nextGenSettledAmount);
|
||||
},
|
||||
|
||||
saveAuthorizationAmount(context, authorizationAmount) {
|
||||
context.commit(storeMutations.UPDATE_AUTHORIZATION_AMOUNT, authorizationAmount);
|
||||
},
|
||||
|
||||
savePaypalToken(context, ppToken) {
|
||||
context.commit(storeMutations.UPDATE_PAYPAL_TOKEN, ppToken);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -920,6 +920,105 @@ describe("Actions", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("saveSession action, includes authorizationAmount when PIA was authorized", async () => {
|
||||
const context = createAuthorizationAmountSaveSessionContext(312.45);
|
||||
|
||||
globalMethods.callHttpClient.mockImplementation(() => {
|
||||
return Promise.resolve({ data: { referralNumber: 123 } });
|
||||
});
|
||||
|
||||
await actions.saveSession(context, { pageNameToLog: "test" });
|
||||
|
||||
expect(globalMethods.callHttpClient).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
payload: expect.objectContaining({
|
||||
order: expect.objectContaining({
|
||||
payment: expect.objectContaining({
|
||||
authorizationAmount: 312.45,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("saveSession action, omits authorizationAmount when PIA was not authorized", async () => {
|
||||
const context = createAuthorizationAmountSaveSessionContext(null);
|
||||
|
||||
globalMethods.callHttpClient.mockImplementation(() => {
|
||||
return Promise.resolve({ data: { referralNumber: 123 } });
|
||||
});
|
||||
globalMethods.callHttpClient.mockClear();
|
||||
|
||||
await actions.saveSession(context, { pageNameToLog: "test" });
|
||||
|
||||
const callPayload = globalMethods.callHttpClient.mock.calls[0][0].payload;
|
||||
expect(callPayload.order.payment.authorizationAmount).toBeUndefined();
|
||||
});
|
||||
|
||||
function createAuthorizationAmountSaveSessionContext(authorizationAmount) {
|
||||
const context = state;
|
||||
const damage = {
|
||||
numberOfChips: "2",
|
||||
partQuestionAnswers: {},
|
||||
moldingQuestionAnswers: {},
|
||||
capabilityQuestionAnswers: {},
|
||||
};
|
||||
|
||||
context.getters = {
|
||||
vehicle: { registration: {} },
|
||||
order: { damage },
|
||||
damage: {},
|
||||
applicationUser: {
|
||||
lastPageVisited: "test-page",
|
||||
crmCustomerId: "xxx-xxx-xxx",
|
||||
savedSessionId: "xxx-xxx-xxx",
|
||||
},
|
||||
};
|
||||
context.state = {
|
||||
order: {
|
||||
damage,
|
||||
payment: {
|
||||
insuranceCoverage: { isVerified: false },
|
||||
isInsurance: false,
|
||||
authorizationAmount,
|
||||
ccToken: {
|
||||
subscriptionId: authorizationAmount ? "sub-123" : null,
|
||||
expMonth: null,
|
||||
expYear: null,
|
||||
cardType: null,
|
||||
billToPostalCode: null,
|
||||
billToFirstName: null,
|
||||
billToLastName: null,
|
||||
referenceNumber: null,
|
||||
authCode: authorizationAmount ? "831001" : null,
|
||||
transactionId: null,
|
||||
transReferenceNumber: null,
|
||||
lastFour: null,
|
||||
},
|
||||
},
|
||||
serviceLocation: {},
|
||||
customer: {
|
||||
emailAddress: "test@safelite.com",
|
||||
firstName: "John",
|
||||
lastName: "Doe",
|
||||
isSmsOptIn: true,
|
||||
phoneNumber: "1234567890",
|
||||
address: {
|
||||
streetAddress: "123 Main St",
|
||||
streetAddress2: "Apt 1",
|
||||
city: "Anytown",
|
||||
state: "OH",
|
||||
zipCode: "12345",
|
||||
},
|
||||
},
|
||||
lineItems: {},
|
||||
},
|
||||
};
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
it("loadSession action, returns order information, calls mutation", async () => {
|
||||
// Arrange
|
||||
const context = state;
|
||||
|
|
|
|||
Loading…
Reference in a new issue