SFCC Cartridge
Accounts
MFRA Integration
5 min
accounts mfra integration accounts sfra this section describes how to integrate the forter cartridge based on the sfra/mfra structure the section provides a list of all affected controllers integration of the cartridge into storefront application does not imply modifications of the core cartridge the standard sfra/mfra approach of overwriting files should be used instead in cases where the sfcc storefront application has same controllers or templates extended or replaced,all mentioned code modifications must be added to the top level cartridge of the storefront application 1\) account js file include the following code changes within the account js file in the int forter mfra section the exact path to account js is cartridges > int forter mfra > cartridge > controllers > account js customer login (replaces the ‘login’ with next code include) var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer login }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); customer create (replaces the `submitregistration’ with next code include) var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer create } fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); customer profile update (replaces the ‘saveprofile’ with next code include) var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer profile update }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); full account js (including overriding code changes) 'use strict'; // local modules var server = require('server'); server extend(module supermodule); var csrfprotection = require(' /cartridge/scripts/middleware/csrf'); server replace( 'login', server middleware https, csrfprotection validateajaxrequest, function (req, res, next) { var transaction = require('dw/system/transaction'); var customermgr = require('dw/customer/customermgr'); var resource = require('dw/web/resource'); var urlutils = require('dw/web/urlutils'); var email = req form loginemail; var password = req form loginpassword; var rememberme = req form loginrememberme ? (!!req form loginrememberme) false; var authenticatedcustomer; var checkoutlogin = req querystring checkoutlogin; transaction wrap(function () { authenticatedcustomer = customermgr logincustomer(email, password, rememberme); }); if (authenticatedcustomer && authenticatedcustomer authenticated) { // add the replacement 'login' code var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer login }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); // end of included 'login' code res setviewdata({ authenticatedcustomer authenticatedcustomer }); res json({ success true, redirecturl checkoutlogin ? urlutils url('checkout begin') tostring() urlutils url('account show') tostring() }); } else { res json({ error \[resource msg('error message login form', 'login', null)] }); } return next(); }); server replace( 'submitregistration', server middleware https, csrfprotection validateajaxrequest, function (req, res, next) { var customermgr = require('dw/customer/customermgr'); var resource = require('dw/web/resource'); var formerrors = require(' /cartridge/scripts/formerrors'); var registrationform = server forms getform('profile'); // form validation if (registrationform customer email value tolowercase() !== registrationform customer emailconfirm value tolowercase() ) { registrationform customer email valid = false; registrationform customer emailconfirm valid = false; registrationform customer emailconfirm error = resource msg('error message mismatch email', 'forms', null); registrationform valid = false; } if (registrationform login password value !== registrationform login passwordconfirm value ) { registrationform login password valid = false; registrationform login passwordconfirm valid = false; registrationform login passwordconfirm error = resource msg('error message mismatch password', 'forms', null); registrationform valid = false; } if (!customermgr isacceptablepassword(registrationform login password value)) { registrationform login password valid = false; registrationform login passwordconfirm valid = false; registrationform login passwordconfirm error = resource msg('error message password constraints not matched', 'forms', null); registrationform valid = false; } // setting variables for the beforecomplete function var registrationformobj = { firstname registrationform customer firstname value, lastname registrationform customer lastname value, phone registrationform customer phone value, email registrationform customer email value, emailconfirm registrationform customer emailconfirm value, password registrationform login password value, passwordconfirm registrationform login passwordconfirm value, validform registrationform valid, form registrationform }; if (registrationform valid) { res setviewdata(registrationformobj); this on('route\ beforecomplete', function (req, res) { // eslint disable line no shadow var transaction = require('dw/system/transaction'); var urlutils = require('dw/web/urlutils'); // getting variables for the beforecomplete function var registrationform = res getviewdata(); // eslint disable line if (registrationform validform) { var login = registrationform email; var password = registrationform password; var authenticatedcustomer; // attempt to create a new user and log that user in try { transaction wrap(function () { var newcustomer = customermgr createcustomer(login, password); if (newcustomer) { // assign values to the profile var newcustomerprofile = newcustomer getprofile(); authenticatedcustomer = customermgr logincustomer(login, password, false); newcustomerprofile firstname = registrationform firstname; newcustomerprofile lastname = registrationform lastname; newcustomerprofile phonehome = registrationform phone; newcustomerprofile email = registrationform email; } if (authenticatedcustomer === undefined) { registrationform validform = false; registrationform form customer email valid = false; registrationform form customer emailconfirm valid = false; } }); } catch (e) { registrationform validform = false; registrationform form customer email valid = false; registrationform form customer email error = resource msg('error message username invalid', 'forms', null); } } delete registrationform password; delete registrationform passwordconfirm; formerrors removeformvalues(registrationform form); if (registrationform validform) { // add the replacement 'customer create' code var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer create }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); // add the replacement 'login' code res setviewdata({ authenticatedcustomer authenticatedcustomer }); res json({ success true, redirecturl urlutils url('account show', 'registration', 'submitted' ) tostring() }); } else { res json({ fields formerrors getformerrors(registrationform) }); } }); } else { res json({ fields formerrors getformerrors(registrationform) }); } return next(); }); server replace( 'saveprofile', server middleware https, csrfprotection validateajaxrequest, function (req, res, next) { var transaction = require('dw/system/transaction'); var customermgr = require('dw/customer/customermgr'); var resource = require('dw/web/resource'); var urlutils = require('dw/web/urlutils'); var formerrors = require(' /cartridge/scripts/formerrors'); var profileform = server forms getform('profile'); // form validation if (profileform customer email value tolowercase() !== profileform customer emailconfirm value tolowercase()) { profileform valid = false; profileform customer email valid = false; profileform customer emailconfirm valid = false; profileform customer emailconfirm error = resource msg('error message mismatch email', 'forms', null); } var result = { firstname profileform customer firstname value, lastname profileform customer lastname value, phone profileform customer phone value, email profileform customer email value, confirmemail profileform customer emailconfirm value, password profileform login password value, profileform profileform }; if (profileform valid) { res setviewdata(result); this on('route\ beforecomplete', function (req, res) { // eslint disable line no shadow var forminfo = res getviewdata(); var customer = customermgr getcustomerbycustomernumber( req currentcustomer profile customerno ); var profile = customer getprofile(); var customerlogin; var status; transaction wrap(function () { status = profile credentials setpassword( forminfo password, forminfo password, true ); if (status error) { forminfo profileform login password valid = false; forminfo profileform login password error = resource msg('error message currentpasswordnomatch', 'forms', null); } else { customerlogin = profile credentials setlogin( forminfo email, forminfo password ); } }); delete forminfo password; delete forminfo confirmemail; if (customerlogin) { transaction wrap(function () { profile setfirstname(forminfo firstname); profile setlastname(forminfo lastname); profile setemail(forminfo email); profile setphonehome(forminfo phone); }); delete forminfo profileform; delete forminfo email; // add the replacement 'customer profile update' code var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer profile update }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); // end 'customer profile update' code res json({ success true, redirecturl urlutils url('account show') tostring() }); } else { if (!status error) { forminfo profileform customer email valid = false; forminfo profileform customer email error = resource msg('error message username invalid', 'forms', null); } delete forminfo profileform; delete forminfo email; res json({ success false, fields formerrors getformerrors(profileform) }); } }); } else { res json({ success false, fields formerrors getformerrors(profileform) }); } return next(); }); module exports = server exports(); 2\) address js file include the following code changes within the address js file in the int forter mfra section the exact path to account js is cartridges > int forter mfra > cartridge > controllers > address js the full address js file is also included below customer address update (replaces the 'list' with below code) include the below code in the `address js` file var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer address update }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); full address js file 'use strict'; //local modules var server = require('server'); server extend(module supermodule); server append('list', function (req, res, next) { // add the replacement `customer address update` code var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer address update }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); // end of included 'customer address update` code next(); }); module exports = server exports(); 3\) login js file include the following code changes within the login js file in the int forter mfra section the exact path to account js is cartridges > int forter mfra > cartridge > controllers > login js the full login js file is also included below customer logout (prepends the ‘logout’ with next code include) var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer logout }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); full login js file 'use strict'; //local modules var server = require('server'); server extend(module supermodule); server prepend('logout', function (req, res, next) { // add the replacement `customer logout` code var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer logout }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); // end `customer logout` code next(); }); module exports = server exports(); 4\) paymentinstruments js file include the below code changes to the paymentinstrument js file in the int forter mfra section the exact path to account js is cartridges > int forter mfra > cartridge > controllers > paymentinstrument js the full paymentinstrument js file is also included below customer payment update (appends the ‘list’ with next code include) var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer payment update }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); full paymentinstrument js file 'use strict'; //local modules var server = require('server'); server extend(module supermodule); var csrfprotection = require(' /cartridge/scripts/middleware/csrf'); / checks if a credit card is valid or not @param {object} card plain object with card details @param {object} form form object @returns {boolean} a boolean representing card validation / function verifycard(card, form) { var collections = require(' /cartridge/scripts/util/collections'); var resource = require('dw/web/resource'); var paymentmgr = require('dw/order/paymentmgr'); var paymentstatuscodes = require('dw/order/paymentstatuscodes'); var paymentcard = paymentmgr getpaymentcard(card cardtype); var error = false; var cardnumber = card cardnumber; var creditcardstatus; var formcardnumber = form cardnumber; if (paymentcard) { creditcardstatus = paymentcard verify( card expirationmonth, card expirationyear, cardnumber ); } else { formcardnumber valid = false; formcardnumber error = resource msg('error message creditnumber invalid', 'forms', null); error = true; } if (creditcardstatus && creditcardstatus error) { collections foreach(creditcardstatus items, function (item) { switch (item code) { case paymentstatuscodes creditcard invalid card number formcardnumber valid = false; formcardnumber error = resource msg('error message creditnumber invalid', 'forms', null); error = true; break; case paymentstatuscodes creditcard invalid expiration date var expirationmonth = form expirationmonth; var expirationyear = form expirationyear; expirationmonth valid = false; expirationmonth error = resource msg('error message creditexpiration expired', 'forms', null); expirationyear valid = false; error = true; break; default error = true; } }); } return error; } / creates an object from form values @param {object} paymentform form object @returns {object} a plain object of payment instrument / function getdetailsobject(paymentform) { return { name paymentform cardowner value, cardnumber paymentform cardnumber value, cardtype paymentform cardtype value, expirationmonth paymentform expirationmonth value, expirationyear paymentform expirationyear value, paymentform paymentform }; } server append('list', function (req, res, next) { // add the replacement `customer payment update` code var argcustomerupdate = { eventtype require(' /cartridge/scripts/lib/forter/forterconfig ds') forterconfig customer payment update }, fortercall = require(' /cartridge/scripts/pipelets/forter/fortercustomerupdate'); fortercall execute(argcustomerupdate); // end the replacement `customer payment update` code next(); }); server replace( 'savepayment', csrfprotection validateajaxrequest, function (req, res, next) { var formerrors = require(' /cartridge/scripts/formerrors'); var hookmgr = require('dw/system/hookmgr'); var paymentmgr = require('dw/order/paymentmgr'); var dworderpaymentinstrument = require('dw/order/paymentinstrument'); var paymentform = server forms getform('creditcard'); var result = getdetailsobject(paymentform); if (paymentform valid && !verifycard(result, paymentform)) { res setviewdata(result); this on('route\ beforecomplete', function (req, res) { // eslint disable line no shadow var urlutils = require('dw/web/urlutils'); var customermgr = require('dw/customer/customermgr'); var transaction = require('dw/system/transaction'); var forminfo = res getviewdata(); var customer = customermgr getcustomerbycustomernumber( req currentcustomer profile customerno ); var wallet = customer getprofile() getwallet(); transaction wrap(function () { var paymentinstrument = wallet createpaymentinstrument('credit card'); paymentinstrument setcreditcardholder(forminfo name); paymentinstrument setcreditcardnumber(forminfo cardnumber); paymentinstrument setcreditcardtype(forminfo cardtype); paymentinstrument setcreditcardexpirationmonth(forminfo expirationmonth); paymentinstrument setcreditcardexpirationyear(forminfo expirationyear); //the basic random tokenization makes impossible to get a raw cc number for forter call / var processor = paymentmgr getpaymentmethod(dworderpaymentinstrument method credit card) getpaymentprocessor(); var token = hookmgr callhook( 'app payment processor ' + processor id tolowercase(), 'createmocktoken' ); paymentinstrument setcreditcardtoken(token); / }); res json({ success true, redirecturl urlutils url('paymentinstruments list') tostring() }); }); } else { res json({ success false, fields formerrors getformerrors(paymentform) }); } return next(); }); module exports = server exports(); 5\) checkoutservices js the checkoutservices js file replaces the placeorder with the below code in order to handle the customized error massage configured in the forter business manager extension if (forterconfig fortershowdeclinedpage == true && !empty(forterconfig fortercustomdeclinemessage)) { res json({ error true, errormessage forterconfig fortercustomdeclinemessage }); } full checkoutservices js file 'use strict'; var server = require('server'); server extend(module supermodule); var cohelpers = require(' /cartridge/scripts/checkout/checkouthelpers'); var csrfprotection = require(' /cartridge/scripts/middleware/csrf'); var forterconfig = require('int forter mfra/cartridge/scripts/lib/forter/forterconfig ds') forterconfig; server replace('placeorder', server middleware https, function (req, res, next) { var basketmgr = require('dw/order/basketmgr'); var hookmgr = require('dw/system/hookmgr'); var ordermgr = require('dw/order/ordermgr'); var resource = require('dw/web/resource'); var transaction = require('dw/system/transaction'); var urlutils = require('dw/web/urlutils'); var basketcalculationhelpers = require(' /cartridge/scripts/helpers/basketcalculationhelpers'); var currentbasket = basketmgr getcurrentbasket(); if (!currentbasket) { res json({ error true, carterror true, fielderrors \[], servererrors \[], redirecturl urlutils url('cart show') tostring() }); return next(); } if (req session privacycache get('frauddetectionstatus')) { res json({ error true, carterror true, redirecturl urlutils url('error errorcode', 'err', '01') tostring(), errormessage resource msg('error technical', 'checkout', null) }); return next(); } var validationbasketstatus = hookmgr callhook( 'app validate basket', 'validatebasket', currentbasket, false ); if (validationbasketstatus error) { res json({ error true, errormessage validationbasketstatus message }); return next(); } // check to make sure there is a shipping address if (currentbasket defaultshipment shippingaddress === null) { res json({ error true, errorstage { stage 'shipping', step 'address' }, errormessage resource msg('error no shipping address', 'checkout', null) }); return next(); } // check to make sure billing address exists if (!currentbasket billingaddress) { res json({ error true, errorstage { stage 'payment', step 'billingaddress' }, errormessage resource msg('error no billing address', 'checkout', null) }); return next(); } // calculate the basket transaction wrap(function () { basketcalculationhelpers calculatetotals(currentbasket); }); // re validates existing payment instruments var validpayment = cohelpers validatepayment(req, currentbasket); if (validpayment error) { res json({ error true, errorstage { stage 'payment', step 'paymentinstrument' }, errormessage resource msg('error payment not valid', 'checkout', null) }); return next(); } // re calculate the payments var calculatedpaymenttransactiontotal = cohelpers calculatepaymenttransaction(currentbasket); if (calculatedpaymenttransactiontotal error) { res json({ error true, errormessage resource msg('error technical', 'checkout', null) }); return next(); } // creates a new order var order = cohelpers createorder(currentbasket); if (!order) { res json({ error true, errormessage resource msg('error technical', 'checkout', null) }); return next(); } // handles payment authorization var handlepaymentresult = cohelpers handlepayments(order, order orderno); if (handlepaymentresult error) { // include `custome message` code if (forterconfig fortershowdeclinedpage == true && !empty(forterconfig fortercustomdeclinemessage)) { res json({ error true, errormessage forterconfig fortercustomdeclinemessage }); } else { res json({ error true, errormessage resource msg('error technical', 'checkout', null) }); } // end `custom message` code return next(); } var frauddetectionstatus = hookmgr callhook('app fraud detection', 'frauddetection', currentbasket); if (frauddetectionstatus status === 'fail') { transaction wrap(function () { ordermgr failorder(order); }); // fraud detection failed req session privacycache set('frauddetectionstatus', true); res json({ error true, carterror true, redirecturl urlutils url('error errorcode', 'err', frauddetectionstatus errorcode) tostring(), errormessage resource msg('error technical', 'checkout', null) }); return next(); } // places the order var placeorderresult = cohelpers placeorder(order, frauddetectionstatus); if (placeorderresult error) { res json({ error true, errormessage resource msg('error technical', 'checkout', null) }); return next(); } cohelpers sendconfirmationemail(order, req locale id); // reset usingmultiship after successful order placement req session privacycache set('usingmultishipping', false); todo res json({ error false, orderid order orderno, ordertoken order ordertoken, continueurl urlutils url('order confirm') tostring() }); return next(); }); module exports = server exports(); forterconfig fortercustomdeclinemessage (replaces the ‘placeorder’ with next code include)