This commit is contained in:
Leah Schumann 2023-05-23 07:04:51 -04:00
parent bc6f7d5865
commit 0431cae39f
3 changed files with 300 additions and 46 deletions

View file

@ -1,4 +1,5 @@
import { storeActions } from "@/constants/store-actions";
import store from "@/store";
import baseMixin from "@/mixins/base-mixin.js";
export async function getPricedMobileFeePart(serviceZipCode) {
@ -43,48 +44,42 @@ export async function getServiceabilityDetails(serviceZipCode, lineItems) {
return Promise.resolve(serviceabilityDetails);
}
export async function getShopTimeSlots(providerNumber, startDate, endDate) {
export async function getAvailabilityRating(providerNumber, startDate, endDate, appointmentType) {
// For a given shop provider number and date range, get the appointment time slots available
/*
Request
{
"providerNumber": "string",
"startDate": "2023-05-19T18:32:02.026Z",
"endDate": "2023-05-19T18:32:02.026Z",
"shopAppointmentType": "string",
"applicationName": "string",
"parentAccountNumber": 0,
"carId": "string",
"partNumbers": [
"string"
],
"glassPieces": [
{
"name": "string",
"location": "string"
const shopTimeSlots = await baseMixin.methods.dispatchStoreAction(
storeActions.GET_SHOP_TIME_SLOTS,
{
providerNumber: providerNumber,
startDate: startDate,
endDate: endDate,
shopAppointmentType: appointmentType,
},
false
);
// Rate the availability for the shop
let numberOfAppointmentsPerDay = []
for (let i = 0; i < shopTimeSlots.days.length; i++) {
numberOfAppointmentsPerDay.push(shopTimeSlots.days[i].timeSlots.length);
}
const dateRange = 7;
const minimumNumberOfAppointmentsPerDay = 1;
const numberOfDaysToEvaluate = 2;
let daysWithMinimalAppointmentsCount = 0;
for (let i = 0; i < dateRange; i++) {
if (numberOfAppointmentsPerDay[i] >= minimumNumberOfAppointmentsPerDay) {
daysWithMinimalAppointmentsCount++;
if (daysWithMinimalAppointmentsCount >= numberOfDaysToEvaluate) {
break;
}
],
"eon": "string",
"paymentType": "string",
"coverage": {
"status": "string",
"deductible": 0,
"additionalAuthFlag": "string"
},
"partSelection": {
"hasAnsweredPartQuestions": true,
"hasAnsweredMoldingQuestions": true,
"hasAnsweredCapabilityQuestions": true,
"hasManuallySelectedParts": true
},
"vehicle": {
"year": 0,
"make": "string",
"model": "string",
"style": "string",
"vin": "string"
}
}
*/
const isGoodAvailability = daysWithMinimalAppointmentsCount >= numberOfDaysToEvaluate;
const shopStatus = isGoodAvailability ? "Good" : "Low"
return shopStatus;
}

View file

@ -1,10 +1,183 @@
import { getPricedMobileFeePart, getServiceabilityDetails } from "./service-location-helper";
import { getPricedMobileFeePart, getServiceabilityDetails, getAvailabilityRating } from "./service-location-helper";
import { storeActions } from "@/constants/store-actions";
jest.mock("@/store", () => ({
getters: {
order: {
vehicle: {
year: null,
make: null,
model: null,
style: null,
carId: null,
category: null,
vin: null,
imageUrl: null,
imageVifNumber: null,
imageColor: null,
registration: {
licensePlate: null,
address: null,
city: null,
state: null,
zipCode: null,
firstName: null,
lastName: null,
},
},
serviceLocation: {
address: null,
city: null,
state: null,
zipCode: null,
zipCodeCtu: null,
appointmentType: null,
provider: {
providerNumber: null,
address: {
streetAddress: null,
city: null,
state: null,
zip: null,
},
},
},
customer: {
emailAddress: null,
},
damage: {
isRepair: null,
numberOfChips: null,
glassToReplace: null,
partQuestionAnswers: null,
moldingQuestionAnswers: null,
capabilityQuestionAnswers: null,
},
lineItems: {
glassParts: null,
supportingItems: null,
vaps: null,
serverData: null,
},
payment: {
isInsurance: null,
insuranceCoverage: {
isVerified: null,
coverageStatus: null,
},
parentAccountNumber: 0,
},
schedule: {
date: null,
startTime: null,
endTime: null,
routeCode: null,
},
referralNumber: null,
referralDate: null,
referralCorrelationId: null,
eon: null,
},
},
}));
const mockStoreActionGetMobileFeePart = storeActions.GET_MOBILE_FEE_PART;
const mockStoreActionPriceOrderItemsAndSaveServerData =
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA;
const mockStoreActionGetServiceabilityDetails = storeActions.GET_SERVICEABILITY_DETAILS;
const mockStoreActionGetShopTimeSlots = storeActions.GET_SHOP_TIME_SLOTS;
const mockGetShopTimeSlotsGoodAvailability = {
estimatedServiceMinutesMinimum: 0,
estimatedServiceMinutesMaximimum: 0,
days: [
{
date: "string",
timeSlots: [
{
id: "string",
startTime: "",
endTime: "",
offerPremium: true
},
]
},
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: [
{
id: "string",
startTime: "",
endTime: "",
offerPremium: true
},
]
},
]
}
const mockGetShopTimeSlotsLowAvailability = {
estimatedServiceMinutesMinimum: 0,
estimatedServiceMinutesMaximimum: 0,
days: [
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: []
},
{
date: "string",
timeSlots: [
{
id: "string",
startTime: "",
endTime: "",
offerPremium: true
},
]
},
]
}
jest.mock("@/mixins/base-mixin.js", () => ({
methods: {
@ -18,7 +191,7 @@ jest.mock("@/mixins/base-mixin.js", () => ({
});
}),
dispatchStoreAction: jest.fn().mockImplementation((actionName) => {
dispatchStoreAction: jest.fn().mockImplementation((actionName, request) => {
if (actionName === mockStoreActionGetMobileFeePart) {
return Promise.resolve({
data: {
@ -50,6 +223,15 @@ jest.mock("@/mixins/base-mixin.js", () => ({
isRecalibrationServiceableMobile: true,
});
}
if (actionName === mockStoreActionGetShopTimeSlots) {
if (request.providerNumber == "0000001") {
return Promise.resolve(mockGetShopTimeSlotsGoodAvailability);
}
return Promise.resolve(mockGetShopTimeSlotsLowAvailability);
}
}),
},
}));
@ -124,4 +306,32 @@ describe("service-location-helper.js", () => {
expect(result).toEqual(expected);
});
});
describe("getAvailabilityRating", () => {
it("Should return a 'Good' rating", async () => {
// Arrange
const providerNumber = "0000001";
const expected = "Good";
// Act
const result = await getAvailabilityRating(providerNumber);
// Assert
expect(result).toEqual(expected);
});
it("Should return a 'Low' rating", async () => {
// Arrange
const providerNumber = "0000000";
const expected = "Low";
// Act
const result = await getAvailabilityRating(providerNumber);
// Assert
expect(result).toEqual(expected);
});
});
});

View file

@ -551,6 +551,7 @@ export const actions = {
payload: {},
});
},
lookupVehicleByYmms(context, { year, make, model, style }) {
return globalMethods.callHttpClient({
method: endpoints.LookupVehicleByYmms.method,
@ -558,6 +559,7 @@ export const actions = {
payload: {},
});
},
lookupVehicleByVin(context, { vin }) {
return globalMethods.callHttpClient({
method: endpoints.LookupVehicleByVin.method,
@ -567,6 +569,7 @@ export const actions = {
},
});
},
lookupVinByPlate(context, { licensePlate, licenseState }) {
return globalMethods.callHttpClient({
method: endpoints.LookupVinByPlate.method,
@ -577,6 +580,7 @@ export const actions = {
},
});
},
lookupVinByAddress(
context,
{ licenseLastName, licenseStreetAddress, licenseZip, licenseState }
@ -592,6 +596,7 @@ export const actions = {
},
});
},
lookupVinByImage(context, image) {
const data = new FormData();
data.append("vinImage", image);
@ -602,6 +607,7 @@ export const actions = {
isFormData: true,
});
},
isVinByAddressPermissible(context, zip) {
return globalMethods.callHttpClient({
method: endpoints.IsVinByAddressPermissible.method,
@ -609,6 +615,7 @@ export const actions = {
payload: {},
});
},
getVehicleMakes(context, { year }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleMakes.method,
@ -616,6 +623,7 @@ export const actions = {
payload: {},
});
},
getVehicleModels(context, { year, make }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleModels.method,
@ -623,6 +631,7 @@ export const actions = {
payload: {},
});
},
getVehicleStyles(context, { year, make, model }) {
return globalMethods.callHttpClient({
method: endpoints.GetVehicleStyles.method,
@ -630,6 +639,7 @@ export const actions = {
payload: {},
});
},
setVehicle(context, { year, make, model, style }) {
return globalMethods
.callHttpClient({
@ -652,6 +662,7 @@ export const actions = {
return response;
});
},
getDamageOptions(context, { carId }) {
return globalMethods.callHttpClient({
methods: endpoints.GetDamageOptions.method,
@ -659,6 +670,7 @@ export const actions = {
payload: {},
});
},
validateZip(context, { zip }) {
return globalMethods.callHttpClient({
methods: endpoints.ValidateZip.method,
@ -673,18 +685,22 @@ export const actions = {
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
context.commit(storeMutations.UPDATE_VAPS, null);
},
resetRegistrationAndDependencies(context) {
context.commit(storeMutations.RESET_REGISTRATION_STATE);
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
},
resetPartsAndDependencies(context) {
context.commit(storeMutations.RESET_GLASS_PARTS_STATE);
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, null);
},
resetState(context) {
context.commit(storeMutations.RESET_STATE);
},
resetSaveSessionPromise(context) {
context.commit(storeMutations.RESET_SAVE_SESSION_PROMISE);
},
@ -699,12 +715,14 @@ export const actions = {
},
});
},
getHomepageName(context) {
return globalMethods.callHttpClient({
method: endpoints.GetHomepageInfo.method,
endpoint: endpoints.GetHomepageInfo.url(applicationConfig.APPLICATION_ABBREVIATION),
});
},
getPageData(context, { pageName }) {
return globalMethods.callHttpClient({
method: endpoints.GetPageData.method,
@ -771,6 +789,7 @@ export const actions = {
context.commit(storeMutations.UPDATE_SAVED_SESSION_ID, savedSessionId);
context.commit(storeMutations.UPDATE_CRM_CUSTOMER_ID, crmCustomerId);
},
logPageView(
context,
{
@ -812,6 +831,7 @@ export const actions = {
}
);
},
logCustomEvent(
context,
{
@ -1116,15 +1136,19 @@ export const actions = {
});
},
getShopTimeSlots(
context,
{ startDate = "2023-01-01", endDate = "2023-05-01", shopAppointmentType = "" }
getShopTimeSlots(context,
{
providerNumber,
startDate = "2023-01-01",
endDate = "2023-05-01",
shopAppointmentType = ""
}
) {
const order = context.state.order;
const mockArray = [];
var payload = {
providerNumber: order.providerNumber,
providerNumber: providerNumber ?? order.providerNumber,
startDate: startDate,
endDate: endDate,
shopAppointmentType: shopAppointmentType,
@ -1150,6 +1174,7 @@ export const actions = {
// logApiCall: false,
// });
},
getMobileEarlyBirdFee(context) {
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
const paymentType = context.getters.order.payment.isInsurance ? "Insurance" : "Cash";
@ -1162,6 +1187,7 @@ export const actions = {
// endpoint: `${endpoints.GetMobileEarlyBirdFee.url}/${paymentType}/${damageType}`,
// });
},
// Session API Actions
saveSession(context) {
const vehicle = context.getters.vehicle;
@ -1262,6 +1288,7 @@ export const actions = {
},
});
},
loadSession(
context,
{
@ -1339,6 +1366,7 @@ export const actions = {
context.commit(storeMutations.UPDATE_YEAR, year);
}
},
saveVehicleMake(context, make) {
//Reset dependent state when changing
if (context.state.order.vehicle.make !== make) {
@ -1359,6 +1387,7 @@ export const actions = {
context.commit(storeMutations.UPDATE_MAKE, make);
}
},
saveVehicleModel(context, model) {
//Reset dependent state when changing
if (context.state.order.vehicle.model !== model) {
@ -1378,6 +1407,7 @@ export const actions = {
context.commit(storeMutations.UPDATE_MODEL, model);
}
},
saveVehicleStyle(context, style) {
//Reset dependent state when changing
if (context.state.order.vehicle.style !== style) {
@ -1396,6 +1426,7 @@ export const actions = {
context.commit(storeMutations.UPDATE_STYLE, style);
}
},
saveVehicleDamage(
context,
{ isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount }
@ -1453,6 +1484,7 @@ export const actions = {
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
}
},
saveRegistrationLicensePlateLookup(
context,
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
@ -1474,6 +1506,7 @@ export const actions = {
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
}
},
saveRegistrationAddressLookup(
context,
{ isSelectedGlassAvailableForVehicle, vehicleInfo, registrationInfo }
@ -1499,6 +1532,7 @@ export const actions = {
context.commit(storeMutations.UPDATE_REGISTRATION, registrationInfo);
}
},
savePartQuestionAnswers(context, partQuestionAnswersArray) {
// if part question answers have changed, reset subsequent question answers
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
@ -1537,6 +1571,7 @@ export const actions = {
//Save new values
context.commit(storeMutations.UPDATE_PART_QUESTION_ANSWERS, partQuestionAnswersArray);
},
resetMoldingAndCapabilityQuestionAnswersIfNeeded(context, matchedParts) {
const partsOrQuestionsDataToCompareWith =
context.getters.pageData(fmgPageValues.MOLDING_QUESTIONS)?.partsOrQuestions ??
@ -1576,6 +1611,7 @@ export const actions = {
});
}
},
saveMoldingQuestionAnswers(context, moldingQuestionAnswers) {
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
context.getters.damage.moldingQuestionAnswers,
@ -1604,6 +1640,7 @@ export const actions = {
//Save new values
context.commit(storeMutations.UPDATE_MOLDING_QUESTION_ANSWERS, moldingQuestionAnswers);
},
saveCapabilityQuestionAnswers(context, capabilityQuestionAnswers) {
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(
context.getters.damage.capabilityQuestionAnswers,
@ -1630,18 +1667,23 @@ export const actions = {
capabilityQuestionAnswers
);
},
savePaymentType(context, isInsurance) {
context.commit(storeMutations.UPDATE_IS_INSURANCE, isInsurance);
},
saveParentAccountNumber(context, parentAccountNumber) {
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber);
},
saveSupportingItems(context, supportingItems) {
context.commit(storeMutations.UPDATE_SUPPORTING_ITEMS, supportingItems);
},
saveVaps(context, vaps) {
context.commit(storeMutations.UPDATE_VAPS, vaps);
},
// Price order actions
async priceOrderItemsAndSaveServerData(
context,
@ -1694,16 +1736,20 @@ export const actions = {
return availableLineItems;
},
// Misc order actions
saveSchedule(context, scheduleInfo) {
context.commit(storeMutations.UPDATE_SCHEDULE, scheduleInfo);
},
saveServiceLocation(context, serviceLocationInfo) {
context.commit(storeMutations.UPDATE_SERVICE_LOCATION, serviceLocationInfo);
},
saveEmail(context, email) {
context.commit(storeMutations.UPDATE_CUSTOMER_EMAIL_ADDRESS, email);
},
saveVin(context, { isSelectedGlassAvailableForVehicle, vehicleInfo }) {
//Reset dependent state when changing
if (vehicleInfo.vin !== context.state.order.vehicle.vin) {
@ -1716,12 +1762,15 @@ export const actions = {
context.commit(storeMutations.UPDATE_VEHICLE, vehicleInfo);
}
},
saveGlassParts(context, parts) {
context.commit(storeMutations.UPDATE_GLASS_PARTS, parts);
},
clearVin(context) {
context.commit(storeMutations.UPDATE_VEHICLE_VIN, null);
},
isVinOptionalVehicle(context) {
switch (context.state.order.vehicle.make.toLowerCase()) {
case "mercedes benz":