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
- Client-side JavaScript
- Controllers (SiteGenesis Controllers only)
- Pipelines (SiteGenesis Pipelines only)
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" />
![cp_1_htmlhead.png 1370](https://files.readme.io/aa94a8b-cp_1_htmlhead.png)
2. cartridge/templates/default/components/footer/footer_UI.isml
Paste code after the last line:
<isinclude template="affirm/affirmfooter" />
![cp_2_footer_UI.png 1075](https://files.readme.io/731fe82-cp_2_footer_UI.png)
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)}">
![cp_3_cart.png 1320](https://files.readme.io/eee04f7-cp_3_cart.png)
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">
![cp_4_options.png 1172](https://files.readme.io/2898719-cp_4_options.png)
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)}" />
![cp_5_productcontent.png 1314](https://files.readme.io/7249b7e-cp_5_productcontent.png)
6. cartridge/templates/default/checkout/billing/paymentmethods.isml
Find the following code:
![cp_6_paymentmethods-1.png 702](https://files.readme.io/6b05cec-cp_6_paymentmethods-1.png)
Replace it with the code below:
![cp_6_paymentmethods-2.png 1274](https://files.readme.io/ee237f1-cp_6_paymentmethods-2.png)
Insert the following tag after the comment tag "Custom processor":
<isinclude template="affirm/affirmpaymentmethod" />
![cp_6_paymentmethods-3.png 1341](https://files.readme.io/cff0e2e-cp_6_paymentmethods-3.png)
7. cartridge/templates/default/checkout/summary/summary.isml
Paste the following code after the COSummary-Submit
form:
<isinclude template="affirm/vcndata" />
![cp_7_summary.png 1341](https://files.readme.io/60d0716-cp_7_summary.png)
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}"/>
![cp_8_producttile.png 1302](https://files.readme.io/94dad46-cp_8_producttile.png)
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)}" />
![cp_9_producttopcontentPS.png 1338](https://files.readme.io/9a04331-cp_9_producttopcontentPS.png)
10. cartridge/templates/default/util/modules.isml
Paste the following after the content asset module import:
<isinclude template="util/affirmmodule"/>
![cp_10_modules.png 513](https://files.readme.io/80957ea-cp_10_modules.png)
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>
![cp_11_orderdetails.png 1326](https://files.readme.io/fc107e0-cp_11_orderdetails.png)
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>
![cp_12_orderdetailsemail.png 1251](https://files.readme.io/1c12aec-cp_12_orderdetailsemail.png)
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)}" >
![cp_13_confirmation.png 1086](https://files.readme.io/5308771-cp_13_confirmation.png)
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();
}
![cp_js_1_variant.png 843](https://files.readme.io/4c25c4d-cp_js_1_variant.png)
2. cartridge/js/pages/search.js
Within the $('#man').load
jQuery callback include the snippet below:
if (typeof affirm !== "undefined"){
affirm.ui.refresh();
}
![cp_js_2_search.png 842](https://files.readme.io/aa7df5d-cp_js_2_search.png)
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);
![controllers_1_COBilling-1.png 1332](https://files.readme.io/0235777-controllers_1_COBilling-1.png)
In the same file, find publicStart
function and replace applicablePaymentMethods
assignment with the following:
var applicablePaymentMethods = require('*/cartridge/controllers/Affirm').Init(cart, creditCardList.ApplicablePaymentMethods);
![controllers_1_COBilling-2.png 1323](https://files.readme.io/3d87682-controllers_1_COBilling-2.png)
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;
![controllers_1_COBilling-3.png 1320](https://files.readme.io/6f4c829-controllers_1_COBilling-3.png)
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;
}
![controllers_3_COSummary.png 1267](https://files.readme.io/6315f17-controllers_3_COSummary.png)
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:
![pipelines_1_COBilling_1.png 529](https://files.readme.io/34ccde1-pipelines_1_COBilling_1.png)
pipelines_1_COBilling_1_Affirm-Init
Find start node ResetPaymentForms
and add Pipelet nodes as shown below:
![pipelines_1_COBilling_2.png 722](https://files.readme.io/b0ff01a-pipelines_1_COBilling_2.png)
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)
![pipelines_1_COBilling_4.png 745](https://files.readme.io/dfce965-pipelines_1_COBilling_4.png)
pipelines_1_COBilling_4_ResetPaymentForms_additional_branch