Merge branch 'release/2025.10.23' into rlsmerge/2025.10.23-to-dev

This commit is contained in:
CarlNation 2025-10-18 10:21:08 -04:00
commit 2dbead5b37
4 changed files with 11 additions and 202 deletions

View file

@ -35,7 +35,7 @@
:isNoComp="isNoComp"
:isExpandedOnLoad="false"
:isMSRFeeApplicable="isMSRFeeApplicable"
@itemRemoved="reTaxItemsOnOrder" />
@itemRemoved="evaluatePromosAndTaxItemsOnOrder" />
<afterpayBreakout
v-if="isAfterpayBreakoutDisplay"
@ -589,7 +589,13 @@ export default {
this.pageName
);
},
async reTaxItemsOnOrder() {
async evaluatePromosAndTaxItemsOnOrder() {
//Revalidate promos if there are any inactive, or active promos
const hasInactivePromos = this.inactivePromos.length > 0;
const hasActivePromos = this.lineItems.promos.length > 0;
if (hasInactivePromos || hasActivePromos) {
await this.revalidatePromos();
}
this.lineItems = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{

View file

@ -319,7 +319,6 @@ describe("payment.vue", () => {
);
// Assert
expect(vmMock.availableVaps).not.toBeUndefined();
expect(vmMock.lineItems).not.toBeUndefined();
expect(vmMock.setCmsContent).toBeCalled();

View file

@ -42,7 +42,7 @@
<cart
ref="cart"
:damage="damageInfo"
:availableVaps="availableVaps"
:availableVaps="[]"
:allowItemRemoval="false"
v-model="lineItems"
servicePackageOptionsCmsName="ServicePackageTitle"
@ -237,25 +237,11 @@ import { applicationConfig } from "@/constants/application-config";
import { paymentMethods } from "@/constants/payment-method-constants";
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
import baseMixin from "@/mixins/base-mixin.js";
import { mapTaxedLineItemsToStoreFormat } from "../../store";
import {
revalidatePromosAndValidateQueryStringPromo,
getAddableVapsFromAvailableLineItems,
getVapsThatNeedToBeAddedToSatisfyPromos,
} from "@/helpers/promotions-helper";
import { queryStrings } from "@/constants/query-strings";
import { getQuerystringParameter } from "@/helpers/querystring-helper";
import { deepClone } from "@/helpers/object-helper";
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
import iframeResize from "../../../node_modules/iframe-resizer/js/iframeResizer.js";
import { coverageStatus } from "@/constants/insurance";
import { getBoolFromString } from "@/helpers/boolean-helper.js";
import {
getDisplayAmountDue,
getAmountDue,
getSubTotal,
getSalesTax,
} from "@/helpers/pricing-helper.js";
import { getDisplayAmountDue, getAmountDue } from "@/helpers/pricing-helper.js";
import { debugLog } from "@/helpers/debug-log-helper.js";
import buttonQuestion from "@/digital-components/button-question/button-question";
import paymentMethodListButton from "@/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button";
@ -290,7 +276,6 @@ export default {
displayAmount: this.getDisplayAmountDue(),
piaLineItems: "",
lineItems: [],
availableVaps: [],
shouldBlockInteraction: false,
paymentMethodListButton: paymentMethodListButton,
showSwitchPaymentMethod: !this.isAfterpay(),
@ -321,21 +306,6 @@ export default {
"payment"
);
const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_WIPERS,
{
serviceZipCode: store.getters.order.serviceLocation.zipCode,
carId: store.getters.vehicle.carId,
},
"payment"
);
const rainRepelPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_RAIN_REPEL,
null,
"payment"
);
const promiseResultMap = [
{
resultKey: "cmsContent",
@ -345,92 +315,14 @@ export default {
resultKey: "signature",
promise: signaturePromise,
},
{
resultKey: "wipers",
promise: wipersPromise,
},
{
resultKey: "rainRepel",
promise: rainRepelPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
const lineItemsFromStore = deepClone(store.getters.order.lineItems);
const glassParts = lineItemsFromStore.glassParts ?? [];
const supportingItems = lineItemsFromStore.supportingItems ?? [];
const lineItemsToTax = [
resultMap.rainRepel,
...supportingItems,
...resultMap.wipers,
...glassParts,
];
const availableVaps = [resultMap.rainRepel, ...resultMap.wipers];
const pricedLineItemsToTax = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
availableLineItems: lineItemsToTax,
},
"payment",
false
);
// Promo logic
const promoCodeFromQueryString = getQuerystringParameter(queryStrings.PROMO);
const { validatePromoResponse, revalidatePromoResponse } =
await revalidatePromosAndValidateQueryStringPromo(
promoCodeFromQueryString,
pricedLineItemsToTax,
"payment"
);
const newValidatedPromos = validatePromoResponse?.orderPromos ?? [];
newValidatedPromos.push(
...(revalidatePromoResponse ? revalidatePromoResponse.promoLineItems : [])
);
pricedLineItemsToTax.push(...newValidatedPromos);
// End of promo logic
const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
billToAccountNumber: store.getters.payment.billToAccountNumber,
providerNumber: store.getters.order.serviceLocation.provider.providerNumber,
appointmentType: store.getters.order.serviceLocation.appointmentType,
serviceLocationCity: store.getters.order.serviceLocation.city,
serviceLocationState: store.getters.order.serviceLocation.state,
serviceLocationZipCode: store.getters.order.serviceLocation.zipCode,
pricedLineItems: pricedLineItemsToTax,
},
"payment",
false
);
// Match all line items to the line items as they are in the store
// and rebuild the original structure.
const lineItems = mapTaxedLineItemsToStoreFormat(taxedLineItems, lineItemsFromStore);
const taxedVaps = mapTaxedLineItemsToStoreFormat(taxedLineItems, availableVaps);
// Add items that were not in the store yet but added via query string promo validation
//newValidatedPromos contains both validated and revalidated promos.
lineItems.promos = Array.from(newValidatedPromos);
const vapsToAddToCart = getVapsThatNeedToBeAddedToSatisfyPromos(
newValidatedPromos,
taxedVaps,
lineItems
);
lineItems.vaps = lineItems.vaps ?? [];
lineItems.vaps.push(...vapsToAddToCart);
// Call the "next" function to complete the transition to this page.
next(async (vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.availableVaps = taxedVaps;
vm.lineItems = lineItems;
vm.lineItems = deepClone(store.getters.order.lineItems);
vm.$nextTick(() => {
if (vm.$refs.cart) {

View file

@ -200,94 +200,6 @@ export default {
await this.logPageView(analyticsPageEvents.ENTRY);
},
// This sends session data to the session logging endpoint on the analytics service.
// From there, it uses aws kinesis data stream, DigitalConsumer-Session-Data-Stream,
// and aws FireHose stream, DigitalConsumer-Session-Firehose, to push data to an
// S3 bucket, safelite-dev-digitalconsumer-session-data-us-east-2/1.
// This bucket data is then picked up by snowflake for analytics use.
async pushFmgSessionData() {
const hasSubmittedOrder = baseMixin.methods.hasSubmittedOrder();
const submittedOrder = baseMixin.methods.getSubmittedOrder();
const order = hasSubmittedOrder ? submittedOrder : store.getters.order;
const hasSubmittedApplicationUser = baseMixin.methods.hasSubmittedApplicationUser();
const submittedApplicationUser = baseMixin.methods.getSubmittedApplicationUser();
const applicationUser = hasSubmittedApplicationUser
? submittedApplicationUser
: store.getters.applicationUser;
const isEarlyBird = order?.lineItems?.supportingItems?.find(
(lineItem) => lineItem.partType == partTypeStrings.EARLY_BIRD
);
const promoCodes = Array.isArray(order?.lineItems?.promos)
? order?.lineItems?.promos
.map((item) => item.promoCode)
.filter((code) => code)
.join(", ")
: null;
const glassProducts = order?.damage?.glassToReplace?.map(
(part) => `${part.glassLocation}-${part.glassName}`
);
var sessionData = {};
sessionData.currentPage = getPageNameFromRouter();
sessionData.sid = getSessionIdValue();
sessionData.deviceId = getDeviceIdValue();
sessionData.fmgSessionId = applicationUser?.savedSessionId;
sessionData.userId = getUserIdValue();
sessionData.carId = order?.vehicle?.carId;
sessionData.vehicleYear = order?.vehicle?.year;
sessionData.vehicleMake = order?.vehicle?.make;
sessionData.vehicleModel = order?.vehicle?.model;
sessionData.vehicleStyle = order?.vehicle?.style;
sessionData.hasVin = order?.vehicle?.vin ? true : false;
sessionData.cashOrInsuranceAccountType = order?.payment?.isInsurance
? "Insurance"
: "Cash";
sessionData.damageType = order?.damage?.isRepair ? "Repair" : "Replace";
sessionData.productType = glassProducts;
sessionData.eon = order?.eon;
sessionData.referralNumber = order?.referralNumber;
sessionData.referralSequenceNumber = order?.referralSequenceNumber;
sessionData.referralDate = order?.referralDate;
sessionData.workOrderNumber = order?.workOrderNumber;
sessionData.workOrderId = order?.workOrderId;
sessionData.isPia = order?.payment?.isPia ?? false;
sessionData.piaType = order?.payment?.piaType;
sessionData.parentAccountNumber = order?.payment?.parentAccountNumber;
sessionData.settledTenderAmount = order?.settledTenderAmount;
sessionData.recalRequired = containsRecalParts(order?.lineItems);
sessionData.recalType = getRecalPartNumbers(order?.lineItems?.glassParts);
sessionData.serviceZipCode = order?.serviceLocation?.provider?.address?.zipCode
? order?.serviceLocation?.provider?.address?.zipCode
: order?.serviceLocation?.zipCode;
sessionData.providerCtu = order?.serviceLocation?.provider?.address?.zipCodeCtu
? order?.serviceLocation?.provider?.address?.zipCodeCtu
: order?.serviceLocation?.zipCodeCtu;
sessionData.appointmentDate = `${order?.schedule?.date} ${order?.schedule?.startTime}`;
sessionData.serviceType = order?.serviceLocation?.appointmentType;
sessionData.promoCodes = promoCodes;
sessionData.hasTechnicianNotes = order?.serviceLocation?.techNotes ? true : false;
sessionData.paymentMethod = order?.payment?.piaType;
sessionData.isTextingOptedIn = order?.customer?.isSmsOptIn ? true : false;
sessionData.isEarlyBird = isEarlyBird ? true : false;
sessionData.insuranceCo = order?.policy?.insuranceCompanyName;
sessionData.deductible = order?.policy?.currentDeductible;
sessionData.isVerified = order?.payment?.insuranceCoverage?.isVerified ?? false;
sessionData.isNoComp = order?.policy?.isNoComp;
sessionData.isItac = order?.policy?.isItac;
sessionData.subTotalPrice = getSubTotal(order?.lineItems);
sessionData.totalPrice = getAmountDue(order?.lineItems, true);
await baseMixin.methods.dispatchStoreAction(
storeActions.LOG_FMG_SESSION_DATA,
sessionData,
false
);
},
pushOrderToDataLayer() {
// helper check for if an object is defined (but maybe falsey)
const isDefined = (x) => x !== null && x !== undefined;