there seems to be a fidelity issue using scriptabl...
# suitecommerce
t
there seems to be a fidelity issue using scriptable cart. we are trying to do custom pricing rules and after completion we read the line item rates and amounts as having changed successfully in scriptable cart but in the suitecommerce cart the rates haven't changed. the crazy part is that the cart Total shows the updated amount with the rates changed from scriptable cart so now the cart line amounts and the cart total doesn't equal. the live order put response shows the same inconsistency this is kind of scary as a basic premise of using software is that fidelity issues like this can't exist
m
Hey, Scriptable Cart can be really tricky to implement properly. Are you able to share the Client script?
c
There are a ton of guidelines in the docs for using scriptable cart. Make sure you read ALL of them. It's a very powerful AND finicky solution. Iirc, every time you make a script change, you need a new incognito window to test your changes b/c the script is cached per user form.
💯 1
m
Yup. Testing in a fresh Incognito window is definitely a must to ensure you are working on the last version of your Client Script.
t
I'm ok with finicky but not ok with inconsistent data. in suitescript it logs the new rates as having changed but in suitecommerce only the order total is changing not the rates. sometimes when I navigate to another view/page the rates then update so maybe a timing issue or next tick. I tried to add an extra liveOrder.fetch() but it didn't help
would appreciate a second pair of eyes. the main logic is to recalculate rates on field change (to each price). I can see the field change register in the logs
Copy code
var EVENT;
var PROCESSING = false;


function recalc(type, action) {
  EVENT = 'recalc';
  var context = nlapiGetContext();
  var executionContext = context.getExecutionContext();

  if (executionContext !== 'webstore') return;
  nlapiLogExecution('DEBUG', EVENT + ' type:action', type + ':' + action);

  var isItemChange = (type === 'item' && (action === 'commit' || action === 'remove'));

  if (!isItemChange) return;

  if (PROCESSING) {
    nlapiLogExecution('DEBUG', EVENT + ' type:action already processing', type + ':' + action);
    return true;
  }

  PROCESSING = true;

  var showType = nlapiGetFieldValue('custbody_nafco_showfx_shop_type');

  nlapiLogExecution('DEBUG', EVENT + ' isItemChange', isItemChange);
  nlapiLogExecution('DEBUG', EVENT + ' executionContext', executionContext);
  nlapiLogExecution('DEBUG', EVENT + ' field showType', showType);

  var amount = nlapiGetFieldValue('subtotal');
  // updateHandling(amount, showType);

  if (Number(showType) === 1) {
    updateHandling(amount, showType);
  }

  var lineCount = nlapiGetLineItemCount('item');
  for (var i = 1; i <= lineCount; i++) {
    var rate = nlapiGetLineItemValue('item', 'rate', i);
    var amt = nlapiGetLineItemValue('item', 'amount', i);
    var priceLevel = nlapiGetLineItemValue('item', 'price', i);
    nlapiLogExecution('DEBUG', EVENT + ' line item', 'Line ' + i + ': Rate ' + rate + ', Amount ' + amt + ', Price Level ' + priceLevel);
  }

  PROCESSING = false;
}

function saveRecord() {
  var context = nlapiGetContext();
  var executionContext = context.getExecutionContext();
  if (executionContext !== 'webstore') return true;
  nlapiLogExecution('DEBUG', 'saveRecord executionContext', executionContext);

  var currSession = context.getSessionObject('shopflow');

  if (currSession) {
    currSession = JSON.parse(currSession);
    currSession.saved = 'T';
    currSession.savedAt = new Date().getTime();
    context.setSessionObject('shopflow', JSON.stringify(currSession));
  }

  return true;
}

function fieldChanged(type, name, linenum) {
  if (type === 'item') return true;
  var context = nlapiGetContext();

  var executionContext = context.getExecutionContext();

  if (executionContext !== 'webstore') return;

  nlapiLogExecution('DEBUG', 'fieldChanged name', name);
  var amount = nlapiGetFieldValue('total');
  var showType = nlapiGetFieldValue('custbody_nafco_showfx_shop_type');
  nlapiLogExecution('DEBUG', 'fieldChanged showType', showType);

  if (name !== 'custbody_nafco_showfx_shop_type') {
    return;
  }

  EVENT = 'fieldChanged';

  var oldShopType = null;

  nlapiLogExecution('DEBUG', 'fieldChanged executionContext', executionContext);

  var currSession = context.getSessionObject('shopflow');

  if (currSession) {
    currSession = JSON.parse(currSession);
    oldShopType = currSession.shopflowtype;
  } else {
    currSession = { items: {}, saved: 'F', savedAt: null };
  }

  var isShopTypeChange = (showType && showType !== oldShopType);

  nlapiLogExecution('DEBUG', 'fieldChanged isShopTypeChange', isShopTypeChange);

  /* if (!isShopTypeChange) {
    return;
  } */

  currSession.shopflowtype = showType;

  nlapiLogExecution('DEBUG', 'fieldChanged currSession', JSON.stringify(currSession));

  nlapiLogExecution('DEBUG', 'fieldChanged showType', showType);

  togglePricing(showType, currSession);

  context.setSessionObject('shopflow', JSON.stringify(currSession));

  // nlapiSetFieldValue('custbody_bpc_miscellaneous_description', JSON.stringify(currSession), false, true);

  amount = nlapiGetFieldValue('subtotal');
  // updateHandling(amount, showType);

  if (Number(showType) === 1) {
    updateHandling(amount, showType);
  } else {
    nlapiSetFieldValue('handlingcost', '', true, true);
  }

  nlapiLogExecution('DEBUG', EVENT + ' amount 2', amount);
}

