Modifications to Existing Promotions Code

This topic applies to

Applies to

SuiteCommerce Advanced | Elbrus

Important

Each section below describes the required changes needed. Since many files are affected, and for simplicity, we have not described the detailed implementation steps here. However, you should implement these changes using the best practices of using extensions and overrides while ensuring that you do not impact previous customizations to your implementation. For more information, see Best Practices for Customizing SuiteCommerce Advanced.


In addition to making the changes described, you must create ns.package.json files and update your distro.json file for any custom modules you include the code updates in.

Note

After creating modifications to existing modules, you also need to create a new PromocodeNotifications custom module, Updates to the distro.json file must include this module as well. See Custom PromocodeNotifications Module.


Modify LiveOrder\SuiteScript\LiveOrder.Model.js

Replace

In the update method:

var current_order = this.get();
With
var current_order = this.get(); this.setOldPromocodes();
Replace

In the confirmationCreateResult method:

result.promocodes.push({ internalid: placed_order.getLineItemValue('promotions', 'couponcode', i) , code: placed_order.getLineItemValue('promotions', 'couponcode_display', i) , isvalid: placed_order.getLineItemValue('promotions', 'promotionisvalid', i) === 'T' , discountrate_formatted: '' //placed_order.getLineItemValue('promotions', 'discountrate', i) });
With
if(placed_order.getLineItemValue('promotions', 'applicabilitystatus', i) !== 'NOT_APPLIED') { result.promocodes.push({ internalid: placed_order.getLineItemValue('promotions', 'couponcode', i) , code: placed_order.getLineItemValue('promotions', 'couponcode_display', i) , isvalid: placed_order.getLineItemValue('promotions', 'promotionisvalid', i) === 'T' , discountrate_formatted: '' //placed_order.getLineItemValue('promotions', 'discountrate', i) }); }
Replace

in the addLines method:

var items = [] , self = this;
With
var items = [] , self = this; this.setOldPromocodes();
Replace

In the removeLine method:

// Removes the line ModelsInit.order.removeItem(line_id);
With
this.setOldPromocodes(); // Removes the line ModelsInit.order.removeItem(line_id);
Replace

In the getPromoCodes method:

, getPromoCodes: function getPromoCodes (order_fields) { var result = []; if (order_fields.promocodes && order_fields.promocodes.length) { _.each(order_fields.promocodes, function (promo_code) { // @class LiveOrder.Model.PromoCode result.push({ // @property {String} internalid internalid: promo_code.internalid // @property {String} code , code: promo_code.promocode // @property {Boolean} isvalid , isvalid: promo_code.isvalid === 'T' // @property {String} discountrate_formatted , discountrate_formatted: '' , errormsg : promo_code.errormsg , name: promo_code.discount_name , rate: promo_code.discount_rate , type: promo_code.discount_type }); }); } return result; }
With
, getPromoCodes: function getPromoCodes (order_fields) { var result = [] , self = this; if (order_fields.promocodes && order_fields.promocodes.length) { _.each(order_fields.promocodes, function (promo_code) { // @class LiveOrder.Model.PromoCode var promocode = { // @property {String} internalid internalid: promo_code.internalid // @property {String} code , code: promo_code.promocode // @property {Boolean} isvalid , isvalid: promo_code.isvalid === 'T' // @property {String} discountrate_formatted , discountrate_formatted: '' , errormsg : promo_code.errormsg , name: promo_code.discount_name , rate: promo_code.discount_rate , type: promo_code.discount_type }; if (!_.isUndefined(promo_code.is_auto_applied)) { // @property {Boolean} isautoapplied promocode.isautoapplied = promo_code.is_auto_applied; // @property {String} applicabilitystatus promocode.applicabilitystatus = (promo_code.applicability_status) ? promo_code.applicability_status : ''; // @property {String} applicabilityreason promocode.applicabilityreason = (promo_code.applicability_reason) ? promo_code.applicability_reason : ''; } if (!_.isUndefined(promo_code.is_auto_applied) && !_.isUndefined(promo_code.applicability_status) && !_.isUndefined(promo_code.applicability_reason) && !_.isUndefined(self.old_promocodes)) { var old_promocode = (self.old_promocodes) ? _.find(self.old_promocodes, function (old_promo_code){ return old_promo_code.internalid === promo_code.internalid; }) : ''; if (!old_promocode || old_promocode.applicability_status !== promo_code.applicability_status || (!promo_code.is_auto_applied && promo_code.applicability_reason !== old_promocode.applicability_reason)) { promocode.notification = true; } } result.push(promocode); }); delete this.old_promocodes; } return result; }
Replace

In the getOptionByCartOptionId method:

, getOptionByCartOptionId: function getOptionByCartOptionId (options, cart_option_id) { return _.findWhere(options, {cartOptionId: cart_option_id}); }
With
, getOptionByCartOptionId: function getOptionByCartOptionId (options, cart_option_id) { return _.findWhere(options, {cartOptionId: cart_option_id}); } // @method setOldPromocodes sets a local instance of the order's promocodes, used to be able to detect changes in a promocode. , setOldPromocodes: function setOldPromocodes () { var order_fields = this.getFieldValues(); this.old_promocodes = order_fields.promocodes; }

Modify Transaction\SuiteScript\Transaction.Model.js

Replace

In the getRecordPromocodes method:

this.result.promocodes.push({ //@class Transaction.Model.Get.Promocode //@property {String} internalid internalid: this.record.getLineItemValue('promotions', 'couponcode', i) //@property {String} code , code: this.record.getLineItemValue('promotions', 'couponcode_display', i) //@property {Boolean} isvalid , isvalid: this.record.getLineItemValue('promotions', 'promotionisvalid', i) === 'T' //@property {String} discountrate_formatted , discountrate_formatted: ''//this.record.getLineItemValue('promotions', 'discountrate', i) });
With
if(this.record.getLineItemValue('promotions', 'applicabilitystatus', i) !== 'NOT_APPLIED'){ this.result.promocodes.push({ //@class Transaction.Model.Get.Promocode //@property {String} internalid internalid: this.record.getLineItemValue('promotions', 'couponcode', i) //@property {String} code , code: this.record.getLineItemValue('promotions', 'couponcode_display', i) //@property {Boolean} isvalid , isvalid: this.record.getLineItemValue('promotions', 'promotionisvalid', i) === 'T' //@property {String} discountrate_formatted , discountrate_formatted: ''//this.record.getLineItemValue('promotions', 'discountrate', i) }); }

Modify Cart\Templates\cart_detailed.tpl

Replace
<div data-confirm-message class="cart-detailed-confirm-message"> </div>
With
<div data-confirm-message class="cart-detailed-confirm-message"></div> <div data-view="Promocode.Notifications"></div>

Add the file Cart\Templates\cart_promocode_notifications.tpl

<div data-view="Promocode.Notification"> </div>

Add the file Cart/Sass/_cart-promocode-notifications.scss

//empty file

Modify Cart\JavaScript\Cart.Promocode.List.Item.View.js

Replace
//@module Cart define('Cart.Promocode.List.Item.View' , [ 'cart_promocode_list_item.tpl' , 'Backbone' ] , function ( cart_promocode_list_item_tpl , Backbone )
With
//@module Cart define('Cart.Promocode.List.Item.View' , [ 'cart_promocode_list_item.tpl' , 'Backbone' , 'underscore' ] , function ( cart_promocode_list_item_tpl , Backbone , _ )
Replace

In the getContext method:

var code = this.model.get('code') , internalid = this.model.get('internalid');
With
var code = this.model.get('code') , internalid = this.model.get('internalid') , hide_autoapply_promo = (!_.isUndefined(this.model.get('isautoapplied'))) ? this.model.get('applicabilityreason') === 'DISCARDED_BEST_OFFER' || (this.model.get('isautoapplied') && this.model.get('applicabilitystatus') === 'NOT_APPLIED') : false;
Replace

In the getContext method:

//@property {Boolean} showPromo showPromo: !!code
With
//@property {Boolean} showPromo showPromo: !!code && !hide_autoapply_promo
Replace

In the getContext method:

//@property {Boolean} isEditable , isEditable: !this.options.isReadOnly
With
//@property {Boolean} isEditable , isEditable: !this.options.isReadOnly && !this.model.get('isautoapplied')

Add the file Cart\JavaScript\Cart.Promocode.Notifications.View.js

//@module Cart define('Cart.Promocode.Notifications.View' , [ 'GlobalViews.Message.View' , 'cart_promocode_notifications.tpl' , 'Backbone' , 'Backbone.CompositeView' , 'underscore' ] , function ( GlobalViewsMessageView , cart_promocode_notifications , Backbone , BackboneCompositeView , _ ) { 'use strict'; //@class Cart.Promocode.Notification.View @extend Backbone.View return Backbone.View.extend({ //@property {Function} template template:cart_promocode_notifications //@method initialize //@return {Void} , initialize: function initialize () { BackboneCompositeView.add(this); this.on('afterCompositeViewRender', this.afterViewRender, this); } // @property {ChildViews} childViews , childViews: { 'Promocode.Notification': function () { var notification = this.getNotification(); return new GlobalViewsMessageView({ message: notification.message , type: notification.type , closable: true }); } } // @method afterViewRender lets parent model know the promotion already shwoed its current notification // @return {Void} , afterViewRender: function() { this.options.parentModel.trigger('promocodeNotificationShown', this.model.get('internalid')); } // @method getNotification // @return {Notification} , getNotification: function () { var notification = {}; if(this.model.get('applicabilitystatus') === 'APPLIED') { notification.type = 'success'; notification.message = _('Promotion <strong>').translate() + this.model.get('code') + _('</strong> is now affecting your order.').translate(); } else if(this.model.get('applicabilityreason') === 'CRITERIA_NOT_MET') { notification.type = (!this.model.get('isautoapplied')) ? 'warning' : 'info'; notification.message = _('Promotion <strong>').translate() + this.model.get('code') + _('</strong> is not affecting your order. ').translate() + this.model.get('errormsg'); } else if(this.model.get('applicabilityreason') === 'DISCARDED_BEST_OFFER') { notification.type = 'info'; notification.message = _('We have chosen the best possible offer for you. Promotion <strong>').translate() + this.model.get('code') + _('</strong> is not affecting your order.').translate(); } return notification; } //@method getContext //@return {Cart.Promocode.Notifications.View.context} , getContext: function getContext () { //@class Cart.Promocode.Notifications.View.context return {}; //@class Cart.Promocode.Notifications.View } }); });

Modify Cart\JavaScript\Cart.Detailed.View.js

Replace
, 'Cart.Lines.View'
With
, 'Cart.Lines.View' , 'Cart.Promocode.Notifications.View'
Replace
, CartLinesView
With
, CartLinesView , CartPromocodeNotifications
Replace

In the initialize method:

this.model.on('LINE_ROLLBACK', this.render, this);
With
this.model.on('LINE_ROLLBACK', this.render, this); this.model.on('promocodeNotificationShown', this.removePromocodeNotification, this);
Replace

In the storeColapsiblesState method:

// @method storeColapsiblesState // @return {Void} , storeColapsiblesState: function () { this.$('.collapse').each(function (index, element) { colapsibles_states[Utils.getFullPathForElement(element)] = jQuery(element).hasClass('in'); }); }
With
// @method storeColapsiblesState // @return {Void} , storeColapsiblesState: function () { this.$('.collapse').each(function (index, element) { colapsibles_states[Utils.getFullPathForElement(element)] = jQuery(element).hasClass('in'); }); } // @method removePromocodeNotification // @param String promocode_id // @return {Void} , removePromocodeNotification: function(promocode_id) { var promocode = _.findWhere(this.model.get('promocodes'), {internalid: promocode_id}); delete promocode.notification; }
Replace

In the childViews object:

, 'Item.ListNavigable': function () { return new BackboneCollectionView({ collection: this.model.get('lines') , viewsPerRow: 1 , childView: CartLinesView , childViewOptions: { navigable: true , application: this.application , SummaryView: CartItemSummaryView , ActionsView: CartItemActionsView , showAlert: false } }); }
With
, 'Item.ListNavigable': function () { return new BackboneCollectionView({ collection: this.model.get('lines') , viewsPerRow: 1 , childView: CartLinesView , childViewOptions: { navigable: true , application: this.application , SummaryView: CartItemSummaryView , ActionsView: CartItemActionsView , showAlert: false } }); } , 'Promocode.Notifications': function () { var promotions = _.filter(this.model.get('promocodes') || [], function (promocode) { return promocode.notification === true; }); if(promotions.length){ return new BackboneCollectionView({ collection: promotions , viewsPerRow: 1 , childView: CartPromocodeNotifications , childViewOptions: { parentModel: this.model } }); } }

Modify CheckoutApplication\JavaScript\SC.Checkout.Configuration.Steps.BillingFirst.js

Replace
, 'OrderWizard.Module.PromocodeForm'
With
, 'OrderWizard.Module.PromocodeForm' , 'OrderWizard.Module.PromocodeNotifications'
Replace
, OrderWizardModulePromocodeForm
With
, OrderWizardModulePromocodeForm , OrderWizardModulePromocodeNotification
Replace

In the Billing Address step:

[OrderWizardModuleMultiShipToEnableLink, {exclude_on_skip_step: true}]
With
[OrderWizardModulePromocodeNotification, {exclude_on_skip_step: true}] , [OrderWizardModuleMultiShipToEnableLink, {exclude_on_skip_step: true}]
Replace

In the Shipping Address step:

, isActive: function () { return !this.wizard.isMultiShipTo(); } , modules: [ [OrderWizardModuleMultiShipToEnableLink, {exclude_on_skip_step: true}]
With
, isActive: function () { return !this.wizard.isMultiShipTo(); } , modules: [ [OrderWizardModulePromocodeNotification, {exclude_on_skip_step: true}] , [OrderWizardModuleMultiShipToEnableLink, {exclude_on_skip_step: true}]
Replace

In the Shipping method step:

[OrderWizardModuleAddressShipping, {edit_url: '/shipping/address'}]
With
[OrderWizardModulePromocodeNotification, {exclude_on_skip_step: true}] , [OrderWizardModuleAddressShipping, {edit_url: '/shipping/address'}]
Replace

In the Payment step:

OrderWizardModulePaymentMethodGiftCertificates
With
[OrderWizardModulePromocodeNotification, {exclude_on_skip_step: true}] , OrderWizardModulePaymentMethodGiftCertificates
Replace

In the Review step:

, [OrderWizardModuleSubmitButton, {className: 'order-wizard-submitbutton-module-top'}]
With
, [OrderWizardModuleSubmitButton, {className: 'order-wizard-submitbutton-module-top'}] , [OrderWizardModulePromocodeNotification, {exclude_on_skip_step: true}]

Modify CheckoutApplication\JavaScript\SC.Checkout.Configuration.Steps.OPC.js

Replace
, 'OrderWizard.Module.PromocodeForm'
With
, 'OrderWizard.Module.PromocodeForm' , 'OrderWizard.Module.PromocodeNotifications'
Replace
, OrderWizardModulePromocodeForm
With
, OrderWizardModulePromocodeForm , OrderWizardModulePromocodeNotification
Replace

In the Checkout Information step:

[OrderWizardModuleTitle, {title: _('Shipping Address').translate(), exclude_on_skip_step: true, isActive: function() {return this.wizard.model.shippingAddressIsRequired();}}]
With
[OrderWizardModulePromocodeNotification, {exclude_on_skip_step: true}] , [OrderWizardModuleTitle, {title: _('Shipping Address').translate(), exclude_on_skip_step: true, isActive: function() {return this.wizard.model.shippingAddressIsRequired();}}]
Replace

In the Review step:

, [ //Mobile Top OrderWizardModuleSubmitButton , { className: 'order-wizard-submitbutton-module-top' } ]
With
, [ //Mobile Top OrderWizardModuleSubmitButton , { className: 'order-wizard-submitbutton-module-top' } ] , [OrderWizardModulePromocodeNotification, {exclude_on_skip_step: true}]

Modify CheckoutApplication\JavaScript\SC.Checkout.Configuration.Steps.Standard.js

Replace
, 'OrderWizard.Module.PromocodeForm'
With
, 'OrderWizard.Module.PromocodeForm' , 'OrderWizard.Module.PromocodeNotifications'
Replace
, OrderWizardModulePromocodeForm
With
, OrderWizardModulePromocodeForm , OrderWizardModulePromocodeNotification
Replace

In the Shipping Address step:

OrderWizardModuleMultiShipToEnableLink
With
[OrderWizardModulePromocodeNotification, {exclude_on_skip_step: true}] , OrderWizardModuleMultiShipToEnableLink
Replace

In the Payment step:

OrderWizardModulePaymentMethodGiftCertificates
With
[OrderWizardModulePromocodeNotification, {exclude_on_skip_step: true}] , OrderWizardModulePaymentMethodGiftCertificates
Replace

In the Review step:

, [ //Mobile Top OrderWizardModuleSubmitButton , { className: 'order-wizard-submitbutton-module-top' } ]
With
, [ //Mobile Top OrderWizardModuleSubmitButton , { className: 'order-wizard-submitbutton-module-top' } ] , [OrderWizardModulePromocodeNotification, {exclude_on_skip_step: true}]