diff --git a/src/fmg-components/cart/cart.vue b/src/fmg-components/cart/cart.vue
index afb13c0e1..d00e08630 100644
--- a/src/fmg-components/cart/cart.vue
+++ b/src/fmg-components/cart/cart.vue
@@ -52,7 +52,15 @@
:text="recycleFeeCartItem.name"
href="#!"
@click-event="openModal(recyclingModalCmsWidgetName)" />
- {{ currencyFormatter.format(cartItem.subTotal) }}
+ {{
+ `${
+ cartItem.category == "promos"
+ ? "(" + currencyFormatter.format(cartItem.subTotal * -1) + ")"
+ : currencyFormatter.format(cartItem.subTotal)
+ }`
+ }}
+
@@ -88,6 +96,7 @@ import baseMixin from "@/mixins/base-mixin.js";
// Helpers
import { deepClone } from "@/helpers/object-helper";
import { getHighestFullySatisfiedTier, getPackageContents } from "@/helpers/service-package-helper";
+import { getPromoCodeWithoutBundleIdentifier } from "@/helpers/promotions-helper";
// Constants
import { partTypeStrings } from "@/constants/part-type-strings";
@@ -216,33 +225,16 @@ export default {
cartItems.push(this.mobileFeeCartItem);
}
- // Create a cart item for each promo
- this.promos.forEach((promoLineItem) => {
- let cartItem = null;
-
- cartItem = {
- name: promoLineItem?.promoCode, // get from CMS?
- category: cartItemCategories.PROMOS,
- cartItemType: promoLineItem?.partType,
- isDisplayed: true,
- subTotal:
- (promoLineItem?.kitPrice ?? 0) +
- (promoLineItem?.laborAmount ?? 0) +
- (promoLineItem?.sellingPrice ?? 0),
- salesTax: promoLineItem?.salesTax,
- lineItems: [],
- };
-
- promoLineItem.cartItemType = cartItem.cartItemType;
- cartItem.lineItems.push(promoLineItem);
-
- cartItems.push(cartItem);
- });
-
if (this.premiumAppointmentDiscountCartItem) {
cartItems.push(this.premiumAppointmentDiscountCartItem);
}
+ if (this.promoCartItems) {
+ this.promoCartItems.forEach((promoCartItem) => {
+ cartItems.push(promoCartItem);
+ });
+ }
+
return cartItems;
},
},
@@ -346,6 +338,7 @@ export default {
category: cartItemCategories.VAPS,
cartItemType: cartItemTypes.FRONT_WIPERS,
isDisplayed: true,
+ isRemovable: true,
subTotal: 0,
salesTax: 0,
lineItems: [],
@@ -382,6 +375,7 @@ export default {
category: cartItemCategories.VAPS,
cartItemType: cartItemTypes.REAR_WIPERS,
isDisplayed: true,
+ isRemovable: true,
subTotal: 0,
salesTax: 0,
lineItems: [],
@@ -547,10 +541,7 @@ export default {
otherSupportingItemsCartItem() {
let cartItem = null;
- let otherSupportingItemsLineItems = baseMixin.methods.filterOutFees(
- this.supportingItems
- );
- otherSupportingItemsLineItems = otherSupportingItemsLineItems.filter(
+ const otherSupportingItemsLineItems = this.supportingItems.filter(
(lineItem) => lineItem.partType != partTypeStrings.EARLY_BIRD
);
@@ -597,6 +588,7 @@ export default {
category: cartItemCategories.SUPPORTING_ITEMS,
cartItemType: cartItemTypes.EARLY_BIRD,
isDisplayed: true,
+ isRemovable: true,
subTotal: 0,
salesTax: 0,
lineItems: [],
@@ -615,6 +607,57 @@ export default {
return cartItem;
},
+ promoCartItems() {
+ const promoCartItems = [];
+
+ // clone the promos array
+ const promosClone = deepClone(this.promo);
+ // get unique promo codes
+ const uniquePromoCodes = [
+ ...new Set(
+ this.promos.map((promo) => getPromoCodeWithoutBundleIdentifier(promo.promoCode))
+ ),
+ ];
+
+ uniquePromoCodes.forEach((promoCode) => {
+ // get the codes with the prefix from the promo array
+ const promoLineItems = this.promos.filter(
+ (promo) => getPromoCodeWithoutBundleIdentifier(promo.promoCode) == promoCode
+ );
+
+ // Create a cart item for each promo
+ let cartItem = null;
+
+ cartItem = {
+ name: promoCode,
+ category: cartItemCategories.PROMOS,
+ cartItemType: promoCode,
+ isDisplayed: true,
+ isRemovable: true,
+ subTotal: 0,
+ salesTax: 0,
+ lineItems: [],
+ };
+
+ promoLineItems.forEach((promoLineItem) => {
+ promoLineItem.cartItemType = cartItem.cartItemType;
+
+ cartItem.subTotal +=
+ (promoLineItem.kitPrice ?? 0) +
+ (promoLineItem.laborAmount ?? 0) +
+ (promoLineItem.sellingPrice ?? 0);
+
+ cartItem.salesTax += promoLineItem.salesTax ?? 0;
+
+ cartItem.lineItems.push(promoLineItem);
+ });
+
+ promoCartItems.push(cartItem);
+ });
+
+ return promoCartItems;
+ },
+
removeLinkText() {
return this.getCmsContent("RemoveCartItemTextWidget", "Text");
},
diff --git a/src/helpers/date-helper.js b/src/helpers/date-helper.js
index 756863765..482440431 100644
--- a/src/helpers/date-helper.js
+++ b/src/helpers/date-helper.js
@@ -5,7 +5,7 @@ export function getDateDifferenceInDays(startDate, endDate) {
// Use the built-in method to get the difference in milliseconds
var difference = date1 - date2;
// Convert milliseconds to days and return the result
- return difference / (1000 * 3600 * 24);
+ return Math.floor(difference / (1000 * 3600 * 24));
}
export function get12HourTimeFormat(time) {
// Check correct time format and split into components
diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js b/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js
new file mode 100644
index 000000000..3846a6bfd
--- /dev/null
+++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.spec.js
@@ -0,0 +1,90 @@
+import { mount, shallowMount } from "@vue/test-utils";
+import promoModalQuestion from "./promo-modal-question";
+
+jest.mock("@/digital-components/textbox-question/textbox-question", () => ({
+ getCmsContent: jest.fn((widgetName, cmsFieldName) => {
+ return widgetName[cmsFieldName];
+ }),
+}));
+
+jest.mock("@/digital-components/modal/modal", () => ({
+ methods: {
+ closeModal: jest.fn(),
+ resetButtonStyle: jest.fn(),
+ },
+}));
+
+const linkWidgetName = "linkWidgetName";
+const modalWidgetName = "modalWidgetName";
+
+const mockLinkCmsContent = {
+ BodyText: "Sample link body text here.",
+};
+
+const mockModalCmsContent = {
+ FooterText: "Sample modal footer text here.",
+};
+
+const mockMixin = {
+ methods: {
+ getCmsContent: jest.fn((widgetName, cmsFieldName) => {
+ if (widgetName === linkWidgetName) {
+ return mockLinkCmsContent[cmsFieldName];
+ }
+
+ if (widgetName === modalWidgetName) {
+ return mockModalCmsContent[cmsFieldName];
+ }
+
+ return null;
+ }),
+ },
+};
+
+describe("promo-modal-question.vue", () => {
+ it("Should reset all alerts on onModalClosed", async () => {
+ // Arrange
+
+ const wrapper = mount(promoModalQuestion, {
+ mixins: [mockMixin],
+ props: {
+ linkWidgetName: linkWidgetName,
+ modalWidgetName: modalWidgetName,
+ },
+ attachTo: document.body,
+ });
+
+ // Act
+ wrapper.vm.onModalClosed();
+
+ // Assert
+ expect(wrapper.vm.displayInvalidPromoAlert).toBe(false);
+ expect(wrapper.vm.displayInvalidOnOrderPromoAlert).toBe(false);
+ });
+ it("Should emit update:modelValue on Modal closed", async () => {
+ // Arrange
+ const lineItems = {
+ glassParts: [],
+ supportingItems: [],
+ vaps: [],
+ promos: [],
+ };
+
+ const wrapper = mount(promoModalQuestion, {
+ mixins: [mockMixin],
+ props: {
+ modelValue: lineItems,
+ linkWidgetName: linkWidgetName,
+ modalWidgetName: modalWidgetName,
+ },
+ attachTo: document.body,
+ });
+
+ // Act
+
+ await wrapper.vm.onModalClosed();
+
+ // Assert
+ expect(wrapper.emitted("update:modelValue")).toEqual([[lineItems]]);
+ });
+});
diff --git a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue
index db04dfb00..ac42fce2e 100644
--- a/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue
+++ b/src/layouts/payment-method/promo-modal-question/promo-modal-question.vue
@@ -98,16 +98,16 @@ export default {
return this.getCmsContent("AlertInvalidPromoOnOrderWidget", "HeadlineText");
},
InvalidPromoOnOrderText() {
- return this.PromoText?.replaceAll("{custom:NEWPROMOCODE}", this.promoCode).replaceAll(
- "{custom:OLDPROMOCODE}",
- this.promoCode
- );
+ return this.PromoOnOrderText?.replaceAll(
+ "{custom:NEWPROMOCODE}",
+ this.promoCode.toUpperCase()
+ ).replaceAll("{custom:OLDPROMOCODE}", this.getPromoCode().toUpperCase());
},
PromoText() {
return this.getCmsContent("AlertInvalidPromoWidget", "HeadlineText");
},
InvalidPromoText() {
- return this.PromoText?.replaceAll("{custom:PROMOCODE}", this.promoCode);
+ return this.PromoText?.replaceAll("{custom:PROMOCODE}", this.promoCode.toUpperCase());
},
removeLinkText() {
return this.getCmsContent("RemoveCartItemTextWidget", "Text");
@@ -115,6 +115,7 @@ export default {
},
methods: {
resetAlerts() {
+ this.displayInvalidOnOrderPromoAlert = false;
this.displayInvalidPromoAlert = false;
},
resetsOnPromoInput() {
@@ -123,6 +124,9 @@ export default {
getPromoList() {
return this.lineItems.promos;
},
+ getPromoCode() {
+ return this.lineItems.promos?.[0].promoCode;
+ },
openModal() {
this.modal.openModal();
},
@@ -130,7 +134,9 @@ export default {
this.modal.closeModal();
},
onModalClosed() {
+ this.resetAlerts();
this.$emit("update:modelValue", this.lineItems);
+ this.promoCode = "";
},
focusOnPromoInput() {
const input = document.getElementById(this.promoTextInputId);
@@ -139,16 +145,8 @@ export default {
resetModalButtonStyle() {
this.modal.resetButtonStyle();
},
- getPromoAddedMessage() {
- return this.AddPromoSuccessMessageFromCms?.replaceAll(
- "{custom:PROMOCODE}",
- this.promoCode
- );
- },
async getPromoCodeData(promoCode, lineItems, availableVaps, pageNameToLog = null) {
const pageName = pageNameToLog ?? this.$options?.name;
- //const addableVaps = getAddableVapsFromAvailableLineItems(availableLineItems);
- //const lineItemsToUse = lineItems.Length > 0 ? lineItems : null;
const promoValidationResponse = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA,
{
@@ -216,16 +214,16 @@ export default {
this.lineItems?.promos.push(...promoCodeData.promoCode);
this.lineItems.vaps?.push(...getVaps);
this.closeModal();
- this.promoCode = "";
} else {
if (promoCodeData.errorCode == promoErrorCodes.PROMO_STACKING_NOT_ALLOWED) {
- this.displayInvalidPromoOnOrderAlert = true;
+ this.displayInvalidOnOrderPromoAlert = true;
+ this.focusOnPromoInput();
+ this.resetModalButtonStyle();
+ } else {
+ this.displayInvalidPromoAlert = true;
this.focusOnPromoInput();
this.resetModalButtonStyle();
}
- this.displayInvalidPromoAlert = true;
- this.focusOnPromoInput();
- this.resetModalButtonStyle();
}
}
},
@@ -253,7 +251,7 @@ export default {