Salesforce Commerce Cloud - Custom Code (Controllers & Pipelines)

Overview

This page describes changes that should be made to the site for SiteGenesis storefronts. Custom modifications to your core cartridge outlined in this guide can be separated to four parts: templates, client-side JavaScript, controllers (SiteGenesis Controllers version) and pipelines (SiteGenesis Pipelines version).

Templates

1. cartridge/templates/default/components/header/htmlhead.isml

Paste the following code after the “Google verification feature” as it shown on the screenshot below.

<isinclude template="affirm/affirmheader" />
1370

2. cartridge/templates/default/components/footer/footer_UI.isml

Paste code after the last line:

<isinclude template="affirm/affirmfooter" />
1075

3. cartridge/templates/default/checkout/cart/cart.isml

Find the closing tag for the div with cart-footer class (line 850). Paste code after the below:

<isaffirmpromo context="cart" fpname="${require('int_affirm/cartridge/scripts/utils/affirmUtils').getFPNameByBasket(pdict.Basket)}">
1320

4. cartridge/templates/default/product/components/options.isml

Add “data-affirm-name” property to the select component.

<select id="${Option.htmlName}" name="${Option.htmlName}" data-affirm-name="${Option.ID}" class="product-option input-select">
1172

5. cartridge/templates/default/product/productcontent.isml

Paste after “pricing component”:

<isinclude template="util/affirmmodule"/>
<isaffirmpromo context="pdp" fpname="${require('int_affirm/cartridge/scripts/utils/affirmUtils').getFinancingProgramByProduct(pdict.Product, true)}" />
1314

6. cartridge/templates/default/checkout/billing/paymentmethods.isml

Find the following code:

702

Replace it with the code below:

1274

Insert the following tag after the comment tag "Custom processor":

<isinclude template="affirm/affirmpaymentmethod" />
1341

7. cartridge/templates/default/checkout/summary/summary.isml

Paste the following code after the COSummary-Submit form:

<isinclude template="affirm/vcndata" />
1341

8. cartridge/templates/default/product/producttile.isml

Paste the code below after the product swatches block:

<isinclude template="util/affirmmodule"/>
<isaffirmpromo context="plp" fpname="${require('int_affirm/cartridge/scripts/utils/affirmUtils').getFPNameForPLP(pdict.CurrentHttpParameterMap.cgid.value, Product)}" price="${prices}"/>
1302

9. cartridge/templates/default/product/producttopcontentPS.isml

Paste the following code after the div with product-number class:

<isinclude template="util/affirmmodule"/>
<isaffirmpromo context="pdp" fpname="${require('int_affirm/cartridge/scripts/utils/affirmUtils').getFinancingProgramByProduct(pdict.Product, true)}" />
1338

10. cartridge/templates/default/util/modules.isml

Paste the following after the content asset module import:

<isinclude template="util/affirmmodule"/>
513

11. cartridge/templates/default/components/order/orderdetails.isml

Replace the div with payment-type class and isminicreditcard tag with the code below:

<isif condition="${!paymentInstr.custom.affirmed}">
			<div class="payment-type"><isprint value="${dw.order.PaymentMgr.getPaymentMethod(paymentInstr.paymentMethod).name}" /> </div>
			<isminicreditcard card="${paymentInstr}" show_expiration="${false}"/>
		<iselse/>
			<isaffirmpaymenttype email="${false}"/>
</isif>
1326

12. cartridge/templates/default/components/order/orderdetailsemail.isml

Replace lines above isminicreditcard tag (lines 46-50) with the code below:

<isif condition="${!paymentInstr.custom.affirmed}">
	<div><isprint value="${dw.order.PaymentMgr.getPaymentMethod(paymentInstr.paymentMethod).name}" /></div>
	<isif condition="${dw.order.PaymentInstrument.METHOD_GIFT_CERTIFICATE.equals(paymentInstr.paymentMethod)}">
		<isprint value="${paymentInstr.maskedGiftCertificateCode}"/><br />
	</isif>
	<isminicreditcard card="${paymentInstr}" show_expiration="${false}"/>
<iselse/>
	<isaffirmpaymenttype email="${true}"/>
</isif>
1251

13. cartridge/templates/default/checkout/confirmation/confirmation.isml

Paste the following code after the close tag of the div with confirmation message class to include tracking script template:

<isinclude url="${URLUtils.http('Affirm-Tracking', 'orderId', pdict.Order.orderNo)}" >
1086

14. int_affirm_controllers/cartridge/templates/resources/affirm.properties

Find the property affirm.controllers.cartridge. Set it as the name of your controllers cartridge (with script files app.js, guard.js), for example:

affirm.controllers.cartridge=app_storefront_controllers

Client-side JavaScript

1. cartridge/js/pages/product/variant.js

Update the ajax.load within updateContent method with the following snippet:

if (typeof affirm !== "undefined"){
    affirm.ui.refresh();
}
843

2. cartridge/js/pages/search.js

Within the $('#man').load jQuery callback include the snippet below:

if (typeof affirm !== "undefined"){
    affirm.ui.refresh();
}
842

3. cartridge/js/pages/product/productSet.js

Update on('click') of event action with $productSetList with the extended code:

var updateAffirmItems = function($container, oldSKU) {
        var affirmItem = affirmItems.find(function (item) {
            return item.sku === oldSKU;
        });
 
        affirmItem.sku = $container.find('input[name=pid]').first().val();
    }
 
