970 lines
39 KiB
Vue
970 lines
39 KiB
Vue
<template>
|
|
<Form>
|
|
<loadingModal notFullScreen ref="loadingModal" />
|
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
|
<div class="container">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div>
|
|
<alert
|
|
ref="piaCCErrorAlert"
|
|
class="my-4"
|
|
v-if="shouldDisplayPiaCCAlert"
|
|
cmsWidgetName="PIACCErrorAlertWidget"
|
|
alertClass="alert-danger"
|
|
@textLinkClicked="paymentFailedPayLater"
|
|
v-bind:isDismissible="false" />
|
|
</div>
|
|
|
|
<div>
|
|
<alert
|
|
ref="piaAPErrorAlert"
|
|
class="my-4"
|
|
v-if="shouldDisplayPiaAPAlert"
|
|
cmsWidgetName="PIAAPErrorAlertWidget"
|
|
alertClass="alert-danger"
|
|
@textLinkClicked="paymentFailedPayLater"
|
|
v-bind:isDismissible="false" />
|
|
</div>
|
|
|
|
<div id="card-container">
|
|
<iframe
|
|
v-resize
|
|
ref="paymentFrame"
|
|
class="hop-iframe payment-iframe"
|
|
name="card-frame"
|
|
id="card-frame"
|
|
seamless
|
|
scrolling="no"
|
|
allow="payment *; microphone *; geolocation *;"></iframe>
|
|
|
|
<div id="cart-container">
|
|
<cart
|
|
ref="cart"
|
|
:damage="damageInfo"
|
|
:availableVaps="availableVaps"
|
|
:allowItemRemoval="false"
|
|
v-model="lineItems"
|
|
servicePackageOptionsCmsName="ServicePackageTitle"
|
|
recyclingModalCmsWidgetName="RecycleModal"
|
|
:isInsurance="isInsurance"
|
|
:insuranceDeductible="currentDeductible"
|
|
:insuranceCompanyName="insuranceCompanyName"
|
|
:showInsuranceCoverageAs="showInsuranceCoverageAs"
|
|
:isItac="isItac"
|
|
:isNoComp="isNoComp"
|
|
:isCollapsible="false" />
|
|
|
|
<button
|
|
v-if="showSwitchPaymentMethod"
|
|
id="submit-payment"
|
|
class="btn btn-primary rounded-pill py-3 px-6 delay w-100"
|
|
type="button"
|
|
@click="submitPayment">
|
|
Submit payment
|
|
</button>
|
|
|
|
<div class="payment-method-question">
|
|
<buttonQuestion
|
|
v-if="showSwitchPaymentMethod"
|
|
groupName="payment-method"
|
|
buttonTypeString="payment-method-list-button"
|
|
:buttonTypeObject="paymentMethodListButton"
|
|
isWide
|
|
:questionText="paymentMethodQuestionText"
|
|
:answers="paymentMethodAnswerData"
|
|
isRequired
|
|
:validationRules="validationRules"
|
|
:showApplePay="false"
|
|
:isInsurance="isInsurance"
|
|
v-model="switchedPaymentMethod" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<navbar
|
|
cmsWidgetName="FunnelFooterWidget"
|
|
isForwardActionDisabled="true"
|
|
:isBackButtonHidden="shouldHideBackButton"
|
|
isSubmitHidden="true"
|
|
@back-clicked="backButtonAction" />
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="shouldBlockInteraction" class="ui-block" @click="supressClick"></div>
|
|
</div>
|
|
</Form>
|
|
|
|
<form
|
|
ref="hopForm"
|
|
id="card-data"
|
|
:target="isPaypal ? '_top' : 'card-frame'"
|
|
method="POST"
|
|
:action="checkoutUrl">
|
|
<input type="hidden" name="paymentType" :value="paymentType" />
|
|
<input type="hidden" name="sgSessionId" :value="authToken" />
|
|
<input type="hidden" name="sgAuthToken" :value="authToken" />
|
|
<input type="hidden" name="sgSignaturePublic" :value="authSignature" />
|
|
<input type="hidden" name="sgSignatureStartDate" :value="authSignatureStart" />
|
|
<input type="hidden" name="referralSeqNum" :value="referralSequenceNumber" />
|
|
|
|
<input type="hidden" name="sge_commerce_indicator_isinternet" value="true" />
|
|
<input type="hidden" name="sghopsource" value="Safelite.com" />
|
|
<input type="hidden" name="sgHtmlStyle" value="ResourceSafeliteHtml" />
|
|
<input type="hidden" name="sgErrorMessagesEmbedded" value="true" />
|
|
|
|
<input type="hidden" name="sgNoKeystrokeProcessing" value="false" />
|
|
|
|
<input type="hidden" name="maskCharacter" value="*" />
|
|
<input type="hidden" name="styleSheetCode" :value="dynamicCSSUrl" />
|
|
<input type="hidden" name="styleSheetCode2" :value="dynamicHopCSSUrl" />
|
|
|
|
<input type="hidden" name="sgReceiptResponseURL" :value="piaResponseUrl" />
|
|
<input type="hidden" name="sgDeclineResponseURL" :value="piaResponseUrl" />
|
|
<input type="hidden" name="sgErrorResponseURL" :value="piaResponseUrl" />
|
|
|
|
<input type="hidden" name="sgheaderline1" :value="getHeaderLine1" />
|
|
<input type="hidden" name="sgHeader1subtitle" value="" />
|
|
<input type="hidden" name="sgheaderline2" :value="getHeaderLine2" />
|
|
<input type="hidden" name="sgheaderline3" value="" />
|
|
<input type="hidden" name="sgheaderline4" value="" />
|
|
<input type="hidden" name="sgheaderline5" value="*Required information" />
|
|
|
|
<input type="hidden" name="billTo_firstName" :value="firstName" />
|
|
<input type="hidden" name="billTo_firstNameShow" value="true" />
|
|
<input type="hidden" name="sghopmiddleInitialShow" value="false" />
|
|
<input type="hidden" name="billTo_lastName" :value="lastName" />
|
|
<input type="hidden" name="billTo_lastNameShow" value="true" />
|
|
|
|
<input type="hidden" name="billTo_street1" value="" />
|
|
<input type="hidden" name="billTo_street2" value="" />
|
|
<input type="hidden" name="billTo_city" value="" />
|
|
<input type="hidden" name="billTo_state" value="" />
|
|
|
|
<input type="hidden" name="billTo_postalCode" value="" />
|
|
<input type="hidden" name="billTo_postalCodeShow" value="true" />
|
|
<input type="hidden" name="billTo_postalCodeEnable" value="true" />
|
|
<input type="hidden" name="sgLabelPostalCode" value="Billing ZIP" />
|
|
|
|
<input type="hidden" name="sgtotalamount" :value="displayAmount" />
|
|
<input type="hidden" name="totalAmountDecimal" :value="totalAmount" />
|
|
<input type="hidden" name="lineItems" :value="piaLineItems" />
|
|
|
|
<input type="hidden" name="sgdiscountstrikethruamount" value="" />
|
|
|
|
<input type="hidden" name="callerDisplayText" value="" />
|
|
|
|
<input
|
|
type="hidden"
|
|
name="sgtermsofusedisplaytext"
|
|
value="By selecting submit, I agree to Safelite's" />
|
|
<input
|
|
type="hidden"
|
|
name="sgtermsofuseurl"
|
|
value="http://www.safelite.com/terms-of-service/" />
|
|
<input type="hidden" name="sgtermsofuselinkdisplaytext" value="Terms of service" />
|
|
<input type="hidden" name="sgtermsofcancelrefunddisplaytext" value="and" />
|
|
<input
|
|
type="hidden"
|
|
name="sgtermsofcancelrefundlinkdisplaytext"
|
|
value="cancellation and refund policy" />
|
|
<input
|
|
type="hidden"
|
|
name="sgtermsofcancelrefundurl"
|
|
value="http://www.safelite.com/cancellation-refund-policy" />
|
|
|
|
<input
|
|
type="hidden"
|
|
name="sgErrorMessageCardVerification"
|
|
value="Credit card could not be processed" />
|
|
<input
|
|
type="hidden"
|
|
name="sgErrorMessageTimeOut"
|
|
value="For your security, this transaction has been timed out." />
|
|
|
|
<input type="hidden" name="sgLabelCardNumber" value="" />
|
|
<input type="hidden" name="sgLabelAddressLine1" :value="address1" />
|
|
<input type="hidden" name="sgLabelAddressLine2" :value="address2" />
|
|
<input type="hidden" name="sgLabelCity" :value="city" />
|
|
<input type="hidden" name="sgLabelState" :value="state" />
|
|
|
|
<input type="hidden" name="sgCtu" :value="ctu" />
|
|
<input type="hidden" name="sgWorkOrder" :value="workOrderNumber" />
|
|
<input type="hidden" name="sgEmailAddress" :value="emailAddress" />
|
|
<input type="hidden" name="paypalInvoiceNumber" :value="invoiceNumber" />
|
|
<input type="hidden" name="paypalSuccessUrl" :value="piaResponseUrl" />
|
|
<input type="hidden" name="paypalCancelUrl" :value="piaCancelUrl" />
|
|
|
|
<input type="hidden" name="sgCCDeclineURL" :value="piaErrorUrl" />
|
|
<input type="hidden" name="sgCCTimeoutURL" :value="piaCancelUrl" />
|
|
|
|
<input type="hidden" name="sgTransactionType" value="authorization" />
|
|
<input type="hidden" name="amount" :value="totalAmount" />
|
|
<input type="hidden" name="ctu" :value="ctu" />
|
|
<input type="hidden" name="orderNumber" :value="workOrderNumber" />
|
|
|
|
<input type="hidden" name="billTo_email" :value="emailAddress" />
|
|
<input type="hidden" name="useDecisionManager" value="True" />
|
|
<input type="hidden" name="correlationId" :value="referralCorrelationId" />
|
|
<input type="hidden" name="sgErrorMessageCard_CVN" value="Please enter a valid CVV" />
|
|
|
|
<input type="hidden" name="ship_to_address_line1" :value="address1" />
|
|
<input type="hidden" name="ship_to_address_line2" :value="address2" />
|
|
<input type="hidden" name="ship_to_address_city" :value="city" />
|
|
<input type="hidden" name="ship_to_address_state" :value="state" />
|
|
<input type="hidden" name="ship_to_address_country" value="US" />
|
|
<input type="hidden" name="ship_to_address_postal_code" :value="zipCode" />
|
|
<input type="hidden" name="ship_to_phone" :value="phoneNumber" />
|
|
|
|
<input type="hidden" name="calling_application" value="NextGen" />
|
|
<input type="hidden" name="parentdomainname" :value="parentNomainName" />
|
|
</form>
|
|
</template>
|
|
|
|
<script>
|
|
// Components
|
|
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
|
import navbar from "@/fmg-components/nav-bar/nav-bar";
|
|
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
|
import cart from "@/fmg-components/cart/cart";
|
|
import alert from "@/ux-components/alert/alert";
|
|
|
|
import { storeActions } from "@/constants/store-actions";
|
|
import store from "@/store";
|
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
|
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 { 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";
|
|
|
|
export default {
|
|
name: "payment",
|
|
data() {
|
|
return {
|
|
checkoutUrl: applicationConfig.SAFELITE_HOP,
|
|
piaResponseUrl: applicationConfig.PIA_RESPONSE_URL,
|
|
piaCancelUrl: applicationConfig.PIA_CANCEL_URL,
|
|
piaErrorUrl: applicationConfig.PIA_ERROR_URL,
|
|
paymentType: this.getPaymentType(),
|
|
authToken: "",
|
|
authSignature: "",
|
|
authSignatureStart: "",
|
|
referralSequenceNumber: store.getters.order.referralSequenceNumber,
|
|
emailAddress: store.getters.order.customer.emailAddress,
|
|
address1: this.getAddress1(),
|
|
address2: this.getAddress2(),
|
|
city: this.getCity(),
|
|
state: this.getState(),
|
|
zipCode: this.getZipCode(),
|
|
firstName: store.getters.order.customer.firstName,
|
|
lastName: store.getters.order.customer.lastName,
|
|
phoneNumber: store.getters.order.customer.phoneNumber,
|
|
ctu: store.getters.order.serviceLocation.zipCodeCtu,
|
|
referralCorrelationId: store.getters.order.referralCorrelationId,
|
|
workOrderNumber: this.getWOrkOrderNumber(),
|
|
invoiceNumber: this.getInvoiceNumber(),
|
|
totalAmount: this.getAmountDue(),
|
|
displayAmount: this.getDisplayAmountDue(),
|
|
piaLineItems: "",
|
|
lineItems: [],
|
|
availableVaps: [],
|
|
shouldBlockInteraction: false,
|
|
paymentMethodListButton: paymentMethodListButton,
|
|
showSwitchPaymentMethod: !this.isAfterpay(),
|
|
};
|
|
},
|
|
props: {
|
|
switchedpaymentTypeValue: String,
|
|
},
|
|
directives: {
|
|
resize: {
|
|
mounted: function (el) {
|
|
el.addEventListener("load", () => {
|
|
iframeResize({ checkOrigin: false }, el);
|
|
});
|
|
},
|
|
unmounted: function (el) {
|
|
el.iFrameResizer.removeListeners();
|
|
},
|
|
},
|
|
},
|
|
async beforeRouteEnter(to, from, next) {
|
|
// Call APIs
|
|
const cmsContentPromise = fetchCmsContentForPage(to.name);
|
|
|
|
const signaturePromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.GET_SIGNATURE,
|
|
null,
|
|
"payment"
|
|
);
|
|
|
|
const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.GET_WIPERS,
|
|
{
|
|
serviceZipCode: store.getters.order.serviceLocation.zipCode,
|
|
carId: store.getters.vehicle.carId,
|
|
},
|
|
"payment"
|
|
);
|
|
|
|
const rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.GET_RAIN_DEFENSE,
|
|
null,
|
|
"payment"
|
|
);
|
|
|
|
const promiseResultMap = [
|
|
{
|
|
resultKey: "cmsContent",
|
|
promise: cmsContentPromise,
|
|
},
|
|
{
|
|
resultKey: "signature",
|
|
promise: signaturePromise,
|
|
},
|
|
{
|
|
resultKey: "wipers",
|
|
promise: wipersPromise,
|
|
},
|
|
{
|
|
resultKey: "rainDefense",
|
|
promise: rainDefensePromise,
|
|
},
|
|
];
|
|
|
|
const resultMap = await settleAllPromises(promiseResultMap);
|
|
const lineItemsFromStore = deepClone(store.getters.order.lineItems);
|
|
const glassParts = lineItemsFromStore.glassParts ?? [];
|
|
const supportingItems = lineItemsFromStore.supportingItems ?? [];
|
|
|
|
const lineItemsToTax = [
|
|
resultMap.rainDefense,
|
|
...supportingItems,
|
|
...resultMap.wipers,
|
|
...glassParts,
|
|
];
|
|
const availableVaps = [resultMap.rainDefense, ...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.$nextTick(() => {
|
|
if (vm.$refs.cart) {
|
|
const cartItems = vm.$refs.cart.cartItems;
|
|
vm.getPiaLineItems(cartItems);
|
|
}
|
|
|
|
vm.fetchSignatureInfo(resultMap.signature);
|
|
vm.setIFrameListener();
|
|
});
|
|
});
|
|
},
|
|
computed: {
|
|
switchedPaymentMethod: {
|
|
get: function () {
|
|
return this.switchedpaymentTypeValue;
|
|
},
|
|
set: function (switchedPaymentMethod) {
|
|
this.$emit("update:switchedpaymentTypeValue", switchedPaymentMethod);
|
|
if (switchedPaymentMethod === paymentMethods.AFTERPAY) {
|
|
this.switchToAfterpay();
|
|
}
|
|
},
|
|
},
|
|
parentNomainName() {
|
|
return window.location.hostname;
|
|
},
|
|
dynamicCSSUrl() {
|
|
const { protocol, hostname, port } = window.location;
|
|
return `${protocol}//${hostname}:${port}/fmg/css/site-2020Styling.css`;
|
|
},
|
|
dynamicHopCSSUrl() {
|
|
const { protocol, hostname, port } = window.location;
|
|
return `${protocol}//${hostname}:${port}/fmg/css/hop-styling.css`;
|
|
},
|
|
getHeaderLine1() {
|
|
if (!this.isPaypal) {
|
|
return this.getCmsContent("PIAHeaderLine1", "Text");
|
|
}
|
|
return "";
|
|
},
|
|
getHeaderLine2() {
|
|
if (!this.isPaypal) {
|
|
return this.getCmsContent("PIAHeaderLine2", "Text");
|
|
}
|
|
return "";
|
|
},
|
|
damageInfo() {
|
|
return this.$store.getters.damage;
|
|
},
|
|
isInsurance() {
|
|
return this.$store.getters.payment.isInsurance;
|
|
},
|
|
isNoComp() {
|
|
return this.$store.getters.policy.isNoComp;
|
|
},
|
|
isItac() {
|
|
return this.$store.getters.policy.isItac;
|
|
},
|
|
hasVapsInCart() {
|
|
if (this.lineItems?.vaps?.length > 0) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
showInsuranceCoverageAs() {
|
|
if (!this.isInsurance) return null;
|
|
if (this.isNoComp || this.isItac) {
|
|
return coverageStatus.NOCOMP;
|
|
} else {
|
|
return this.$store.getters.payment.insuranceCoverage.coverageStatus;
|
|
}
|
|
},
|
|
currentDeductible() {
|
|
return this.$store.getters.policy.currentDeductible;
|
|
},
|
|
insuranceCompanyName() {
|
|
return this.$store.getters.policy.insuranceCompanyName;
|
|
},
|
|
isPaypal() {
|
|
if (this.paymentType == "pp") {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
shouldDisplayPiaCCAlert() {
|
|
return this.shouldDisplayPiaAlert(paymentMethods.CREDIT_CARD);
|
|
},
|
|
shouldDisplayPiaAPAlert() {
|
|
return this.shouldDisplayPiaAlert(paymentMethods.AFTERPAY);
|
|
},
|
|
paymentMethodQuestionText() {
|
|
return this.getCmsContent("SwitchPaymentMethodWidget", "QuestionText");
|
|
},
|
|
paymentMethodAnswerData() {
|
|
var cmsData = this.getAnswersNullSafe("SwitchPaymentMethodWidget");
|
|
|
|
var tempItems = cmsData.map((answer) => {
|
|
return {
|
|
buttonLabel: answer.Text,
|
|
altText: answer.Text,
|
|
groupName: "payment-method",
|
|
value: answer.Name,
|
|
buttonImage: answer.AnswerImageUrl,
|
|
};
|
|
});
|
|
|
|
return tempItems;
|
|
},
|
|
},
|
|
methods: {
|
|
arePagePrerequisitesValid() {
|
|
// Service Location
|
|
const serviceLocation = store.getters.order.serviceLocation;
|
|
const mobileReqs = !!(
|
|
serviceLocation.address &&
|
|
serviceLocation.city &&
|
|
serviceLocation.state &&
|
|
serviceLocation.zipCode
|
|
);
|
|
|
|
const providerLocation = serviceLocation.provider.address;
|
|
const dropOffInshopReqs = !!(
|
|
providerLocation.streetAddress &&
|
|
providerLocation.city &&
|
|
providerLocation.state &&
|
|
providerLocation.zipCode
|
|
);
|
|
|
|
const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE;
|
|
|
|
const serviceLocationReqs =
|
|
(isMobile && mobileReqs) || (!isMobile && dropOffInshopReqs);
|
|
|
|
// Insurance
|
|
const isInsuranceSet = store.getters.order.payment.isInsurance !== null;
|
|
|
|
// Schedule
|
|
const schedule = store.getters.order.schedule;
|
|
const scheduleReqs = !!(
|
|
schedule.date &&
|
|
schedule.startTime &&
|
|
schedule.endTime &&
|
|
schedule.jobMaxMinutes &&
|
|
schedule.jobMinMinutes
|
|
);
|
|
|
|
// Customer
|
|
const customer = store.getters.order.customer;
|
|
const customerReqs = !!(
|
|
customer.firstName &&
|
|
customer.lastName &&
|
|
customer.phoneNumber &&
|
|
customer.emailAddress
|
|
);
|
|
|
|
const paymentMethodReqs =
|
|
store.getters.order.payment.isPia !== null &&
|
|
(store.getters.order.payment.isPia || !!store.getters.order.payment.piaType);
|
|
|
|
const preReqResult =
|
|
serviceLocationReqs &&
|
|
isInsuranceSet &&
|
|
scheduleReqs &&
|
|
customerReqs &&
|
|
paymentMethodReqs;
|
|
|
|
// prettier-ignore
|
|
{
|
|
debugLog("--- payment.vue pagePrereqs start ---", null, !preReqResult);
|
|
debugLog("mobileReqs:", mobileReqs, !preReqResult);
|
|
debugLog("serviceLocation.address:", serviceLocation.address, !preReqResult);
|
|
debugLog("serviceLocation.city:", serviceLocation.city, !preReqResult);
|
|
debugLog("serviceLocation.state:", serviceLocation.state, !preReqResult);
|
|
debugLog("serviceLocation.zipCode:", serviceLocation.zipCode, !preReqResult);
|
|
|
|
debugLog("", null, !preReqResult);
|
|
|
|
debugLog("dropOffInshopReqs:", dropOffInshopReqs, !preReqResult);
|
|
debugLog("serviceLocationReqs:", serviceLocationReqs, !preReqResult);
|
|
debugLog("providerLocation.streetAddress:", providerLocation.streetAddress, !preReqResult);
|
|
debugLog("providerLocation.city:", providerLocation.city, !preReqResult);
|
|
debugLog("providerLocation.state:", providerLocation.state, !preReqResult);
|
|
debugLog("providerLocation.zipCode:", providerLocation.zipCode, !preReqResult);
|
|
|
|
debugLog("", null, !preReqResult);
|
|
|
|
debugLog("isInsuranceSet:", isInsuranceSet, !preReqResult);
|
|
|
|
debugLog("", null, !preReqResult);
|
|
|
|
debugLog("scheduleReqs:", scheduleReqs, !preReqResult);
|
|
debugLog("schedule.date:", schedule.date, !preReqResult);
|
|
debugLog("schedule.startTime:", schedule.startTime, !preReqResult);
|
|
debugLog("schedule.endTime:", schedule.endTime, !preReqResult);
|
|
debugLog("schedule.jobMaxMinutes:", schedule.jobMaxMinutes, !preReqResult);
|
|
debugLog("schedule.jobMinMinutes:", schedule.jobMinMinutes, !preReqResult);
|
|
|
|
debugLog("", null, !preReqResult);
|
|
|
|
debugLog("customerReqs:", customerReqs, !preReqResult);
|
|
debugLog("customer.firstName:", customer.firstName, !preReqResult);
|
|
debugLog("customer.lastName:", customer.lastName, !preReqResult);
|
|
debugLog("customer.phoneNumber:", customer.phoneNumber, !preReqResult);
|
|
debugLog("customer.emailAddress:", customer.emailAddress, !preReqResult);
|
|
|
|
debugLog("", null, !preReqResult);
|
|
|
|
debugLog("paymentMethodReqs:", paymentMethodReqs, !preReqResult);
|
|
debugLog("store.getters.order.payment.isPia:", store.getters.order?.payment?.isPia, !preReqResult);
|
|
debugLog("store.getters.order.payment.piaType:", store.getters.order?.payment?.piaType, !preReqResult);
|
|
|
|
debugLog("--- payment.vue pagePrereqs end ---", null, !preReqResult);
|
|
}
|
|
|
|
return preReqResult;
|
|
},
|
|
getAnswersNullSafe(widgetName) {
|
|
const rawData = this.getCmsContent(widgetName, "Answers");
|
|
|
|
if (!rawData) {
|
|
return [];
|
|
} else {
|
|
return rawData;
|
|
}
|
|
},
|
|
getWOrkOrderNumber() {
|
|
if (store.getters.order.workOrderNumber) {
|
|
const items = store.getters.order.workOrderNumber.split("-");
|
|
return items[1];
|
|
}
|
|
|
|
this.backButtonAction();
|
|
},
|
|
getInvoiceNumber() {
|
|
if (store.getters.order.workOrderNumber) {
|
|
return store.getters.order.workOrderNumber.replace("-", "");
|
|
}
|
|
|
|
this.backButtonAction();
|
|
},
|
|
getAddress1() {
|
|
return store.getters.order.serviceLocation.address
|
|
? store.getters.order.serviceLocation.address
|
|
: store.getters.order.serviceLocation.provider.address.streetAddress;
|
|
},
|
|
getAddress2() {
|
|
return store.getters.order.serviceLocation.address2
|
|
? store.getters.order.serviceLocation.address2
|
|
: null;
|
|
},
|
|
getCity() {
|
|
return store.getters.order.serviceLocation.city
|
|
? store.getters.order.serviceLocation.city
|
|
: store.getters.order.serviceLocation.provider.address.city;
|
|
},
|
|
getState() {
|
|
return store.getters.order.serviceLocation.state
|
|
? store.getters.order.serviceLocation.state
|
|
: store.getters.order.serviceLocation.provider.address.state;
|
|
},
|
|
getZipCode() {
|
|
return store.getters.order.serviceLocation.zipCode
|
|
? store.getters.order.serviceLocation.zipCode
|
|
: store.getters.order.serviceLocation.provider.address.zipCode;
|
|
},
|
|
getPaymentType() {
|
|
switch (store.getters.order.payment.piaType) {
|
|
case paymentMethods.AFTERPAY:
|
|
return "ap";
|
|
case paymentMethods.CREDIT_CARD:
|
|
return "cc";
|
|
case paymentMethods.PAYPAL:
|
|
return "pp";
|
|
default:
|
|
return store.getters.payment.piaType;
|
|
}
|
|
},
|
|
getPiaLineItems(cartItems) {
|
|
const glassParts = store.getters.order.lineItems.glassParts;
|
|
let lineItems = [];
|
|
|
|
if (glassParts === null) {
|
|
lineItems = ["Labor|0|1", "Repair supplies|0|1"];
|
|
} else {
|
|
lineItems = ["Parts and labor|0|1"];
|
|
}
|
|
|
|
cartItems.forEach((item) => {
|
|
if (item.name !== null && item.category != "promos") {
|
|
const total = (item.salesTax + item.subTotal).toFixed(2);
|
|
if (total > 0) {
|
|
lineItems.push(
|
|
`${item.name}|${(item.salesTax + item.subTotal).toFixed(2)}|1`
|
|
);
|
|
}
|
|
}
|
|
});
|
|
|
|
this.piaLineItems = lineItems.join("||");
|
|
},
|
|
getAmountDue() {
|
|
return getAmountDue(store.getters.order.lineItems);
|
|
},
|
|
getDisplayAmountDue() {
|
|
return getDisplayAmountDue(store.getters.order.lineItems);
|
|
},
|
|
async paymentFailedPayLater() {
|
|
this.$refs.loadingModal.isModalVisible = true;
|
|
|
|
await this.dispatchStoreAction(
|
|
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
|
paymentMethods.LATER,
|
|
false
|
|
);
|
|
|
|
await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
|
try {
|
|
await submitWorkOrder({
|
|
pageNameToLog: "payment",
|
|
submitAfterSave: true,
|
|
});
|
|
|
|
await baseMixin.methods.dispatchStoreAction(storeActions.CREATE_SUBMITTED_STATE);
|
|
this.$router.navigateAndForceTopLevelNavigation(
|
|
this.navigationScenarios.CLICKED_PAY_LATER,
|
|
this.pageName
|
|
);
|
|
//window.location = applicationConfig.CONFIRMATION_URL;
|
|
} catch (error) {
|
|
console.log("error: response from submit work order(payment pg):" + error.message);
|
|
this.$router.navigateWithoutSaving(
|
|
this.navigationScenarios.PIA_ERROR,
|
|
this.pageName
|
|
);
|
|
this.$refs.loadingModal.isModalVisible = false;
|
|
return;
|
|
}
|
|
},
|
|
backButtonAction() {
|
|
// Used to set the url directly here.
|
|
// Now hooks into a shared set of logic for doing this, also used with `payment-pia-return`.
|
|
// And uses nav scenarios properly.
|
|
this.$router.navigateAndForceTopLevelNavigation(
|
|
this.navigationScenarios.CLICKED_BACK,
|
|
this.pageName
|
|
);
|
|
},
|
|
submitHopForm() {
|
|
this.$nextTick(() => {
|
|
this.$refs.hopForm.submit();
|
|
|
|
const iframe = this.$refs.paymentFrame;
|
|
if (iframe) {
|
|
iframe.onload = () => {
|
|
if (iframe.contentWindow) {
|
|
if (baseMixin.methods.showApplePay()) {
|
|
iframe.contentWindow.postMessage("hybrid-with-applepay", "*");
|
|
console.log(new Date() + ": Sent applepay: new hop with applepay");
|
|
} else {
|
|
iframe.contentWindow.postMessage("hybrid", "*");
|
|
console.log(new Date() + ": Sent hybrid: new hop no applepay");
|
|
}
|
|
|
|
if (this.paymentType == "cc" || this.paymentType == "PayNow") {
|
|
iframe.contentWindow.postMessage("CreditCardChosen", "*");
|
|
console.log(new Date() + ": Sent creditcard");
|
|
} else if (this.paymentType == "ap") {
|
|
iframe.contentWindow.postMessage("afterpay", "*");
|
|
console.log(new Date() + ": Sent afterpay");
|
|
}
|
|
}
|
|
};
|
|
}
|
|
});
|
|
},
|
|
async fetchSignatureInfo(signatureInfo) {
|
|
if (this.isPaypal) {
|
|
this.$refs.loadingModal.showModal();
|
|
}
|
|
|
|
this.authToken = signatureInfo.token;
|
|
this.authSignature = signatureInfo.signature;
|
|
this.authSignatureStart = signatureInfo.startDate;
|
|
|
|
this.submitHopForm();
|
|
},
|
|
handleIFrameContentWindowMessage(event) {
|
|
if (typeof event.data === "string") {
|
|
if (event.data.indexOf("afterpayClosed") > -1) {
|
|
this.backButtonAction();
|
|
}
|
|
|
|
if (event.data.indexOf("afterpayOpened") > -1) {
|
|
console.log(new Date() + ": Payment method afterpay selected");
|
|
this.updatePaymentMethod(paymentMethods.AFTERPAY);
|
|
this.showSwitchPaymentMethod = false;
|
|
}
|
|
|
|
if (event.data.indexOf("creditCardSubmit") > -1) {
|
|
console.log(new Date() + ": Payment method credit card selected");
|
|
this.updatePaymentMethod(paymentMethods.CREDIT_CARD);
|
|
this.setUIBlock(true);
|
|
}
|
|
|
|
if (event.data.indexOf("afterpayPaymentReceived") > -1) {
|
|
console.log(new Date() + ": Payment method afterpay selected");
|
|
this.updatePaymentMethod(paymentMethods.AFTERPAY);
|
|
}
|
|
|
|
if (event.data.indexOf("applepayOpened") > -1) {
|
|
console.log(new Date() + ": Payment method applepay selected");
|
|
this.updatePaymentMethod(paymentMethods.APPLE_PAY);
|
|
}
|
|
|
|
if (event.data.indexOf("showLoaderForPaypal") > -1) {
|
|
console.log(new Date() + ": Payment method paypal selected");
|
|
this.updatePaymentMethod(paymentMethods.PAYPAL);
|
|
}
|
|
}
|
|
},
|
|
updatePaymentMethod(paymentMethod) {
|
|
// if the payment method is not set yet, then set it based on what HOP sends us
|
|
if (
|
|
store.getters.order.payment.piaType == paymentMethods.PAY_NOW ||
|
|
store.getters.order.payment.piaType == paymentMethods.NONE
|
|
) {
|
|
console.log(new Date() + " UPDATE PaymentMethod from HOP:" + paymentMethod);
|
|
this.dispatchStoreAction(
|
|
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
|
paymentMethod,
|
|
false
|
|
);
|
|
}
|
|
},
|
|
switchToAfterpay() {
|
|
const iframe = this.$refs.paymentFrame;
|
|
if (iframe) {
|
|
iframe.contentWindow.postMessage("afterpay", "*");
|
|
window.scrollTo({ top: 0, left: 0, behavior: "smooth" });
|
|
}
|
|
},
|
|
setIFrameListener() {
|
|
window.addEventListener("message", (event) =>
|
|
this.handleIFrameContentWindowMessage(event)
|
|
);
|
|
},
|
|
setUIBlock(val) {
|
|
this.shouldBlockInteraction = val;
|
|
},
|
|
supressClick(event) {
|
|
if (this.shouldBlockInteraction) {
|
|
event.stopPropagation();
|
|
}
|
|
},
|
|
shouldDisplayPiaAlert(payMethod) {
|
|
return this.$route?.query?.piaErrorType === payMethod;
|
|
},
|
|
isAfterpay() {
|
|
if (this.paymentType == "ap") {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
submitPayment() {
|
|
const iframe = this.$refs.paymentFrame;
|
|
if (iframe) {
|
|
iframe.contentWindow.postMessage("submitPayment", "*");
|
|
}
|
|
},
|
|
},
|
|
components: {
|
|
funnelHeader,
|
|
navbar,
|
|
loadingModal,
|
|
cart,
|
|
alert,
|
|
buttonQuestion,
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.hop-iframe {
|
|
position: relative;
|
|
width: 100%;
|
|
min-height: 650px;
|
|
border: 0 none;
|
|
}
|
|
#pageLoadingModal {
|
|
background-color: red;
|
|
}
|
|
|
|
#card-container {
|
|
display: flex;
|
|
& > iframe {
|
|
flex-basis: 55%;
|
|
margin-right: 9%;
|
|
}
|
|
& > #cart-container {
|
|
flex-basis: 36%;
|
|
margin-top: 2rem;
|
|
}
|
|
|
|
@include media-breakpoint-down(lg) {
|
|
flex-direction: column;
|
|
& > iframe {
|
|
flex-basis: auto;
|
|
margin-right: 0;
|
|
}
|
|
& > #cart-container {
|
|
flex-basis: auto;
|
|
margin: 0 0.5rem;
|
|
|
|
& > button#submit-payment {
|
|
display: none;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.payment-method-question {
|
|
padding: 0;
|
|
|
|
& .list-button-content {
|
|
justify-content: center;
|
|
}
|
|
}
|
|
|
|
.ui-block {
|
|
position: fixed;
|
|
top: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 9999;
|
|
}
|
|
</style>
|