Shopify Checkout MFPP code

{% comment %}<!-- Zip MFPP -->{% endcomment %}
<script type="application/javascript">
{% assign quadpay_default_money_format = '${{amount}}' %}
window.QuadPayCheckoutOptions = {
    merchantId: "{{quadpay_merchant_id}}",
    state: "{{checkout.shipping_address.province_code}}",
    country: "{{checkout.shipping_address.country_code}}",
    currency: "{{shop.currency}}",
    moneyFormat: "{{quadpay_money_format | default: quadpay_default_money_format}}",
    quadpayGatewaySelector: "{{quadpay_selector}}",
    gatewaysSelector: "{{quadpay_all_gateways_selector | default: '.section--payment-method .section__content'}}",
    totalSelector: "{{quadpay_total_selector | default: '.total-line-table__footer .total-line__price .payment-due__price'}}",
    totalDataName: "{{quadpay_total_data_name | default: 'checkout-payment-due-target'}}",
    subtotalsSelector: "{{quadpay_subtotals_selector | default: '.total-line-table__tbody'}}",
    quadpayFeeApi: "https://gateway.quadpay.com/orders/calculate-merchant-fees",
};

{% assign quadpay_transaction = checkout.transactions | where: "gateway", "quadpay" | first %}
{% if quadpay_transaction %}
{% comment %}/* Thank You page and paid with QuadPay. */{% endcomment %}
window.QuadPayCheckoutOptions.thankYouPageFee = {{ quadpay_transaction.amount | minus: checkout.total_price }};
{% endif %}