var updateBuyWithAffirmButton = function () {
        if ($productSetList.find('.add-to-cart[disabled]').length > 0) {
            $('#js-affirm-checkout-now').hide();
        } else {
            $('#js-affirm-checkout-now').show();
            document.dispatchEvent(new CustomEvent('affirm-checkout-button-rendered')); 
        }
            };
 
    // click on swatch for product set
    $productSetList.on('click', '.product-set-item .swatchanchor', function (e) {
        e.preventDefault();
        if ($(this).parents('li').hasClass('unselectable')) { return; }
        var url = Urls.getSetItem + this.search;
        var $container = $(this).closest('.product-set-item');
        var qty = $container.find('form input[name="Quantity"]').first().val();
 
        var oldSKU = $container.find('input[name=pid]').first().val();
        ajax.load({
            url: util.appendParamToURL(url, 'Quantity', isNaN(qty) ? '1' : qty),
            target: $container,
            callback: function () {
                updateAddToCartButtons();
                updateAffirmItems($container, oldSKU);
                updateBuyWithAffirmButton();
                tooltip.init();
            }
        });
    });

📘

Important

To properly render “affirm-as-low” on PDP, PLP and Cart, at the end of handle functions that influence price on basket (ajax product price change, quantity based price change, pagination, search, add-on price change etc.) must call the affirm.ui.refresh function.

👍

Make sure to rebuild client JS after making modifications.


Controllers (SiteGenesis Controllers)

1. cartridge/controllers/COBilling.js

Reassign applicablePaymentMethods within initCreditCardList function with the following code:

applicablePaymentMethods = require('*/cartridge/controllers/Affirm').Init(cart, applicablePaymentMethods);
1332

In the same file, find publicStart function and replace applicablePaymentMethods assignment with the following:

var applicablePaymentMethods = require('*/cartridge/controllers/Affirm').Init(cart, creditCardList.ApplicablePaymentMethods);
1323

Replace the status assignment within resetPaymentForms function with the following block of code:

var status = Transaction.wrap(function () {
        if (app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value.equals('PayPal')) {
            app.getForm('billing').object.paymentMethods.creditCard.clearFormElement();
            app.getForm('billing').object.paymentMethods.bml.clearFormElement();

            cart.removePaymentInstruments(cart.getPaymentInstruments(PaymentInstrument.METHOD_CREDIT_CARD));
            cart.removePaymentInstruments(cart.getPaymentInstruments(PaymentInstrument.METHOD_BML));
            cart.removePaymentInstruments(cart.getPaymentInstruments('Affirm'));
        } else if (app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value.equals(PaymentInstrument.METHOD_CREDIT_CARD)) {
            app.getForm('billing').object.paymentMethods.bml.clearFormElement();

            cart.removePaymentInstruments(cart.getPaymentInstruments(PaymentInstrument.METHOD_BML));
            cart.removePaymentInstruments(cart.getPaymentInstruments('PayPal'));
            cart.removePaymentInstruments(cart.getPaymentInstruments('Affirm'));
        } else if (app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value.equals(PaymentInstrument.METHOD_BML)) {
            app.getForm('billing').object.paymentMethods.creditCard.clearFormElement();

            if (!app.getForm('billing').object.paymentMethods.bml.ssn.valid) {
                return false;
            }
            cart.removePaymentInstruments(cart.getPaymentInstruments(PaymentInstrument.METHOD_CREDIT_CARD));
            cart.removePaymentInstruments(cart.getPaymentInstruments('PayPal'));
            cart.removePaymentInstruments(cart.getPaymentInstruments('Affirm'));
        } else if (app.getForm('billing').object.paymentMethods.selectedPaymentMethodID.value.equals('Affirm')) {
        	cart.removePaymentInstruments(cart.getPaymentInstruments(PaymentInstrument.METHOD_CREDIT_CARD));
            cart.removePaymentInstruments(cart.getPaymentInstruments(PaymentInstrument.METHOD_BML));
            cart.removePaymentInstruments(cart.getPaymentInstruments('PayPal'));
        }
        return true;
    });

    return status;
1320

2. cartridge/controllers/COPlaceOrder.js

Below the saveCCResult variable and its conditional check, include affirmController to get Affirm status with the snippet below:

var affirmController = require('int_affirm_controllers/cartridge/controllers/Affirm');
var affirmCheck = affirmController.CheckCart(cart);
if (affirmCheck.status.error) {
	return {
		error: true,
		PlaceOrderError: affirmCheck.status
	};
}

3. cartridge/controllers/COSummary.js

Go to submit function. Add the following at the beginning of the function:

var redirected = require('int_affirm_controllers/cartridge/controllers/Affirm').Redirect();
if (redirected) {
	return;
}
1267

Pipelines (SiteGenesis Pipelines)

1. cartridge/pipelines/COBilling.xml

Find the start node InitCreditCardList and add call node (Affirm-Init, int_affirm_pipelines) after second Assign node:

529

pipelines_1_COBilling_1_Affirm-Init

Find start node ResetPaymentForms and add Pipelet nodes as shown below:

722

pipelines_1_COBilling_2_ResetPaymentForms

In the same pipeline create an additional branch:
a. Decision node – Decision Key: !CurrentForms.billing.paymentMethods.selectedPaymentMethodID.value.equals('Affirm')
b. ClearFormElement Pipelet – FormElement: CurrentForms.billing.paymentMethods.creditCard
c. ClearFormElement Pipelet – FormElement: CurrentForms.billing.paymentMethods.bml
d. RemoveBasketPaymentInstrument Pipelet – PaymentInstruments: Basket.getPaymentInstruments(dw.order.PaymentInstrument.METHOD_CREDIT_CARD)
e. RemoveBasketPaymentInstrument Pipelet – PaymentInstruments: Basket.getPaymentInstruments( dw.order.PaymentInstrument.METHOD_BML)

745

pipelines_1_COBilling_4_ResetPaymentForms_additional_branch