/**
 * PostSourcing handler – fires after a sourced field is populated.
 * When the shipping method (shipmethod) changes, re-applies the 10%
 * handling surcharge if the order is in Show mode.
 */
function postSourcing(type, name) {
  if (type === 'item') return;
  EVENT = 'postSourcing';
  var context = nlapiGetContext();

  var executionContext = context.getExecutionContext();

  if (executionContext !== 'webstore') return;

  if (name === 'shipmethod') {
    nlapiLogExecution('DEBUG', EVENT + ' ', name);

    var amount = nlapiGetFieldValue('subtotal');
    var showType = nlapiGetFieldValue('custbody_nafco_showfx_shop_type');
    if (Number(showType) === 1) {
      updateHandling(amount);
    }
  }
}

function validateField(type, name, linenum) {
  if (type === 'item') return true;
  var context = nlapiGetContext();

  var executionContext = context.getExecutionContext();

  if (executionContext !== 'webstore') return;
  nlapiLogExecution('DEBUG', 'validateField name', name);
  return true;
}

function pageInit(mode) {
  var customform = nlapiGetFieldValue('customform');
  nlapiLogExecution('DEBUG', 'pageInit customform', customform);
  nlapiLogExecution('DEBUG', 'pageInit mode', mode);

  var context = nlapiGetContext();

  var executionContext = context.getExecutionContext();

  if (executionContext !== 'webstore') return;

  nlapiLogExecution('DEBUG', 'pageInit executionContext', executionContext);

  var currSession = context.getSessionObject('shopflow');

  nlapiLogExecution('DEBUG', 'pageInit currSession', currSession);

  if (currSession) {
    currSession = JSON.parse(currSession);
    if (currSession.saved === 'T') {
      nlapiLogExecution('DEBUG', 'pageInit restored session, skipping', '');
      var lineCount = nlapiGetLineItemCount('item');

      var daysSinceSaved = (new Date().getTime() - currSession.savedAt) / (1000 * 60 * 60 * 24);
      nlapiLogExecution('DEBUG', 'pageInit daysSinceSaved', daysSinceSaved);

      if (lineCount === 0) {
        currSession = {};
        context.setSessionObject('shopflow', JSON.stringify(currSession));
      } else if (currSession.items) {
        var itemArr = [];
        for (var i = 1; i <= lineCount; i++) {
          var item = nlapiGetLineItemValue('item', 'item', i);
          itemArr.push(item);
        }

        for (var itemId in currSession.items) {
          if (currSession.items.hasOwnProperty(itemId)) {
            if (itemArr.indexOf(itemId) === -1) {
              delete currSession.items[itemId];
            }
          }
        }
      }

      return;
    }
  }

  var showType = nlapiGetFieldValue('custbody_nafco_showfx_shop_type');

  nlapiLogExecution('DEBUG', 'pageInit showType', showType);

  var shippingMethod = nlapiGetFieldValue('shipmethod');

  nlapiLogExecution('DEBUG', 'pageInit shippingMethod', shippingMethod);

  var amount = nlapiGetFieldValue('subtotal');

  if (Number(showType) === 1) {
    updateHandling(amount);
  }
}

function updateHandling(amount) {
  var handlingCost;
  nlapiLogExecution('DEBUG', 'updateHandling', amount);

  handlingCost = amount * 0.1;
  nlapiSetFieldValue('handlingcost', handlingCost, true, true);
}