window.QuadPayCheckout = {
    init: function(options, jQuery, step) {
        this.jQuery = jQuery;
        
        this.totalSelector = options.totalSelector;
        this.totalDataName = options.totalDataName;
        this.currency = options.currency;
        this.moneyFormat = options.moneyFormat;
        this.subtotalsSelector = options.subtotalsSelector;

        this.totalLineSelector = '.total-line--quadpay-fee';

        if (step === 'payment_method') {
            this.initPaymentMethodStep(options);
        } else {
            this.initThankYouPage(options);
        }
    },

    initPaymentMethodStep: function(options) {
        this.quadpayFeeApi = options.quadpayFeeApi;
        this.quadpayGatewaySelector = options.quadpayGatewaySelector;
        this.gatewaysSelector = options.gatewaysSelector;

        this.originalCustomerBillingAddressLocation = {
            customerCountry: options.country,
            customerState: options.state
        };

        this.customerBillingAddressLocation = {
            customerCountry: options.country,
            customerState: options.state
        };

        this.shopifyTotal = this.getShopifyTotal();

        this.merchantId = options.merchantId;

        this.monitorGatewaySelection();
        this.monitorBillingAddressForm();

        this.refresh(true);
    },

    initThankYouPage: function(options) {
        var fee = options.thankYouPageFee;
        if (fee) {
            this.shopifyTotal = this.getShopifyTotal();
            this.setTotalLinePriceIncrease(fee);
            this.setQuadPayLinePrice(fee);    
        }
    },

    refresh: function(reloadFee) {
        var self = this;
        if (reloadFee === true) {
            this.fee = null;
        }
        this.getQuadPayFee(function (fee) {
            self.fee = fee;
            if (self.quadpayIsSelected === true) {
                self.repaintFee();
            } else {
                self.hideFee();
            }
        });
    },

    repaintFee: function() {
        this.setTotalLinePriceIncrease(this.fee);
        this.setQuadPayLinePrice(this.fee);
    },

    hideFee: function() {
        this.setTotalLinePriceIncrease(0);
        this.setQuadPayLinePrice(null);
    },

    setTotalLinePriceIncrease: function(fee) {
        var total = this.shopifyTotal + fee;

        this.jQuery(this.totalSelector + ', .total-recap__final-price').html(this.shopifyFormatMoney(total));
    },

    setQuadPayLinePrice: function(fee) {
        var quadPayLine = this.jQuery(this.totalLineSelector);
        if (quadPayLine.length > 0) {
            quadPayLine.remove();
        }

        if (fee === null || fee < 0.01) {
            return;
        }
        
        this.generateQuadPayFeeLine(fee);
    },

    monitorGatewaySelection: function() {
        var self = this;

        this.quadpayIsSelected = null;
        var gatewaySelected = function() {
            var radio = self.jQuery(self.quadpayGatewaySelector);
            var isSelected = radio.is(':checked');

            var shouldRefresh = self.quadpayIsSelected !== null && self.quadpayIsSelected !== isSelected;
            self.quadpayIsSelected = isSelected;

            if (shouldRefresh) {
                self.refresh(false);
            }
        };

        this.jQuery(this.gatewaysSelector).click(gatewaySelected);

        gatewaySelected();
    },

    monitorBillingAddressForm: function() {
        var self = this;

        var shouldRefresh = false;
        var useBillingAddressSelector = '#checkout_different_billing_address_true';
        var countrySelector = '#checkout_billing_address_country';
        var stateSelector = '#checkout_billing_address_province';

        this.useShippingAddressForBilling = null;
        var billingFormChange = function () {
            var useShippingAddressForBilling = !self.jQuery(useBillingAddressSelector).is(':checked');

            var countryCode = self.originalCustomerBillingAddressLocation.customerCountry;
            var stateCode = self.originalCustomerBillingAddressLocation.customerState;

            if (!useShippingAddressForBilling) {
                var country = self.jQuery(countrySelector + ' option:selected');
                if (country.length) {
                    countryCode = country.data('code');
                } else {
                    countryCode = null;
                }

                var state = self.jQuery(stateSelector + ' option:selected');
                if (country.length) {
                    stateCode = state.val();
                } else {
                    stateCode = null;
                }
            }
            
            if ((self.useShippingAddressForBilling !== null && 
                useShippingAddressForBilling !== self.useShippingAddressForBilling) ||
                countryCode !== self.customerBillingAddressLocation.customerCountry || 
                stateCode !== self.customerBillingAddressLocation.customerState 
            ) {
                shouldRefresh = true;
            }

            self.customerBillingAddressLocation = {
                customerCountry: countryCode,
                customerState: stateCode
            };

            self.useShippingAddressForBilling = useShippingAddressForBilling;

            if (shouldRefresh) {
                self.refresh(true);
            }
        };

        this.jQuery('.section--billing-address').change(billingFormChange);

        billingFormChange();
    },

    generateQuadPayFeeLine: function(fee) {
        this.jQuery(this.subtotalsSelector).append(
            this.generateLine(fee)
        );
    },

    generateLine: function(fee) {
        var className = this.totalLineSelector.replace(/^\./, '');
        return '<tr class="total-line ' + className + '">' +
                    '<th class="total-line__name" scope="row">Merchant fee for payment plan</th>' +
                    '<td class="total-line__price"><b>' + this.shopifyFormatMoney(fee) + '</b></td>' +
               '</tr>';
    },

    getQuadPayFee: function(callbackFn) {
        if (this.fee !== null) {
            callbackFn(this.fee);
            return;
        }

        this.fetchFee().done(function (data) {
            var fee = parseFloat(data.merchantFeeForPaymentPlan) * 100;

            callbackFn(fee);
        });
    },

    fetchFee: function() {
        var totalForQuadPay = this.shopifyTotal / 100;

        var dataForQuadPay = {
            merchantId: this.merchantId,
            currency: this.currency,
            customerCountry: this.customerBillingAddressLocation.customerCountry,
            amount: totalForQuadPay
        };

        if (this.customerBillingAddressLocation.customerState) {
            dataForQuadPay.customerState = this.customerBillingAddressLocation.customerState;
        }

        return this.jQuery.ajax({
            url: this.quadpayFeeApi,
            method: 'POST',
            contentType: 'application/json',
            data: JSON.stringify(dataForQuadPay)
        });
    },

    getShopifyTotal: function() {
        var totalElement = this.jQuery(this.totalSelector);
        if (totalElement.length < 1) {
            return;
        }

        return parseInt(totalElement.data(this.totalDataName), 10);
    },

    shopifyFormatMoney: function(cents) {
        if (typeof cents == 'string') {
            cents = cents.replace('.',''); 
        }
        var value = '';
        var placeholderRegex = /\{\{\s*(\w+)\s*.*\}\}/;
        var formatString = this.moneyFormat;
        
        function defaultOption(opt, def) {
            return (typeof opt == 'undefined' ? def : opt);
        }
        
        function formatWithDelimiters(number, precision, thousands, decimal) {
            precision = defaultOption(precision, 2);
            thousands = defaultOption(thousands, ',');
            decimal   = defaultOption(decimal, '.');
        
            if (isNaN(number) || number == null) { return 0; }
        
            number = (number/100.0).toFixed(precision);
        
            var parts   = number.split('.'),
                dollars = parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + thousands),
                cents   = parts[1] ? (decimal + parts[1]) : '';
        
            return dollars + cents;
        }
        
        switch(formatString.match(placeholderRegex)[1]) {
            case 'amount':
            value = formatWithDelimiters(cents, 2);
            break;
            case 'amount_no_decimals':
            value = formatWithDelimiters(cents, 0);
            break;
            case 'amount_with_comma_separator':
            value = formatWithDelimiters(cents, 2, '.', ',');
            break;
            case 'amount_no_decimals_with_comma_separator':
            value = formatWithDelimiters(cents, 0, '.', ',');
            break;
        }
        
        return formatString.replace(placeholderRegex, value);
    }
};

window.Checkout.$(function() {
    var step = window.Shopify.Checkout.step;
    if (!step && window.QuadPayCheckoutOptions.thankYouPageFee) {
        step = 'thank_you';
    }

    if (['payment_method', 'thank_you'].indexOf(step) !== -1) {
        window.QuadPayCheckout.init(window.QuadPayCheckoutOptions, window.Checkout.$, step);
    }
});
</script>