Merge branch 'release/2025.11.20' into rlsmerge/2025.11.20-to-develop

This commit is contained in:
CarlNation 2025-11-14 14:39:26 -05:00
commit 91655c3cb5
18 changed files with 223 additions and 280 deletions

View file

@ -509,7 +509,7 @@
'AccountService': { 'AccountService': {
baseUrl: apiUrl + '/account/api/v1', baseUrl: apiUrl + '/account/api/v1',
endpoints: [ endpoints: [
//{ path: '/healthcheck', method: 'GET' }, { path: '/healthcheck', method: 'GET' },
{ path: '/account/insurance-companies', method: 'GET' }, { path: '/account/insurance-companies', method: 'GET' },
{ path: '/account/account-details/373341', method: 'GET' }, { path: '/account/account-details/373341', method: 'GET' },
{ path: '/account/bill-to-account-number?ParentAccountNumber=373341&ProviderNumber=01820&IsItac=false&TypeOfClaim=Personal&LineOfBusiness=Commercial', method: 'GET' } { path: '/account/bill-to-account-number?ParentAccountNumber=373341&ProviderNumber=01820&IsItac=false&TypeOfClaim=Personal&LineOfBusiness=Commercial', method: 'GET' }
@ -518,7 +518,7 @@
'LocationService': { 'LocationService': {
baseUrl: apiUrl + '/location/api/v1', baseUrl: apiUrl + '/location/api/v1',
endpoints: [ endpoints: [
//{ path: '/healthcheck', method: 'GET' }, { path: '/healthcheck', method: 'GET' },
{ path: '/location/zip/43015/Replace', method: 'GET' }, { path: '/location/zip/43015/Replace', method: 'GET' },
{ path: '/location/alert-reasons/03357', method: 'GET' }, { path: '/location/alert-reasons/03357', method: 'GET' },
{ path: '/location/providers/43015/Replace/100/167132/true/CR00046193/false', method: 'GET' }, { path: '/location/providers/43015/Replace/100/167132/true/CR00046193/false', method: 'GET' },
@ -528,7 +528,7 @@
'VehicleService': { 'VehicleService': {
baseUrl: apiUrl + '/vehicle/api/v1', baseUrl: apiUrl + '/vehicle/api/v1',
endpoints: [ endpoints: [
//{ path: '/healthcheck', method: 'GET' }, { path: '/healthcheck', method: 'GET' },
{ path: '/vehicle/years', method: 'GET' }, { path: '/vehicle/years', method: 'GET' },
{ path: '/vehicle/makes/1997', method: 'GET' }, { path: '/vehicle/makes/1997', method: 'GET' },
{ path: '/vehicle/Models/1997/Toyota', method: 'GET' }, { path: '/vehicle/Models/1997/Toyota', method: 'GET' },
@ -539,7 +539,7 @@
'PartService': { 'PartService': {
baseUrl: apiUrl + '/parts/api/v1', baseUrl: apiUrl + '/parts/api/v1',
endpoints: [ endpoints: [
//{ path: '/healthcheck', method: 'GET' }, { path: '/healthcheck', method: 'GET' },
{ path: '/parts/damage-options/CR00046193', method: 'GET' }, { path: '/parts/damage-options/CR00046193', method: 'GET' },
{ path: '/parts/rain-repel', method: 'GET' }, { path: '/parts/rain-repel', method: 'GET' },
{ path: '/parts/parts-or-questions', method: 'POST', body: {"carId":"CR00046193","glassPieces":[{"location":"Windshield","name":"Single"}],"zip":"43015","vin":null,"serviceType":null,"referralSeqNumber":environmentContext.referralNumber,"AppName":"FixMyGlass"} }, { path: '/parts/parts-or-questions', method: 'POST', body: {"carId":"CR00046193","glassPieces":[{"location":"Windshield","name":"Single"}],"zip":"43015","vin":null,"serviceType":null,"referralSeqNumber":environmentContext.referralNumber,"AppName":"FixMyGlass"} },
@ -553,7 +553,7 @@
'PriceService': { 'PriceService': {
baseUrl: apiUrl + '/price/api/v1', baseUrl: apiUrl + '/price/api/v1',
endpoints: [ endpoints: [
//{ path: '/healthcheck', method: 'GET' }, { path: '/healthcheck', method: 'GET' },
{ path: '/price/taxed-order-items?ParentAccountNumber=167132&BillToAccountNumber=87291&ProviderNumber=003357&AppointmentType=Mobile&ServiceLocation.City=asdf&ServiceLocation.State=OH&ServiceLocation.ZipCode=43015&lineItems[0].partNumber=FW02018GBNN&lineItems[0].laborAmount=60&lineItems[0].kitPrice=0&lineItems[0].sellingPrice=297.33&lineItems[1].partNumber=GGG%202018&lineItems[1].laborAmount=0&lineItems[1].kitPrice=0&lineItems[1].sellingPrice=13.4&lineItems[2].partNumber=RECYCLE%20FEE&lineItems[2].laborAmount=39.99&lineItems[2].kitPrice=0&lineItems[2].sellingPrice=0&ServerData=' + encodeURIComponent(environmentContext.serverData), method: 'GET' }, { path: '/price/taxed-order-items?ParentAccountNumber=167132&BillToAccountNumber=87291&ProviderNumber=003357&AppointmentType=Mobile&ServiceLocation.City=asdf&ServiceLocation.State=OH&ServiceLocation.ZipCode=43015&lineItems[0].partNumber=FW02018GBNN&lineItems[0].laborAmount=60&lineItems[0].kitPrice=0&lineItems[0].sellingPrice=297.33&lineItems[1].partNumber=GGG%202018&lineItems[1].laborAmount=0&lineItems[1].kitPrice=0&lineItems[1].sellingPrice=13.4&lineItems[2].partNumber=RECYCLE%20FEE&lineItems[2].laborAmount=39.99&lineItems[2].kitPrice=0&lineItems[2].sellingPrice=0&ServerData=' + encodeURIComponent(environmentContext.serverData), method: 'GET' },
{ path: '/price/order-items', method: 'POST', body: { "parentAccountNumber": 167132, "billToAccountNumber": "87291", "providerNumber": "03357", "carId": "CR00046193", "year": 1997, "make": "Toyota", "model": "Camry", "eon": environmentContext.eon, "state": "OH", "referralNumber": environmentContext.referralNumber, "referralSequenceNumber": environmentContext.referralNumber, "zipCode": "43015", "serviceZipCode": "43015", "referralDate": "2025-10-29T10:55:27.18", "isReplacement": true, "deductible": 0, "coverageStatus": null, "lineItems": [ { "partNumber": "RECYCLE FEE" }, { "partNumber": "FW02018GBNN" }, { "partNumber": "GGG 2018" }, { "partNumber": "SBB19" }, { "partNumber": "SBB21" } ], "serverData": "", "AppName": "FixMyGlass" } }, { path: '/price/order-items', method: 'POST', body: { "parentAccountNumber": 167132, "billToAccountNumber": "87291", "providerNumber": "03357", "carId": "CR00046193", "year": 1997, "make": "Toyota", "model": "Camry", "eon": environmentContext.eon, "state": "OH", "referralNumber": environmentContext.referralNumber, "referralSequenceNumber": environmentContext.referralNumber, "zipCode": "43015", "serviceZipCode": "43015", "referralDate": "2025-10-29T10:55:27.18", "isReplacement": true, "deductible": 0, "coverageStatus": null, "lineItems": [ { "partNumber": "RECYCLE FEE" }, { "partNumber": "FW02018GBNN" }, { "partNumber": "GGG 2018" }, { "partNumber": "SBB19" }, { "partNumber": "SBB21" } ], "serverData": "", "AppName": "FixMyGlass" } },
{ path: '/price/order-promo', method: 'POST', body: {"promoCode":"WEBSL45","addableVaps":[{"partNumber":"RAIN REPEL","description":null,"partType":"RAIN REPEL","isInsurable":null,"id":"ccb0865d-1c0a-4be7-8605-bc7b9cb3d221","isChildPart":false,"laborAmount":0,"sellingPrice":44.99,"kitPrice":0,"salesTax":null},{"partNumber":"SBB19","description":"SAFELITE BEAM BLADE 19","partType":"FRONT WIPER","isInsurable":null,"id":"4db19a8b-739f-4f7b-983e-f6308c5f5901","isChildPart":false,"laborAmount":0,"sellingPrice":34.99,"kitPrice":0,"salesTax":null},{"partNumber":"SBB21","description":"SAFELITE BEAM BLADE 21","partType":"FRONT WIPER","isInsurable":null,"id":"e27ae20a-3a60-4fdf-a738-4b56d2e761cb","isChildPart":false,"laborAmount":0,"sellingPrice":34.99,"kitPrice":0,"salesTax":null}],"order":{"appointmentType":"Mobile","carId":"CR00046193","correlationId":"b0261e48-1111-44fc-abc9-34b41380687c","eon":environmentContext.eon,"isInsurance":false,"isRepair":false,"glassToReplace":[{"location":"Windshield","name":"Single"}],"lineItemsOnOrder":[{"partNumber":"FW02018GBNN","basePartNumber":"FW02018","description":"solar","color":"Green Tint, Blue Shade","partType":"WINDSHIELD","canSafeliteRecalibrate":false,"requiresRecalibration":false,"requiresCapabilityQuestions":false,"recalibrationType":null,"childParts":[{"partNumber":"GGG 2018","safelitePartNumber":"GGG 2018","id":"329cf0ec-8106-4e62-ab66-de0da8f18a1d","isChildPart":true,"laborAmount":0,"sellingPrice":13.4,"kitPrice":0,"salesTax":0.94}],"kitPrice":0,"sellingPrice":368.94,"laborAmount":60,"id":"4326cee6-b39e-41ff-bb29-df9220e32298","isChildPart":false,"salesTax":30.02},{"partNumber":"GGG 2018","safelitePartNumber":"GGG 2018","id":"329cf0ec-8106-4e62-ab66-de0da8f18a1d","isChildPart":true,"laborAmount":0,"sellingPrice":13.4,"kitPrice":0,"salesTax":0.94},{"partNumber":"RECYCLE FEE","description":null,"partType":"REPLACE FEE","isInsurable":null,"isChildPart":false,"laborAmount":39.99,"sellingPrice":0,"kitPrice":0,"salesTax":2.8,"id":"3771aed5-0de1-4f0e-b1ad-394f73e08f38","cartItemType":"REPLACE FEE"},{"partNumber":"MOBILE FEE","description":null,"partType":"MOBILE FEE","isInsurable":true,"isChildPart":false,"laborAmount":0,"sellingPrice":0,"kitPrice":0,"salesTax":0,"id":"2bc936ec-ef5e-4fe2-95fb-e946792b1ae5"},{"partNumber":"SBB19","description":"SAFELITE BEAM BLADE 19","partType":"FRONT WIPER","isInsurable":null,"id":"4db19a8b-739f-4f7b-983e-f6308c5f5901","isChildPart":false,"laborAmount":0,"sellingPrice":34.99,"kitPrice":0,"salesTax":2.45,"cartItemType":"FRONT WIPERS"},{"partNumber":"SBB21","description":"SAFELITE BEAM BLADE 21","partType":"FRONT WIPER","isInsurable":null,"id":"e27ae20a-3a60-4fdf-a738-4b56d2e761cb","isChildPart":false,"laborAmount":0,"sellingPrice":34.99,"kitPrice":0,"salesTax":2.45,"cartItemType":"FRONT WIPERS"},{"partNumber":"RAIN REPEL","description":null,"partType":"RAIN REPEL","isInsurable":null,"id":"ccb0865d-1c0a-4be7-8605-bc7b9cb3d221","isChildPart":false,"laborAmount":0,"sellingPrice":44.99,"kitPrice":0,"salesTax":3.15,"cartItemType":"RAIN REPEL"}],"parentAccountNumber":"167132","referralSequenceNumber":environmentContext.referralNumber,"serviceState":"OH","serverData":environmentContext.serverData,"vehicleYear":"1997","zipCodeOrProviderCtu":"03357"},"AppName":"FixMyGlass"} }, { path: '/price/order-promo', method: 'POST', body: {"promoCode":"WEBSL45","addableVaps":[{"partNumber":"RAIN REPEL","description":null,"partType":"RAIN REPEL","isInsurable":null,"id":"ccb0865d-1c0a-4be7-8605-bc7b9cb3d221","isChildPart":false,"laborAmount":0,"sellingPrice":44.99,"kitPrice":0,"salesTax":null},{"partNumber":"SBB19","description":"SAFELITE BEAM BLADE 19","partType":"FRONT WIPER","isInsurable":null,"id":"4db19a8b-739f-4f7b-983e-f6308c5f5901","isChildPart":false,"laborAmount":0,"sellingPrice":34.99,"kitPrice":0,"salesTax":null},{"partNumber":"SBB21","description":"SAFELITE BEAM BLADE 21","partType":"FRONT WIPER","isInsurable":null,"id":"e27ae20a-3a60-4fdf-a738-4b56d2e761cb","isChildPart":false,"laborAmount":0,"sellingPrice":34.99,"kitPrice":0,"salesTax":null}],"order":{"appointmentType":"Mobile","carId":"CR00046193","correlationId":"b0261e48-1111-44fc-abc9-34b41380687c","eon":environmentContext.eon,"isInsurance":false,"isRepair":false,"glassToReplace":[{"location":"Windshield","name":"Single"}],"lineItemsOnOrder":[{"partNumber":"FW02018GBNN","basePartNumber":"FW02018","description":"solar","color":"Green Tint, Blue Shade","partType":"WINDSHIELD","canSafeliteRecalibrate":false,"requiresRecalibration":false,"requiresCapabilityQuestions":false,"recalibrationType":null,"childParts":[{"partNumber":"GGG 2018","safelitePartNumber":"GGG 2018","id":"329cf0ec-8106-4e62-ab66-de0da8f18a1d","isChildPart":true,"laborAmount":0,"sellingPrice":13.4,"kitPrice":0,"salesTax":0.94}],"kitPrice":0,"sellingPrice":368.94,"laborAmount":60,"id":"4326cee6-b39e-41ff-bb29-df9220e32298","isChildPart":false,"salesTax":30.02},{"partNumber":"GGG 2018","safelitePartNumber":"GGG 2018","id":"329cf0ec-8106-4e62-ab66-de0da8f18a1d","isChildPart":true,"laborAmount":0,"sellingPrice":13.4,"kitPrice":0,"salesTax":0.94},{"partNumber":"RECYCLE FEE","description":null,"partType":"REPLACE FEE","isInsurable":null,"isChildPart":false,"laborAmount":39.99,"sellingPrice":0,"kitPrice":0,"salesTax":2.8,"id":"3771aed5-0de1-4f0e-b1ad-394f73e08f38","cartItemType":"REPLACE FEE"},{"partNumber":"MOBILE FEE","description":null,"partType":"MOBILE FEE","isInsurable":true,"isChildPart":false,"laborAmount":0,"sellingPrice":0,"kitPrice":0,"salesTax":0,"id":"2bc936ec-ef5e-4fe2-95fb-e946792b1ae5"},{"partNumber":"SBB19","description":"SAFELITE BEAM BLADE 19","partType":"FRONT WIPER","isInsurable":null,"id":"4db19a8b-739f-4f7b-983e-f6308c5f5901","isChildPart":false,"laborAmount":0,"sellingPrice":34.99,"kitPrice":0,"salesTax":2.45,"cartItemType":"FRONT WIPERS"},{"partNumber":"SBB21","description":"SAFELITE BEAM BLADE 21","partType":"FRONT WIPER","isInsurable":null,"id":"e27ae20a-3a60-4fdf-a738-4b56d2e761cb","isChildPart":false,"laborAmount":0,"sellingPrice":34.99,"kitPrice":0,"salesTax":2.45,"cartItemType":"FRONT WIPERS"},{"partNumber":"RAIN REPEL","description":null,"partType":"RAIN REPEL","isInsurable":null,"id":"ccb0865d-1c0a-4be7-8605-bc7b9cb3d221","isChildPart":false,"laborAmount":0,"sellingPrice":44.99,"kitPrice":0,"salesTax":3.15,"cartItemType":"RAIN REPEL"}],"parentAccountNumber":"167132","referralSequenceNumber":environmentContext.referralNumber,"serviceState":"OH","serverData":environmentContext.serverData,"vehicleYear":"1997","zipCodeOrProviderCtu":"03357"},"AppName":"FixMyGlass"} },
@ -563,7 +563,7 @@
'ScheduleService': { 'ScheduleService': {
baseUrl: apiUrl + '/schedule/api/v1', baseUrl: apiUrl + '/schedule/api/v1',
endpoints: [ endpoints: [
//{ path: '/healthcheck', method: 'GET' }, { path: '/healthcheck', method: 'GET' },
{ path: '/schedule/mobile-time-slots', method: 'POST', body: {"startDate":startDate,"endDate":endDate,"applicationName":"FixMyGlass","parentAccountNumber":"167132","carId":"CR00046193","lineItems":[{"partNumber":"RECYCLE FEE","partType":"REPLACE FEE","isGlassPart":false},{"partNumber":"SBB19","partType":"FRONT WIPER","isGlassPart":false},{"partNumber":"SBB21","partType":"FRONT WIPER","isGlassPart":false},{"partNumber":"RAIN REPEL","partType":"RAIN REPEL","isGlassPart":false},{"partNumber":"FW02018GBNN","partType":"WINDSHIELD","isGlassPart":true},{"partNumber":"GGG 2018","isGlassPart":false}],"glassPieces":[{"location":"Windshield","name":"Single"}],"eon":environmentContext.eon,"billToAccountNumber":"87291","coverage":{"status":null,"deductible":0,"additionalAuthFlag":null},"partSelection":{"hasAnsweredPartQuestions":false,"hasAnsweredMoldingQuestions":false,"hasAnsweredCapabilityQuestions":false,"hasManuallySelectedParts":false},"vehicle":{"year":1997,"make":"Toyota","model":"Camry","style":"4 door sedan","vin":""},"zipCode":"43015","AppName":"FixMyGlass"} }, { path: '/schedule/mobile-time-slots', method: 'POST', body: {"startDate":startDate,"endDate":endDate,"applicationName":"FixMyGlass","parentAccountNumber":"167132","carId":"CR00046193","lineItems":[{"partNumber":"RECYCLE FEE","partType":"REPLACE FEE","isGlassPart":false},{"partNumber":"SBB19","partType":"FRONT WIPER","isGlassPart":false},{"partNumber":"SBB21","partType":"FRONT WIPER","isGlassPart":false},{"partNumber":"RAIN REPEL","partType":"RAIN REPEL","isGlassPart":false},{"partNumber":"FW02018GBNN","partType":"WINDSHIELD","isGlassPart":true},{"partNumber":"GGG 2018","isGlassPart":false}],"glassPieces":[{"location":"Windshield","name":"Single"}],"eon":environmentContext.eon,"billToAccountNumber":"87291","coverage":{"status":null,"deductible":0,"additionalAuthFlag":null},"partSelection":{"hasAnsweredPartQuestions":false,"hasAnsweredMoldingQuestions":false,"hasAnsweredCapabilityQuestions":false,"hasManuallySelectedParts":false},"vehicle":{"year":1997,"make":"Toyota","model":"Camry","style":"4 door sedan","vin":""},"zipCode":"43015","AppName":"FixMyGlass"} },
{ path: '/schedule/shop-time-slots', method: 'POST', body: {"providerNumber":"003417","startDate":startDate,"endDate":endDate,"shopAppointmentType":"InshopOrDropoff","applicationName":"FixMyGlass","parentAccountNumber":"167132","carId":"CR00046193","lineItems":[{"partNumber":"RECYCLE FEE","partType":"REPLACE FEE","isGlassPart":false},{"partNumber":"FW02018GBNN","partType":"WINDSHIELD","isGlassPart":true},{"partNumber":"GGG 2018","isGlassPart":false}],"glassPieces":[{"location":"Windshield","name":"Single"}],"eon":environmentContext.eon,"billToAccountNumber":"87291","coverage":{"status":null,"deductible":0,"additionalAuthFlag":null},"partSelection":{"hasAnsweredPartQuestions":false,"hasAnsweredMoldingQuestions":false,"hasAnsweredCapabilityQuestions":false,"hasManuallySelectedParts":false},"vehicle":{"year":1997,"make":"Toyota","model":"Camry","style":"4 door sedan","vin":""},"AppName":"FixMyGlass"} } { path: '/schedule/shop-time-slots', method: 'POST', body: {"providerNumber":"003417","startDate":startDate,"endDate":endDate,"shopAppointmentType":"InshopOrDropoff","applicationName":"FixMyGlass","parentAccountNumber":"167132","carId":"CR00046193","lineItems":[{"partNumber":"RECYCLE FEE","partType":"REPLACE FEE","isGlassPart":false},{"partNumber":"FW02018GBNN","partType":"WINDSHIELD","isGlassPart":true},{"partNumber":"GGG 2018","isGlassPart":false}],"glassPieces":[{"location":"Windshield","name":"Single"}],"eon":environmentContext.eon,"billToAccountNumber":"87291","coverage":{"status":null,"deductible":0,"additionalAuthFlag":null},"partSelection":{"hasAnsweredPartQuestions":false,"hasAnsweredMoldingQuestions":false,"hasAnsweredCapabilityQuestions":false,"hasManuallySelectedParts":false},"vehicle":{"year":1997,"make":"Toyota","model":"Camry","style":"4 door sedan","vin":""},"AppName":"FixMyGlass"} }
] ]
@ -571,25 +571,25 @@
'AnalyticsService': { 'AnalyticsService': {
baseUrl: apiUrl + '/analytics/api/v1', baseUrl: apiUrl + '/analytics/api/v1',
endpoints: [ endpoints: [
//{ path: '/healthcheck', method: 'GET' }, { path: '/healthcheck', method: 'GET' },
] ]
}, },
'ExperimentService': { 'ExperimentService': {
baseUrl: apiUrl + '/experiments/api/v1', baseUrl: apiUrl + '/experiments/api/v1',
endpoints: [ endpoints: [
//{ path: '/healthcheck', method: 'GET' }, { path: '/healthcheck', method: 'GET' },
] ]
}, },
'OrderService': { 'OrderService': {
baseUrl: apiUrl + '/order/api/v1', baseUrl: apiUrl + '/order/api/v1',
endpoints: [ endpoints: [
//{ path: '/healthcheck', method: 'GET' }, { path: '/healthcheck', method: 'GET' },
] ]
}, },
'ContentService': { 'ContentService': {
baseUrl: apiUrl + '/content/api/v1', baseUrl: apiUrl + '/content/api/v1',
endpoints: [ endpoints: [
//{ path: '/healthcheck', method: 'GET' }, { path: '/healthcheck', method: 'GET' },
{ path: '/content/fmg/vehicle', method: 'GET' }, { path: '/content/fmg/vehicle', method: 'GET' },
] ]
} }
@ -674,7 +674,7 @@
} }
function updateAtAGlanceText() { function updateAtAGlanceText() {
const healthyCount = Object.values(healthData).filter(service => service.status === 'healthy').length; const healthyCount = Object.values(healthData).filter(service => (service.status === 'healthy' || service.status === 'degraded')).length;
const totalCount = Object.values(healthData).length; const totalCount = Object.values(healthData).length;
let text = 'Healthy'; let text = 'Healthy';
let className = 'stat-pill stat-pill-healthy'; let className = 'stat-pill stat-pill-healthy';
@ -763,14 +763,15 @@
// Determine overall service status // Determine overall service status
const endpoints = healthData[serviceName].endpoints; const endpoints = healthData[serviceName].endpoints;
const healthyCount = endpoints.filter(ep => !isDegraded(ep) && !isUnhealthy(ep)).length; const healthyCount = endpoints.filter(ep => !isDegraded(ep) && !isUnhealthy(ep)).length;
const unhealthyCount = endpoints.filter(ep => isUnhealthy(ep)).length;
const totalCount = endpoints.length; const totalCount = endpoints.length;
if (healthyCount === totalCount) { if (healthyCount === totalCount) {
healthData[serviceName].status = 'healthy'; healthData[serviceName].status = 'healthy';
} else if (healthyCount > 0) { } else if (unhealthyCount > 0) {
healthData[serviceName].status = 'degraded';
} else {
healthData[serviceName].status = 'unhealthy'; healthData[serviceName].status = 'unhealthy';
} else {
healthData[serviceName].status = 'degraded';
} }
} }

View file

@ -3,7 +3,7 @@ const cartItemCategories = {
GLASS_PARTS: "glassParts", GLASS_PARTS: "glassParts",
SUPPORTING_ITEMS: "supportingItems", SUPPORTING_ITEMS: "supportingItems",
PROMOS: "promos", PROMOS: "promos",
QUOTE_PAGE_DISCOUNT: "quotePageDiscount", SERVICE_PACKAGE_DISCOUNT: "servicePackageDiscount",
}; };
export { cartItemCategories }; export { cartItemCategories };

View file

@ -10,7 +10,7 @@ const cartItemTypes = {
PROMOS: "PROMOS", PROMOS: "PROMOS",
EARLY_BIRD: "EARLY BIRD", EARLY_BIRD: "EARLY BIRD",
SUPPLIES_REPAIR: "SUPPLIES-REPAIR", SUPPLIES_REPAIR: "SUPPLIES-REPAIR",
QUOTE_PAGE_DISCOUNT: "QUOTE PAGE DISCOUNT", SERVICE_PACKAGE_DISCOUNT: "SERVICE PACKAGE DISCOUNT",
DONATION: "DONATION", DONATION: "DONATION",
}; };

View file

@ -10,7 +10,6 @@ const partTypeStrings = {
REPAIR_FEE: "REPAIR FEE", REPAIR_FEE: "REPAIR FEE",
EARLY_BIRD: "EARLY BIRD", EARLY_BIRD: "EARLY BIRD",
SERVICE_PACKAGE_DISCOUNT: "SERVICE PACKAGE DISCOUNT", SERVICE_PACKAGE_DISCOUNT: "SERVICE PACKAGE DISCOUNT",
QUOTE_PAGE_DISCOUNT: "QUOTE PAGE DISCOUNT",
DONATION: "DONATION", DONATION: "DONATION",
}; };

View file

@ -1,80 +0,0 @@
import { packageNames } from "./package-names";
import { partTypeStrings } from "./part-type-strings";
export const quotePageDiscountTable = [
// Repair
{
name: "Repair Glass Only",
experimentCode: "Show_GlassOnly_Repair_Discount",
partNumber: "GL RPR CSH PKG",
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
description: "GLASS RPR GEOTARGET DISC",
packageLevel: packageNames.TIER_ONE,
},
{
name: "Repair Standard",
experimentCode: "Show_Standard_Repair_Discount",
partNumber: "STD RPR CSH PKG",
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
description: "STD RPR GEOTARGET DISC",
packageLevel: packageNames.TIER_TWO,
},
{
name: "Repair Premium",
experimentCode: "Show_Premium_Repair_Discount",
partNumber: "PRM RPR CSH PKG",
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
description: "PREM RPR GEOTARGET DISC",
packageLevel: packageNames.TIER_THREE,
},
// Replace - No recal
{
name: "Replace Glass Only",
experimentCode: "Show_GlassOnly_Replace_Discount",
partNumber: "GL RPL CSH PKG",
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
description: "GLASS RPL GEOTARGET DISC",
packageLevel: packageNames.TIER_ONE,
},
{
name: "Replace Standard",
experimentCode: "Show_Standard_Replace_Discount",
partNumber: "STD RPL CSH PKG",
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
description: "STD RPL GEOTARGET DISC",
packageLevel: packageNames.TIER_TWO,
},
{
name: "Replace Premium",
experimentCode: "Show_Premium_Replace_Discount",
partNumber: "PRM RPL CSH PKG",
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
description: "PREM RPL GEOTARGET DISC",
packageLevel: packageNames.TIER_THREE,
},
// Replace - with recal
{
name: "Recal Glass Only",
experimentCode: "Show_GlassOnly_Recal_Discount",
partNumber: "GL RCL CSH PKG",
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
description: "GLASS RCL GEOTARGET DISC",
packageLevel: packageNames.TIER_ONE,
},
{
name: "Recal Standard",
experimentCode: "Show_Standard_Recal_Discount",
partNumber: "STD RCL CSH PKG",
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
description: "STD RCL GEOTARGET DISC",
packageLevel: packageNames.TIER_TWO,
},
{
name: "Recal Premium",
experimentCode: "Show_Premium_Recal_Discount",
partNumber: "PRM RCL CSH PKG",
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
description: "PREM RCL GEOTARGET DISC",
packageLevel: packageNames.TIER_THREE,
},
];

View file

@ -145,7 +145,9 @@ export default {
return "$" + decimalPrice.toFixed(2); return "$" + decimalPrice.toFixed(2);
}, },
hasPackageDiscount() { hasPackageDiscount() {
return this.additionalButtonData.hasDiscount && this.additionalButtonData.Text; return (
this.additionalButtonData.servicePackageDiscount && this.additionalButtonData.Text
);
}, },
}, },
}; };

View file

@ -4,11 +4,11 @@
class="package-label pricing-by-day-pkg-lbl" class="package-label pricing-by-day-pkg-lbl"
:class="[ :class="[
this.buttonLabelSubCopy ? 'has-subheader' : '', this.buttonLabelSubCopy ? 'has-subheader' : '',
!this.additionalButtonData.hasDiscount ? 'adjust-top' : '', !this.additionalButtonData.servicePackageDiscount ? 'adjust-top' : '',
]" ]"
for="testradio"> for="testradio">
<div class="package-specs"> <div class="package-specs">
<div v-if="this.additionalButtonData.hasDiscount" class="row"> <div v-if="this.additionalButtonData.servicePackageDiscount" class="row">
<div class="col md-6"> <div class="col md-6">
<p class="m-0"> <p class="m-0">
<span v-html="this.buttonLabel"></span> <span v-html="this.buttonLabel"></span>
@ -84,7 +84,10 @@
</div> </div>
<div <div
v-if="this.additionalButtonData.hasDiscount && this.additionalButtonData.Text" v-if="
this.additionalButtonData.servicePackageDiscount &&
this.additionalButtonData.Text
"
class="special-save-box"> class="special-save-box">
<span v-html="this.additionalButtonData.Text"></span> <span v-html="this.additionalButtonData.Text"></span>
</div> </div>

View file

@ -190,7 +190,6 @@ import { cartItemCategories } from "@/constants/cart-item-categories";
import { cartItemTypes } from "@/constants/cart-item-types"; import { cartItemTypes } from "@/constants/cart-item-types";
import { coverageStatus, cartItemTypesCoveredByInsurance } from "@/constants/insurance"; import { coverageStatus, cartItemTypesCoveredByInsurance } from "@/constants/insurance";
import { experimentSettings } from "@/constants/experiments"; import { experimentSettings } from "@/constants/experiments";
import { quotePageDiscountTable } from "@/constants/quote-page-discounts";
export default { export default {
name: "cart", name: "cart",
@ -257,11 +256,11 @@ export default {
return subTotal; return subTotal;
}, },
getQuotePageDiscount() { getServicePackageDiscount() {
const quotePageDiscountLineItems = this.quotePageDiscountCartItem; const servicePackageDiscountLineItems = this.servicePackageDiscountCartItem;
let subTotal = 0; let subTotal = 0;
subTotal += quotePageDiscountLineItems?.subTotal ?? 0; subTotal += servicePackageDiscountLineItems?.subTotal ?? 0;
return subTotal; return subTotal;
}, },
getVapsCartItemsForSelectedPackage(packageName) { getVapsCartItemsForSelectedPackage(packageName) {
@ -304,8 +303,7 @@ export default {
getLineItemAmount(amount, useVerifyingText, category) { getLineItemAmount(amount, useVerifyingText, category) {
if (useVerifyingText) return this.verifyingCoverageText; if (useVerifyingText) return this.verifyingCoverageText;
return category == cartItemCategories.PROMOS || return category == "promos" || category == "servicePackageDiscount"
category == cartItemCategories.QUOTE_PAGE_DISCOUNT
? "(" + this.currencyFormatter.format(amount * -1) + ")" ? "(" + this.currencyFormatter.format(amount * -1) + ")"
: this.currencyFormatter.format(amount); : this.currencyFormatter.format(amount);
}, },
@ -318,21 +316,16 @@ export default {
if (category == cartItemCategories.VAPS || category == cartItemCategories.PROMOS) { if (category == cartItemCategories.VAPS || category == cartItemCategories.PROMOS) {
this.saveVaps(this.lineItems); this.saveVaps(this.lineItems);
// Check if service package discount should be removed after vaps change // Check if service package discount should be removed after vaps change
if (this.quotePageDiscountCartItem) { if (
const existingLineItem = this.quotePageDiscountCartItem.lineItems.at(0); this.servicePackageDiscountCartItem &&
const discountInfo = quotePageDiscountTable.find( this.discountPackageNames != this.packageLevel
(info) => info.partNumber === existingLineItem?.partNumber ) {
this.lineItems.supportingItems = this.lineItems.supportingItems.filter(
(lineItemsToKeep) =>
lineItemsToKeep.cartItemType !=
this.servicePackageDiscountCartItem.cartItemType
); );
const packageLevelForDiscount = discountInfo?.packageLevel; shouldSaveSupportingItems = true;
if (this.packageLevel !== packageLevelForDiscount) {
this.lineItems.supportingItems = this.lineItems.supportingItems.filter(
(lineItemsToKeep) =>
lineItemsToKeep.cartItemType !=
this.quotePageDiscountCartItem.cartItemType
);
shouldSaveSupportingItems = true;
}
} }
} }
if (shouldSaveSupportingItems) { if (shouldSaveSupportingItems) {
@ -490,8 +483,8 @@ export default {
cartItems.push(this.mobileFeeCartItem); cartItems.push(this.mobileFeeCartItem);
} }
if (this.quotePageDiscountCartItem) { if (this.servicePackageDiscountCartItem) {
cartItems.push(this.quotePageDiscountCartItem); cartItems.push(this.servicePackageDiscountCartItem);
} }
if (this.premiumAppointmentDiscountCartItem) { if (this.premiumAppointmentDiscountCartItem) {
@ -507,6 +500,12 @@ export default {
return cartItems; return cartItems;
}, },
}, },
discountPackageNames() {
const discountServicePackage = experimentMixin.methods.getSettingValue(
experimentSettings.PROMO_ON_PACKAGE
);
return getDiscountedPackageName(discountServicePackage);
},
servicePackageTitleWidget() { servicePackageTitleWidget() {
const servicePackageNames = this.getCmsContent( const servicePackageNames = this.getCmsContent(
this.servicePackageOptionsCmsName, this.servicePackageOptionsCmsName,
@ -551,8 +550,8 @@ export default {
} }
packagePrice += this.getVapsPrice(this.packageLevel); packagePrice += this.getVapsPrice(this.packageLevel);
if (this.quotePageDiscountCartItem) { if (this.servicePackageDiscountCartItem) {
packagePrice -= this.getQuotePageDiscount(); packagePrice -= this.getServicePackageDiscount();
} }
return packagePrice; return packagePrice;
@ -929,25 +928,25 @@ export default {
} }
return cartItem; return cartItem;
}, },
quotePageDiscountCartItemName() { servicePackageDiscountCartItemName() {
return this.getCmsContent("ServicePackageDiscountTextWidget", "Text"); return this.getCmsContent("ServicePackageDiscountTextWidget", "Text");
}, },
quotePageDiscountCartItem() { servicePackageDiscountCartItem() {
let cartItem = null; let cartItem = null;
const quotePageDiscountLineItem = this.supportingItems.find( const servicePackageDiscountLineItem = this.supportingItems.find(
(lineItem) => lineItem.partType == partTypeStrings.QUOTE_PAGE_DISCOUNT (lineItem) => lineItem.partType == partTypeStrings.SERVICE_PACKAGE_DISCOUNT
); );
if (quotePageDiscountLineItem) { if (servicePackageDiscountLineItem) {
cartItem = { cartItem = {
name: name:
this.quotePageDiscountCartItemName + this.servicePackageDiscountCartItemName +
Math.abs( Math.abs(
baseMixin.methods.getTotalLineItemPrice(quotePageDiscountLineItem) baseMixin.methods.getTotalLineItemPrice(servicePackageDiscountLineItem)
), ),
category: cartItemCategories.QUOTE_PAGE_DISCOUNT, category: cartItemCategories.SERVICE_PACKAGE_DISCOUNT,
cartItemType: cartItemTypes.QUOTE_PAGE_DISCOUNT, cartItemType: cartItemTypes.SERVICE_PACKAGE_DISCOUNT,
isDisplayed: true, isDisplayed: true,
isRemovable: false, isRemovable: false,
subTotal: 0, subTotal: 0,
@ -956,15 +955,15 @@ export default {
isCoveredByInsurance: false, isCoveredByInsurance: false,
}; };
quotePageDiscountLineItem.cartItemType = cartItem.cartItemType; servicePackageDiscountLineItem.cartItemType = cartItem.cartItemType;
cartItem.lineItems.push(quotePageDiscountLineItem); cartItem.lineItems.push(servicePackageDiscountLineItem);
cartItem.subTotal += cartItem.subTotal +=
(quotePageDiscountLineItem.kitPrice ?? 0) + (servicePackageDiscountLineItem.kitPrice ?? 0) +
(quotePageDiscountLineItem.laborAmount ?? 0) + (servicePackageDiscountLineItem.laborAmount ?? 0) +
(quotePageDiscountLineItem.sellingPrice ?? 0); (servicePackageDiscountLineItem.sellingPrice ?? 0);
cartItem.salesTax += quotePageDiscountLineItem.salesTax ?? 0; cartItem.salesTax += servicePackageDiscountLineItem.salesTax ?? 0;
} }
return cartItem; return cartItem;
@ -973,7 +972,7 @@ export default {
let cartItem = null; let cartItem = null;
const otherSupportingItems = this.supportingItems.filter((item) => { const otherSupportingItems = this.supportingItems.filter((item) => {
return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; return item.partType != partTypeStrings.SERVICE_PACKAGE_DISCOUNT;
}); });
// Don't include fees they are part of the package total // Don't include fees they are part of the package total
let otherSupportingItemsLineItems = let otherSupportingItemsLineItems =

View file

@ -163,6 +163,7 @@ export default {
.callout { .callout {
font-family: UrbanistSemibold, Arial, Helvetica, sans-serif; font-family: UrbanistSemibold, Arial, Helvetica, sans-serif;
white-space: nowrap;
} }
> div:first-of-type { > div:first-of-type {
@ -196,7 +197,7 @@ export default {
} }
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
padding-left: 1rem; padding-left: 1rem;
max-width: 32rem; max-width: 36rem;
} }
} }
} }

View file

@ -82,7 +82,7 @@ jest.mock("@/mixins/base-mixin", () => ({
filterOutFees(items) { filterOutFees(items) {
return null; return null;
}, },
filterOutQuotePageDiscountPart(items) { filterOutServicePackageDiscountPart(items) {
return null; return null;
}, },
isFormValid(form) { isFormValid(form) {

View file

@ -31,11 +31,10 @@
:isRecalibrationOnOrder="isRecalibrationOnOrder" :isRecalibrationOnOrder="isRecalibrationOnOrder"
:shouldHideRecalibration="shouldHideRecalibration" :shouldHideRecalibration="shouldHideRecalibration"
@vapsItemsSelected="vapsItemsSelectedAction" @vapsItemsSelected="vapsItemsSelectedAction"
@quotePageDiscountSelected="quotePageDiscountSelectedAction" @servicePackageDiscountSelected="servicePackageDiscountSelectedAction"
@currentNumberOfPackages="currentNumberOfPackagesAction" @currentNumberOfPackages="currentNumberOfPackagesAction"
:servicePackage="servicePackage" :servicePackage="servicePackage"
:activePromos="lineItems.promos" :activePromos="lineItems.promos"
:availableQuotePageDiscounts="quoteDiscountPartsInfo"
v-on="{ 'buttonEvent.openModal': openModalAction }" v-on="{ 'buttonEvent.openModal': openModalAction }"
validationRules="option-required" validationRules="option-required"
isRequired /> isRequired />
@ -175,7 +174,6 @@ import { consumeQueryFromStash } from "@/router/methods/helpers/querystring-stas
import { storeMutations } from "@/constants/store-mutations"; import { storeMutations } from "@/constants/store-mutations";
import { debugLog } from "@/helpers/debug-log-helper"; import { debugLog } from "@/helpers/debug-log-helper";
import { savePageData } from "@/router/methods/helpers/save-page-data"; import { savePageData } from "@/router/methods/helpers/save-page-data";
import { quotePageDiscountTable } from "../../constants/quote-page-discounts";
defineRule("option-required", required(errorMessages.OPTION_REQUIRED)); defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
@ -186,14 +184,6 @@ const ACCEPTED_QUOTE_TYPES = {
INSURANCE: "insurance", INSURANCE: "insurance",
}; };
function getAvailableQuotePageDiscounts() {
const activeDiscounts = quotePageDiscountTable?.filter((discountEntry) =>
experimentMixin?.methods?.hasSettingEqualTo(discountEntry?.experimentCode, "true")
);
return activeDiscounts ?? [];
}
export default { export default {
name: "quote", name: "quote",
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
@ -310,22 +300,29 @@ export default {
const lineItems = deepClone(store.getters.order.lineItems); const lineItems = deepClone(store.getters.order.lineItems);
lineItems.vaps = lineItems.vaps ?? []; lineItems.vaps = lineItems.vaps ?? [];
const nullSafeGlassParts = lineItems.glassParts ?? []; const nullSafeGlassParts = lineItems.glassParts ?? [];
const servicePackageDiscountSettingValue = experimentMixin.methods.getSettingValue(
const quotePageDiscountPartsInfo = getAvailableQuotePageDiscounts(); experimentSettings.SERVICE_PACKAGE_DISCOUNT
);
const quotePageDiscountParts = quotePageDiscountPartsInfo.map((partInfo) => ({ const isServicePackageDiscount = servicePackageDiscountSettingValue === "True";
partNumber: partInfo.partNumber, //Service package cash discount api call when experiment is active
partType: partInfo.partType, var servicePackageDiscountPart = [];
description: partInfo.description, if (isServicePackageDiscount) {
isInsurable: null, const servicePackageDiscountPartResponse =
})); await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_SERVICE_PACKAGE_DISCOUNT_PART,
null,
"quote"
);
if (servicePackageDiscountPartResponse.data) {
servicePackageDiscountPart.push(servicePackageDiscountPartResponse.data);
}
}
const availableLineItems = [ const availableLineItems = [
resultMap.rainRepel, resultMap.rainRepel,
...resultMap.supportingItems, ...resultMap.supportingItems,
...resultMap.wipers, ...resultMap.wipers,
...nullSafeGlassParts, ...nullSafeGlassParts,
...quotePageDiscountParts, ...servicePackageDiscountPart,
]; ];
// When calling pricing from the quote page, always use the cash parent account but save the existing one in case it's unverified insurance navigating backwards // When calling pricing from the quote page, always use the cash parent account but save the existing one in case it's unverified insurance navigating backwards
@ -352,7 +349,7 @@ export default {
false false
); );
// This will remove any discount item from lineItems.supportingItems // This will remove any servicePackageDiscount item from lineItems.supportingItems
baseMixin.methods.dispatchStoreAction( baseMixin.methods.dispatchStoreAction(
storeActions.SAVE_SUPPORTING_ITEMS, storeActions.SAVE_SUPPORTING_ITEMS,
resultMap.supportingItems, resultMap.supportingItems,
@ -454,9 +451,10 @@ export default {
) )
: baseMixin.methods.filterOutFees(availableLineItems); : baseMixin.methods.filterOutFees(availableLineItems);
const lineItemsNoDiscount = baseMixin.methods.filterOutQuotePageDiscountPart( const lineItemsNoDiscount =
lineItemsForCalculatingPrice baseMixin.methods.filterOutServicePackageDiscountPart(
); lineItemsForCalculatingPrice
);
if (isInsuranceFromQueryString != null) { if (isInsuranceFromQueryString != null) {
if (isInsuranceFromQueryString.toLowerCase() === "true") { if (isInsuranceFromQueryString.toLowerCase() === "true") {
@ -580,8 +578,17 @@ export default {
isRecalibrationOnOrder() { isRecalibrationOnOrder() {
return store.getters.isRecalibrationOnOrder; return store.getters.isRecalibrationOnOrder;
}, },
isQuotePageDiscountOnOrder() { isServicePackageDiscountOnOrder() {
return this.quotePageDiscountPartsInfo?.length > 0; return containsLineItemWithPartType(
partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
this.availableLineItems
);
},
servicePackageDiscountParts() {
return findLineItemsWithPartType(
partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
this.availableLineItems
);
}, },
shouldHideRecalibration() { shouldHideRecalibration() {
return ( return (
@ -610,23 +617,6 @@ export default {
thresholdAmount && (thresholdAmount = parseInt(thresholdAmount)); thresholdAmount && (thresholdAmount = parseInt(thresholdAmount));
return thresholdAmount; return thresholdAmount;
}, },
quoteDiscountPartsInfo() {
const defs = getAvailableQuotePageDiscounts();
const withPrices = defs
.map((def) => {
const match = this.availableLineItems?.find?.(
(pricedItem) => pricedItem.partNumber === def.partNumber
);
return {
packageLevel: def.packageLevel,
item: match,
};
})
.filter((result) => result.item);
return withPrices;
},
}, },
methods: { methods: {
getColCount() { getColCount() {
@ -670,7 +660,7 @@ export default {
vapsItemsSelectedAction(vapsItemsSelected) { vapsItemsSelectedAction(vapsItemsSelected) {
this.lineItems.vaps = vapsItemsSelected; this.lineItems.vaps = vapsItemsSelected;
}, },
quotePageDiscountSelectedAction(supportingItemsSelected) { servicePackageDiscountSelectedAction(supportingItemsSelected) {
this.lineItems.supportingItems = supportingItemsSelected; this.lineItems.supportingItems = supportingItemsSelected;
}, },
backButtonAction() { backButtonAction() {
@ -732,10 +722,10 @@ export default {
false false
); );
} }
if (this.isInsuranceSelected && this.isQuotePageDiscountOnOrder) { if (this.isInsuranceSelected && this.isServicePackageDiscountOnOrder) {
let supportingItems = this.lineItems.supportingItems; let supportingItems = this.lineItems.supportingItems;
supportingItems = supportingItems.filter((item) => { supportingItems = supportingItems.filter((item) => {
return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; return item.partType != this.servicePackageDiscountParts[0].partType;
}); });
this.dispatchStoreAction( this.dispatchStoreAction(
this.storeActions.SAVE_SUPPORTING_ITEMS, this.storeActions.SAVE_SUPPORTING_ITEMS,
@ -821,23 +811,19 @@ export default {
lineItemsToPrice = lineItemsToPrice =
baseMixin.methods.filterOutRecalibration(lineItemsToPrice); baseMixin.methods.filterOutRecalibration(lineItemsToPrice);
} }
if (this.isQuotePageDiscountOnOrder) { if (this.isServicePackageDiscountOnOrder) {
lineItemsToPrice = lineItemsToPrice?.filter((item) => { lineItemsToPrice = lineItemsToPrice?.filter((item) => {
return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; return (
item.partType != this.servicePackageDiscountParts[0].partType
);
}); });
} }
let price = 0; let price = 0;
if ( if (
tier.additionalButtonData?.hasDiscount && tier.additionalButtonData?.servicePackageDiscount &&
this.isQuotePageDiscountOnOrder this.isServicePackageDiscountOnOrder
) { ) {
const parts = this.quoteDiscountPartsInfo; lineItemsToPrice.push(...this.servicePackageDiscountParts);
const matchPart = parts.find(
(discountInfo) => discountInfo.packageLevel === tier
);
if (matchPart) {
lineItemsToPrice.push(matchPart);
}
} }
price += baseMixin.methods.getTierOnePackagePrice( price += baseMixin.methods.getTierOnePackagePrice(
baseMixin.methods.filterOutFees(lineItemsToPrice) baseMixin.methods.filterOutFees(lineItemsToPrice)

View file

@ -14,7 +14,6 @@ import { experimentSettings } from "@/constants/experiments";
import baseMixin from "@/mixins/base-mixin.js"; import baseMixin from "@/mixins/base-mixin.js";
import { partTypeStrings } from "@/constants/part-type-strings"; import { partTypeStrings } from "@/constants/part-type-strings";
import { nextTick } from "vue"; import { nextTick } from "vue";
import { packageNames } from "../../../constants/package-names";
jest.mock("@/store", () => ({ jest.mock("@/store", () => ({
commit: jest.fn(), commit: jest.fn(),
@ -74,9 +73,9 @@ describe("service-package-question.vue", () => {
price: 35.5, price: 35.5,
}, },
{ {
partNumber: "PRM RCL CSH PKG", partNumber: "DISC CASHSAVE70",
description: null, description: null,
partType: "QUOTE PAGE DISCOUNT", partType: "SERVICE PACKAGE DISCOUNT",
price: -70, price: -70,
}, },
], ],
@ -106,27 +105,13 @@ describe("service-package-question.vue", () => {
description: null, description: null,
kitPrice: 0, kitPrice: 0,
laborAmount: 0, laborAmount: 0,
partNumber: "PRM RCL CSH PKG", partNumber: "DISC CASHSAVE70",
partType: "QUOTE PAGE DISCOUNT", partType: "SERVICE PACKAGE DISCOUNT",
salesTax: null, salesTax: null,
sellingPrice: -70, sellingPrice: -70,
}, },
], ],
}, },
availableQuotePageDiscounts: [
{
packageLevel: packageNames.TIER_THREE,
item: {
description: null,
kitPrice: 0,
laborAmount: 0,
partNumber: "PRM RCL CSH PKG",
partType: "QUOTE PAGE DISCOUNT",
salesTax: null,
sellingPrice: -70,
},
},
],
activePromos: [], activePromos: [],
}; };
const packageNameKey = "05_01_CSR_Quote_Standard_Repair"; const packageNameKey = "05_01_CSR_Quote_Standard_Repair";
@ -151,17 +136,41 @@ describe("service-package-question.vue", () => {
}); });
it("should return price when there is discount", () => { it("should return price when there is discount", () => {
const wrapper = setupMocks({}); const wrapper = setupMocks({});
const partType = partTypeStrings.SERVICE_PACKAGE_DISCOUNT;
const price = wrapper.vm.getDiscountPrice(packageNames.TIER_THREE); wrapper.vm.isServicePackageDiscountOnOrder = containsLineItemWithPartType(
partType,
mockProps.lineItems.supportingItems
);
const servicePackageDiscountLineItem = findLineItemsWithPartType(
partType,
mockProps.lineItems.supportingItems
);
wrapper.vm.getServicePackageDiscountPrice();
const price = baseMixin.methods.getTotalLineItemPrice(servicePackageDiscountLineItem[0]);
expect(Math.abs(price)).toEqual(70); expect(Math.abs(price)).toEqual(70);
}); });
it("isDiscountOnOrder returns true if it contains quote package discount lineItems", () => { it("isServicePackageDiscountOnOrder returns true if it contains service package discount lineItems", () => {
// Arrange // Arrange
const wrapper = setupMocks({}); const wrapper = setupMocks({});
// Assert // Assert
expect(wrapper.vm.isDiscountOnOrder).toBe(true); expect(wrapper.vm.isServicePackageDiscountOnOrder).toBe(true);
});
it("servicePackageDiscountParts should returns service package discount lineItems", () => {
// Arrange
const wrapper = setupMocks({});
// Assert
expect(wrapper.vm.servicePackageDiscountParts).toEqual([
{
partNumber: "DISC CASHSAVE70",
description: null,
partType: "SERVICE PACKAGE DISCOUNT",
price: -70,
},
]);
}); });
it("should have the correct insurance pricing text when insurance is selected", () => { it("should have the correct insurance pricing text when insurance is selected", () => {
// Arrange // Arrange

View file

@ -60,7 +60,6 @@ export default {
servicePackage: null, servicePackage: null,
isRecalibrationOnOrder: Boolean, isRecalibrationOnOrder: Boolean,
shouldHideRecalibration: Boolean, shouldHideRecalibration: Boolean,
availableQuotePageDiscounts: null,
}, },
data() { data() {
return { return {
@ -86,18 +85,27 @@ export default {
selectedPackageName(newValue) { selectedPackageName(newValue) {
const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue); const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue);
this.$emit("vapsItemsSelected", VapsProductsInSelectedPackage); this.$emit("vapsItemsSelected", VapsProductsInSelectedPackage);
const discountPartInSelectedPackage = this.getDiscountPartForSelectedPackage(newValue); const servicePackageDiscountPartInSelectedPackage =
this.getServicePackageDiscountPartForSelectedPackage(newValue);
let supportingItems = this.supportingLineItems; let supportingItems = this.supportingLineItems;
if (
supportingItems = supportingItems.filter( containsLineItemWithPartType(
(item) => item.partType !== partTypeStrings.QUOTE_PAGE_DISCOUNT partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
); supportingItems
)
if (discountPartInSelectedPackage) { ) {
supportingItems.push(discountPartInSelectedPackage); supportingItems = supportingItems.filter(
(item) => item.partType !== partTypeStrings.SERVICE_PACKAGE_DISCOUNT
);
}
if (
servicePackageDiscountPartInSelectedPackage?.length > 0 &&
supportingItems != null
) {
supportingItems.push(servicePackageDiscountPartInSelectedPackage[0]);
} }
this.$emit("quotePageDiscountSelected", supportingItems); this.$emit("servicePackageDiscountSelected", supportingItems);
}, },
servicePackage(newValue) { servicePackage(newValue) {
if (newValue !== null) { if (newValue !== null) {
@ -110,7 +118,7 @@ export default {
return this.availableLineItems ?? []; return this.availableLineItems ?? [];
}, },
supportingLineItems() { supportingLineItems() {
return this.$store.getters.lineItems?.supportingItems ?? []; return this.$store.getters.lineItems?.supportingItems;
}, },
servicePackageAnswers() { servicePackageAnswers() {
const cmsWidgetName = this.isInsuranceSelected const cmsWidgetName = this.isInsuranceSelected
@ -141,15 +149,18 @@ export default {
? this.getDiscountedPackagePriceString(answer.Name, false) ? this.getDiscountedPackagePriceString(answer.Name, false)
: this.getDiscountedPackagePriceString( : this.getDiscountedPackagePriceString(
answer.Name, answer.Name,
this.hasDiscountForPackage(answer.Name) this.isServicePackageDiscountOnOrder &&
this.discountPackageNames == answer.Name
), ),
buttonFooterCopy: this.getFooterTextFromCms(answer.SubWidgetName), buttonFooterCopy: this.getFooterTextFromCms(answer.SubWidgetName),
additionalButtonData: { additionalButtonData: {
strikeThroughPrice: this.getPackagePriceString(answer.Name), strikeThroughPrice: this.getPackagePriceString(answer.Name),
hasDiscount: this.hasDiscountForPackage(answer.Name), servicePackageDiscount:
this.isServicePackageDiscountOnOrder &&
this.discountPackageNames == answer.Name,
Text: this.isInsuranceSelected Text: this.isInsuranceSelected
? false ? false
: "Special: Save $" + this.getDiscountPrice(answer.Name), : "Special: Save $" + this.getServicePackageDiscountPrice(),
isInsuranceSelected: this.isInsuranceSelected, isInsuranceSelected: this.isInsuranceSelected,
}, },
})); }));
@ -157,8 +168,17 @@ export default {
this.$emit("currentNumberOfPackages", modifiedAnswers.length); this.$emit("currentNumberOfPackages", modifiedAnswers.length);
return modifiedAnswers; return modifiedAnswers;
}, },
isDiscountOnOrder() { isServicePackageDiscountOnOrder() {
return this.availableQuotePageDiscounts?.length > 0; return containsLineItemWithPartType(
partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
this.nullSafeAvailableLineItems
);
},
discountPackageNames() {
const discountServicePackage = experimentMixin.methods.getSettingValue(
experimentSettings.PROMO_ON_PACKAGE
);
return getDiscountedPackageName(discountServicePackage);
}, },
frontWipersApplicableForTierTwo() { frontWipersApplicableForTierTwo() {
return shouldFrontWipersBeAvailable( return shouldFrontWipersBeAvailable(
@ -206,6 +226,12 @@ export default {
isRepair() { isRepair() {
return this.$store.getters.order.damage.isRepair; return this.$store.getters.order.damage.isRepair;
}, },
servicePackageDiscountParts() {
return findLineItemsWithPartType(
partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
this.nullSafeAvailableLineItems
);
},
showRecalInServicePackages() { showRecalInServicePackages() {
return this.isRecalibrationOnOrder && !this.shouldHideRecalibration; return this.isRecalibrationOnOrder && !this.shouldHideRecalibration;
}, },
@ -254,16 +280,16 @@ export default {
const formattedPriceFloat = parseFloat( const formattedPriceFloat = parseFloat(
this.getPackagePrice(packageName, { this.getPackagePrice(packageName, {
discountedPrice: false, discountedPrice: false,
quotePageDiscount: false, servicePackageDiscount: false,
}) })
).toFixed(2); ).toFixed(2);
return "$" + formattedPriceFloat; return "$" + formattedPriceFloat;
}, },
getDiscountedPackagePriceString(packageName, quotePageDiscount) { getDiscountedPackagePriceString(packageName, servicePackageDiscount) {
const formattedPriceFloat = parseFloat( const formattedPriceFloat = parseFloat(
this.getPackagePrice(packageName, { this.getPackagePrice(packageName, {
discountedPrice: true, discountedPrice: true,
quotePageDiscount, servicePackageDiscount,
}) })
).toFixed(2); ).toFixed(2);
@ -272,7 +298,7 @@ export default {
} }
return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat; return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat;
}, },
getPackagePrice(packageName, { discountedPrice = false, quotePageDiscount = false }) { getPackagePrice(packageName, { discountedPrice = false, servicePackageDiscount = false }) {
let lineItemsToPrice = [...this.nullSafeAvailableLineItems]; let lineItemsToPrice = [...this.nullSafeAvailableLineItems];
if (this.isRecalibrationOnOrder && this.shouldHideRecalibration) { if (this.isRecalibrationOnOrder && this.shouldHideRecalibration) {
@ -280,20 +306,17 @@ export default {
} }
//remove service package discount part //remove service package discount part
if (this.isDiscountOnOrder) { if (this.isServicePackageDiscountOnOrder) {
lineItemsToPrice = lineItemsToPrice.filter((item) => { lineItemsToPrice = lineItemsToPrice.filter((item) => {
return item.partType != partTypeStrings.QUOTE_PAGE_DISCOUNT; return item.partType != this.servicePackageDiscountParts[0].partType;
}); });
} }
if (discountedPrice) { if (discountedPrice) {
lineItemsToPrice.push(...removeVapsPromosFromPromoArray(this.activePromos)); lineItemsToPrice.push(...removeVapsPromosFromPromoArray(this.activePromos));
} }
if (quotePageDiscount) { if (servicePackageDiscount) {
const part = this.getDiscountPartForSelectedPackage(packageName); lineItemsToPrice.push(...this.servicePackageDiscountParts);
if (part) {
lineItemsToPrice.push(part);
}
} }
let priceFloat = this.isInsuranceSelected let priceFloat = this.isInsuranceSelected
? 0 ? 0
@ -305,16 +328,14 @@ export default {
return priceFloat; return priceFloat;
}, },
getDiscountPrice(packageName) { getServicePackageDiscountPrice() {
const part = this.getDiscountPartForSelectedPackage(packageName); if (this.isServicePackageDiscountOnOrder) {
let price = 0;
if (part) { price += baseMixin.methods.getTotalLineItemPrice(
const price = baseMixin.methods.getTotalLineItemPrice(part); this.servicePackageDiscountParts[0]
);
return Math.abs(price); return Math.abs(price);
} }
return null;
}, },
getVapsPrice(packageName, applyPromoDiscounts = false) { getVapsPrice(packageName, applyPromoDiscounts = false) {
const vapsItems = this.getVapsLineItemsForSelectedPackage(packageName); const vapsItems = this.getVapsLineItemsForSelectedPackage(packageName);
@ -377,18 +398,13 @@ export default {
return vapsLineItemsForSelectedPackage; return vapsLineItemsForSelectedPackage;
}, },
getDiscountPartForSelectedPackage(packageName) { getServicePackageDiscountPartForSelectedPackage(packageName) {
if (this.availableQuotePageDiscounts?.length > 0) { const selectedPackage = this.servicePackageAnswers.filter(
const match = this.availableQuotePageDiscounts.find( (item) => item.value === packageName
(discountInfo) => discountInfo.packageLevel === packageName );
); if (selectedPackage?.[0]?.additionalButtonData?.servicePackageDiscount) {
return match?.item; return this.servicePackageDiscountParts;
} } else return [];
return null;
},
hasDiscountForPackage(packageName) {
return !!this.getDiscountPartForSelectedPackage(packageName);
}, },
combineLineItemsWithoutDuplicates(lineItemsOne, lineItemsTwo) { combineLineItemsWithoutDuplicates(lineItemsOne, lineItemsTwo) {
const combinedLineItemArray = [...lineItemsTwo]; const combinedLineItemArray = [...lineItemsTwo];

View file

@ -5,7 +5,7 @@
:class="[this.buttonLabelSubCopy ? 'has-subheader' : '']" :class="[this.buttonLabelSubCopy ? 'has-subheader' : '']"
for="testradio"> for="testradio">
<div class="package-specs"> <div class="package-specs">
<div v-if="this.additionalButtonData.hasDiscount" class="row"> <div v-if="this.additionalButtonData.servicePackageDiscount" class="row">
<div class="col md-6"> <div class="col md-6">
<p class="m-0"> <p class="m-0">
<span v-html="this.buttonLabel"></span> <span v-html="this.buttonLabel"></span>
@ -77,7 +77,10 @@
</div> </div>
<div <div
v-if="this.additionalButtonData.hasDiscount && this.additionalButtonData.Text" v-if="
this.additionalButtonData.servicePackageDiscount &&
this.additionalButtonData.Text
"
class="special-save-box"> class="special-save-box">
<span v-html="this.additionalButtonData.Text"></span> <span v-html="this.additionalButtonData.Text"></span>
</div> </div>

View file

@ -958,6 +958,8 @@ function getPageNameFromRouter() {
) { ) {
return router.currentRoute.value.name; return router.currentRoute.value.name;
} }
return window.location.href.replace(/\/$/, "").split("/").pop();
} }
function getValueToLog(value, valueToLogType) { function getValueToLog(value, valueToLogType) {

View file

@ -129,9 +129,9 @@ export default {
}); });
return lineItemsArray; return lineItemsArray;
}, },
filterOutQuotePageDiscountPart(lineItems) { filterOutServicePackageDiscountPart(lineItems) {
const filteredLineItems = lineItems?.filter((item) => { const filteredLineItems = lineItems?.filter((item) => {
return !item?.partType?.includes(partTypeStrings.QUOTE_PAGE_DISCOUNT); return !item?.partType?.includes(partTypeStrings.SERVICE_PACKAGE_DISCOUNT);
}); });
return filteredLineItems; return filteredLineItems;
}, },

View file

@ -6,10 +6,10 @@ import { updateOrCreateFunnelCookie } from "@/helpers/heritage-integration/cooki
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper"; import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
export async function consumeReferralQuerystrings() { export async function consumeReferralQuerystrings() {
var referralNumber = getQuerystringParameter(queryStrings.REFERRAL_NUMBER); let referralNumber = getQuerystringParameter(queryStrings.REFERRAL_NUMBER);
var parentAccount = getQuerystringParameter(queryStrings.PARENT_ACCOUNT); let parentAccount = getQuerystringParameter(queryStrings.PARENT_ACCOUNT);
var correlationId = getQuerystringParameter(queryStrings.CORRELATION_ID); let correlationId = getQuerystringParameter(queryStrings.CORRELATION_ID);
var referralDate = null; let referralDate = null;
// If no referral number in querystring, check if heritage funnel updated last. // If no referral number in querystring, check if heritage funnel updated last.
// This would indicate a customer that went to heritage but did not return through the // This would indicate a customer that went to heritage but did not return through the
@ -30,7 +30,6 @@ export async function consumeReferralQuerystrings() {
if (referralDate) { if (referralDate) {
store.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate); store.commit(storeMutations.UPDATE_REFERRAL_DATE, referralDate);
} }
// log(" --update cookie");
updateOrCreateFunnelCookie(); updateOrCreateFunnelCookie();
} }
} }

View file

@ -6,6 +6,7 @@ import router from "@/router";
import { routeData, FUNNEL_START_PAGE } from "@/router/constants/routes"; import { routeData, FUNNEL_START_PAGE } from "@/router/constants/routes";
import store from "@/store"; import store from "@/store";
import { handleHardError } from "@/router/methods/error"; import { handleHardError } from "@/router/methods/error";
import analyticsMixin from "@/mixins/analytics-mixin";
export async function errorBeforeEnter(to, from) { export async function errorBeforeEnter(to, from) {
// Check if `hasAlreadyTriggeredErrror` is available. // Check if `hasAlreadyTriggeredErrror` is available.
@ -18,6 +19,7 @@ export async function errorBeforeEnter(to, from) {
nextPage: to?.name, nextPage: to?.name,
}; };
analyticsMixin.methods.logDigitalConsumer();
await handleHardError(errorPayload); await handleHardError(errorPayload);
return; return;
} }
@ -31,6 +33,7 @@ export async function errorBeforeEnter(to, from) {
nextPage: to?.name, nextPage: to?.name,
}; };
analyticsMixin.methods.logDigitalConsumer();
await handleHardError(errorPayload); await handleHardError(errorPayload);
return; return;
} else { } else {