function togglePricing(showType, currSession) {
  var amount = nlapiGetFieldValue('total');
  var lineCount = nlapiGetLineItemCount('item');
  for (var i = 1; i <= lineCount; i++) {
    var qtyPerCase = nlapiGetLineItemValue('item', 'custcol_foa_qty_per_case', i);
    var item = nlapiGetLineItemValue('item', 'item', i);
    var rate = nlapiGetLineItemValue('item', 'rate', i);
    var qty = nlapiGetLineItemValue('item', 'quantity', i);
    var amt = nlapiGetLineItemValue('item', 'amount', i);
    var priceLevel = nlapiGetLineItemValue('item', 'price', i);


    var newAmt, defaultRate, defaultAmt;
    // Wholesale: multiply the default (show) rate by qtyPerCase
    if (Number(showType) === 1 && currSession && currSession.items[item] && Number(qtyPerCase)) {
      var newRate = Number(currSession.items[item].wholesaleRate) / Number(qtyPerCase);
      newRate = Number(newRate.toFixed(2));
      newAmt = Number(newRate.toFixed(2)) * Number(qty);
      nlapiLogExecution('DEBUG', EVENT + '  newRate:' + i, newRate);
      nlapiLogExecution('DEBUG', EVENT + '  newAmt:' + i, newAmt);

      nlapiSelectLineItem('item', i);
      nlapiSetCurrentLineItemValue('item', 'price', -1, true, true);
      nlapiSetCurrentLineItemValue('item', 'rate', newRate, true, true);
      nlapiSetCurrentLineItemValue('item', 'amount', newAmt, true, true);
      nlapiCommitLineItem('item');
    // Show (restore): restore the original default rate and price level
    } else if (Number(showType) !== 1 && currSession && currSession.items && currSession.items[item] && currSession.items[item].wholesalePriceLevel) {
      defaultRate = Number(currSession.items[item].wholesaleRate);
      defaultAmt = defaultRate * Number(qty);
      nlapiSelectLineItem('item', i);
      nlapiLogExecution('DEBUG', EVENT + ' resetRate:' + i, defaultRate);
      nlapiSetCurrentLineItemValue('item', 'price', currSession.items[item].wholesalePriceLevel, true, true);
      nlapiSetCurrentLineItemValue('item', 'rate', defaultRate, true, true);
      nlapiSetCurrentLineItemValue('item', 'amount', defaultAmt, true, true);
      nlapiCommitLineItem('item');
    // Store: capture the default rate for future toggling
    } else if (Number(showType) !== 1 && Number(priceLevel) > 0) {
      currSession.items[item] = {
        wholesalePriceLevel: priceLevel,
        wholesaleRate: rate,
        ts: new Date().getTime()
      };
    }
  }

  amount = nlapiGetFieldValue('total');
  nlapiLogExecution('DEBUG', EVENT + ' amount 2', amount);
}

function validateLine(type) {
  EVENT = 'validateLine';

  var context = nlapiGetContext();

  var executionContext = context.getExecutionContext();

  if (executionContext !== 'webstore') return;

  if (type === 'item') {
    var showType = nlapiGetFieldValue('custbody_nafco_showfx_shop_type');
    nlapiLogExecution('DEBUG', EVENT + '  showType', showType);
    var qtyPerCase = nlapiGetCurrentLineItemValue('item', 'custcol_foa_qty_per_case');
    var item = nlapiGetCurrentLineItemValue('item', 'item');
    var rate = nlapiGetCurrentLineItemValue('item', 'rate');
    var qty = nlapiGetCurrentLineItemValue('item', 'quantity');
    var amt = nlapiGetCurrentLineItemValue('item', 'amount');
    var priceLevel = nlapiGetCurrentLineItemValue('item', 'price');
    nlapiLogExecution('DEBUG', EVENT + '  qtyPerCase', qtyPerCase);
    nlapiLogExecution('DEBUG', EVENT + '  rate', rate);
    nlapiLogExecution('DEBUG', EVENT + '  qty', qty);
    nlapiLogExecution('DEBUG', EVENT + '  amt', amt);
    nlapiLogExecution('DEBUG', EVENT + '  priceLevel', priceLevel);
    var currSession = nlapiGetContext().getSessionObject('shopflow');
    if (currSession) {
      currSession = JSON.parse(currSession);
    } else {
      currSession = { items: {}, saved: 'F', savedAt: null };
    }

    if (Number(priceLevel) > 0) {
      if (!currSession.items[item]) {
        currSession.items[item] = {
          wholesalePriceLevel: priceLevel,
          wholesaleRate: rate,
          ts: new Date().getTime()
        };
      }

      nlapiGetContext().setSessionObject('shopflow', JSON.stringify(currSession));
    }

    // Wholesale: multiply the default (show) rate by qtyPerCase on line commit
    if (Number(showType) === 1 && rate && Number(qtyPerCase) && currSession && currSession.items[item] && Number(priceLevel) > 0) {
      var newRate = Number(currSession.items[item].wholesaleRate) / Number(qtyPerCase);
      newRate = Number(newRate.toFixed(2));
      var newAmt = Number(newRate.toFixed(2)) * Number(qty);
      nlapiSetCurrentLineItemValue('item', 'price', -1, true, true);
      nlapiSetCurrentLineItemValue('item', 'rate', newRate, true, true);
      nlapiSetCurrentLineItemValue('item', 'amount', newAmt, true, true);
    }
  }
  return true;
}