392 lines
17 KiB
Vue
392 lines
17 KiB
Vue
<template>
|
|
<Form>
|
|
<loadingModal notFullScreen ref="loadingModal" />
|
|
<div class="container-fluid">
|
|
<div class="row justify-content-center">
|
|
<div class="col-md-6">
|
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row justify-content-center">
|
|
<div class="col-md-6 col-xl-4 p-0">
|
|
<div id="card-container">
|
|
<iframe
|
|
ref="paymentFrame"
|
|
class="hop-iframe payment-iframe"
|
|
name="card-frame"
|
|
id="card-frame"
|
|
seamless
|
|
scrolling="no">
|
|
</iframe>
|
|
</div>
|
|
<navbar
|
|
cmsWidgetName="FunnelFooterWidget"
|
|
isForwardActionDisabled="true"
|
|
:isBackButtonHidden="shouldHideBackButton"
|
|
isSubmitHidden="true"
|
|
@back-clicked="backButtonAction" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Form>
|
|
|
|
<form
|
|
ref="myForm"
|
|
id="card-data"
|
|
:target="paypalPayment ? '_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="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-use/" />
|
|
<input type="hidden" name="sgtermsofuselinkdisplaytext" value="terms of use" />
|
|
<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="piaCancelUrl" />
|
|
<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" />
|
|
</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 { storeActions } from "@/constants/store-actions";
|
|
import store from "@/store";
|
|
import { externalUrls } from "@/router/router-constants/externalUrl-values";
|
|
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 baseMixin from "@/mixins/base-mixin.js";
|
|
|
|
// Validation
|
|
|
|
export default {
|
|
name: "payment",
|
|
data() {
|
|
return {
|
|
checkoutUrl: externalUrls.SAFELITE_HOP,
|
|
piaResponseUrl: applicationConfig.PIA_RESPONSE_URL,
|
|
piaCancelUrl: applicationConfig.PIA_CANCEL_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: this.getPiaLineItems(),
|
|
paypalPayment: this.isPaypal(),
|
|
};
|
|
},
|
|
async beforeRouteEnter(to, from, next) {
|
|
// Call APIs
|
|
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
|
|
|
const signaturePromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.GET_SIGNATURE,
|
|
null,
|
|
"payment"
|
|
);
|
|
|
|
// TODO: Data fetching Promise declarations
|
|
|
|
const promiseResultMap = [
|
|
{
|
|
resultKey: "cmsContent",
|
|
promise: cmsContentPromise,
|
|
},
|
|
{
|
|
resultKey: "signature",
|
|
promise: signaturePromise,
|
|
},
|
|
];
|
|
|
|
const resultMap = await settleAllPromises(promiseResultMap);
|
|
|
|
// Call the "next" function to complete the transition to this page.
|
|
next(async (vm) => {
|
|
vm.setCmsContent(resultMap.cmsContent);
|
|
vm.fetchSignatureInfo(resultMap.signature);
|
|
});
|
|
},
|
|
computed: {
|
|
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 "";
|
|
},
|
|
},
|
|
methods: {
|
|
arePagePrerequisitesValid() {
|
|
// TODO
|
|
return true;
|
|
},
|
|
getWOrkOrderNumber() {
|
|
if (store.getters.order.workOrderNumber) {
|
|
const items = store.getters.order.workOrderNumber.split("-");
|
|
return items[1];
|
|
}
|
|
|
|
// no work order, set pia error and return
|
|
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, "NO WORK ORDER", false);
|
|
this.backButtonAction();
|
|
},
|
|
getInvoiceNumber() {
|
|
if (store.getters.order.workOrderNumber) {
|
|
return store.getters.order.workOrderNumber.replace("-", "");
|
|
}
|
|
|
|
// no work order, set pia error and return
|
|
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, "NO WORK ORDER", false);
|
|
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() {
|
|
let itemsForPia = "";
|
|
const glassParts = store.getters.order.lineItems.glassParts;
|
|
const supportingItems = store.getters.order.lineItems.supportingItems;
|
|
const vaps = store.getters.order.lineItems.vaps;
|
|
const items = [...(glassParts ?? []), ...(supportingItems ?? []), ...(vaps ?? [])];
|
|
|
|
for (let i = 0; i < items.length; i++) {
|
|
const amount = items[i].laborAmount + items[i].sellingPrice;
|
|
itemsForPia += items[i].partType + "|" + amount + "|1|";
|
|
}
|
|
return itemsForPia;
|
|
},
|
|
getAmountDue() {
|
|
return 1600;
|
|
//return baseMixin.methods.getAmountDue(store.getters.order.lineItems);
|
|
},
|
|
getDisplayAmountDue() {
|
|
return "$1600.00";
|
|
//return baseMixin.methods.getDisplayAmountDue(store.getters.order.lineItems);
|
|
},
|
|
isPaypal() {
|
|
if (this.getPaymentType() == "pp") {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
backButtonAction() {
|
|
// The only way I could figure out how to get navigation to work on a page with the iframe.
|
|
// This is also how a cancel from Paypal would work. Just a redirect to the payment-method page.
|
|
// The normal navigation sort of works but the page does not render. The "next" callback function does not get
|
|
// invoked in payment-method's beforeroute enter. I also spotted an error in vue-router.esm-bundler.js when this
|
|
// happens but was unable to ignore it with a try catch. The navigation guard error is:
|
|
// Error: Redirected from "/?fmgPage=payment-method" to "{ params: {isSavingNation: "false"}, query: "fmgPage: "payment-method"}"
|
|
// I don't know if the navigation guard thinks the to and from are the same page.
|
|
// Also tried overriding with a $router.push
|
|
window.location = applicationConfig.PIA_CANCEL_URL;
|
|
//this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
|
},
|
|
async fetchSignatureInfo(signatureInfo) {
|
|
if (this.isPaypal()) {
|
|
this.$refs.loadingModal.showModal();
|
|
}
|
|
|
|
this.authToken = signatureInfo.token;
|
|
this.authSignature = signatureInfo.signature;
|
|
this.authSignatureStart = signatureInfo.startDate;
|
|
|
|
this.$nextTick(() => {
|
|
this.$refs.myForm.submit();
|
|
|
|
if (this.paymentType == "ap") {
|
|
const iframe = this.$refs.paymentFrame;
|
|
if (iframe) {
|
|
iframe.onload = () => {
|
|
if (iframe.contentWindow) {
|
|
iframe.contentWindow.postMessage("afterpay", "*");
|
|
}
|
|
};
|
|
}
|
|
}
|
|
});
|
|
},
|
|
},
|
|
components: {
|
|
funnelHeader,
|
|
navbar,
|
|
loadingModal,
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.hop-iframe {
|
|
position: relative;
|
|
min-height: 1320px;
|
|
width: 100%;
|
|
border: 0 none;
|
|
}
|
|
</style>
|