Script handles linking prescription to line records/Auto-Ship (custom record) both with/without SO reference upon approval of prescription record(custom record); Similarly to Sales Order item Lines.
/**
* @NApiVersion 2.x
* @NScriptType UserEventScript
* @NModuleScope SameAccount
*/
define(['N/record', 'N/search', 'N/url', 'N/https'],
/**
* @param {record} record
*/
function (record, search, url, https) {
/**
* Function definition to be triggered before record is loaded.
* @param {Object} context
* @param {Record} context.newRecord - New record
* @param {Record} context.oldRecord - Old record
* @param {string} context.type - Trigger type
* @Since 2015.2
*/
const _AUTOSHIP_LINE_RECORD = "customrecord_vv_autoship_record";
const _PRESCRIPTION_RECORD = "customrecord_vv_prescription";
const _SHIPMENT_ITEM_RECORD = "customrecord_vv_shipment_item";
const SCRIPTID_CREATE_SHIP = 'customscript_vv_sl_create_shipment';
const DEPLOYID_CREATE_SHIP = 'customdeploy_vv_sl_create_shipment';
/* SHIPMENT ITEM RECORD RECORD FIELDS */
const _SPI_SO_LINE_KEY = "custrecord_vv_ship_item_line_key"
const _SPI_SO_PARENT_SHIPMENT = "custrecord_vv_shipment";
/* SHIPMENT ITEM RECORD RECORD FIELDS */
/* SO RECORD FIELDS */
const PENDING_PRESCRIPTION = 1;
const _SO_ITEM_TYPE = "itemtype";
const _SO_LINE_UNIQUE_KEY = "lineuniquekey";
const _SO_COMMITINVENTORY = "commitinventory"
const _SO_PRESCRIPTION = "custcol_vv_so_prescription";
const _SO_DATE_PRESC_LINKED = "custcol_vv_ue_date_linked";
const _SO_IS_CLOSED = "isclosed";
const _SO_IS_RX_ITEM = "custcol_vv_is_rx_item";
const _SO_RX_HOLD = 'custbody_rxhold';
/* SO RECORD FIELDS */
/* AUTOSHIP CUSTOM RECORD FIELDS */
const _AS_ITEM = "custrecord_vv_autoship_item"
const _AS_SO_REFERENCE = "custrecord_vv_autoship_soref"
const _AS_PET = "custrecord_vv_autoship_pet"
const _AS_PRESCRIPTION = "custrecord_vv_autoship_prescription"
const _AS_LINE_UNIQUE_KEY = "custrecord_vv_autoship_line_unique_key";
const _AS_CUSTOMER_SRC = "custrecord_vv_autoship_customer_src";
/* CUSTOM RECORD FIELDS */
/* PRESCRIPTION RECORD FIELDS AND PRESCRIPTION ITEM RECORD FIELDS OBJ */
const _APPROVED = "2";
const _PR_STATUS = "custrecord_vv_prescription_status";
const _PRESCRIPTION = {
itemName: "custrecord_vv_item_name",
prId: "custrecord_vv_prescription_id",
refillQty: "custrecord_vv_refill_quantity",
autoshipQty: "custrecord_vv_autoship_quantity",
pet: "custrecord_vv_pet",
customer: "custrecord_vv_customer"
}
/* PRESCRIPTION AND PRESCRIPTION ITEM RECORD FIELDS OBJ */
function afterSubmit(context) {
try {
if (context.type === context.UserEventType.EDIT || context.type === context.UserEventType.XEDIT) {
var strOldRxStatus = context.oldRecord.getValue({fieldId: _PR_STATUS})
var recPrescription = record.load({type: _PRESCRIPTION_RECORD, id: context.newRecord.id});
var strNewRxStatus = recPrescription.getValue({fieldId: _PR_STATUS});
if (strOldRxStatus !== strNewRxStatus && strNewRxStatus === _APPROVED) {
var objPrescriptionData = searchItemsUnderPrescription(recPrescription.id);
log.debug("objPrescriptionData", JSON.stringify(objPrescriptionData))
//need to validate if there are items on this as we will omit the item if refillquantity = 0;
var prDataObjItems = objPrescriptionData.items
if (prDataObjItems.length) {
var objAutoShip = searchAutoShipLinesWithoutPrescription(prDataObjItems, objPrescriptionData.customer, objPrescriptionData.pet);
log.debug("objAutoShip", objAutoShip)
var prDataObjItemsQtyMap = objPrescriptionData.itemsqtymap
if (Object.keys(objAutoShip).length && prDataObjItemsQtyMap.length) {
var arrAutoShipPrescriptionMap = [];
var objSalesOrderMap = {};
for (var key in objAutoShip) {
var strAutoShipLineId = key;
var strItem = objAutoShip[key].item;
var strSalesOrderId = objAutoShip[key].salesorder;
var strLineUniqueKey = objAutoShip[key].lineuniquekey;
var flQuantity = parseFloat(objAutoShip[key].quantity);
var numObjIndex = findAttributeIndex(prDataObjItemsQtyMap, "item", strItem);
var strRefillQty = prDataObjItemsQtyMap[numObjIndex].refillquantity
if (numObjIndex >= 0 && strRefillQty >= flQuantity) {
strRefillQty -= flQuantity
arrAutoShipPrescriptionMap.push(strAutoShipLineId);
if (strSalesOrderId) {
if (!objSalesOrderMap.hasOwnProperty(strSalesOrderId)) {
objSalesOrderMap[strSalesOrderId] = [];
}
objSalesOrderMap[strSalesOrderId].push(strLineUniqueKey);
}
}
}
log.debug("arrAutoShipPrescriptionMap", arrAutoShipPrescriptionMap)
for (var itr = 0; itr < arrAutoShipPrescriptionMap.length; itr++) {
try {
record.submitFields({
type: _AUTOSHIP_LINE_RECORD,
id: arrAutoShipPrescriptionMap[itr],
values: {custrecord_vv_autoship_prescription: recPrescription.id},
options: {ignoreMandatoryFields: true}
})
} catch (e) {
record.submitFields({
type: _AUTOSHIP_LINE_RECORD,
id: arrAutoShipPrescriptionMap[itr],
values: {custrecord_vv_autoship_prescription: recPrescription.id},
options: {ignoreMandatoryFields: true}
})
}
}
log.debug("objSalesOrderMap", JSON.stringify(objSalesOrderMap))
var updateShipmentRecordsArr = [];
if (Object.keys(objSalesOrderMap).length) {
for (var key in objSalesOrderMap) {
try {
var strNewSOId = null
var noPrescription = false;
var recSalesOrder = record.load({
type: record.Type.SALES_ORDER,
id: key
});
var lineCount = recSalesOrder.getLineCount({sublistId: 'item'})
var objSalesOrderMapVal = objSalesOrderMap[key]
for (var ctr = 0; ctr < objSalesOrderMapVal.length; ctr++) {
var intLine = recSalesOrder.findSublistLineWithValue({
sublistId: "item",
fieldId: _SO_LINE_UNIQUE_KEY,
value: objSalesOrderMapVal[ctr]
});
if (intLine >= 0) {
recSalesOrder.setSublistValue({
sublistId: "item",
fieldId: _SO_PRESCRIPTION,
line: intLine,
value: recPrescription.id
});
recSalesOrder.setSublistValue({
sublistId: "item",
fieldId: _SO_DATE_PRESC_LINKED,
line: intLine,
value: new Date()
});
recSalesOrder.setSublistValue({
sublistId: "item",
fieldId: _SO_COMMITINVENTORY,
line: intLine,
value: 1
});
updateShipmentRecordsArr.push(objSalesOrderMapVal[ctr]);
}
}
for (var i = 0; i < lineCount; i++) {
var itemtype = recSalesOrder.getSublistValue({
sublistId: 'item',
fieldId: _SO_ITEM_TYPE,
line: i
});
var boolRXItem = recSalesOrder.getSublistValue({
sublistId: "item",
fieldId: _SO_IS_RX_ITEM,
line: i
});
var commit = recSalesOrder.getSublistValue({
sublistId: 'item',
fieldId: _SO_COMMITINVENTORY,
line: i
});
var isLineClosed = recSalesOrder.getSublistValue({
sublistId: 'item',
fieldId: _SO_IS_CLOSED,
line: i
});
var prescription = recSalesOrder.getSublistValue({
sublistId: "item",
fieldId: _SO_PRESCRIPTION,
line: i
});
if (itemtype === 'InvtPart') {
if (
(boolRXItem === true || boolRXItem === 'T')
&& (prescription === null || prescription === '')
&& commit === '1'
&& (isLineClosed === false || isLineClosed === 'F')
) {
noPrescription = true;
}
}
}
log.debug("No Prescription", noPrescription)
if (noPrescription) {
recSalesOrder.setValue({
fieldId: _SO_RX_HOLD,
value: PENDING_PRESCRIPTION,
});
log.debug('RX HOLD is set to', PENDING_PRESCRIPTION);
} else {
recSalesOrder.setValue({
fieldId: _SO_RX_HOLD,
value: "",
});
}
strNewSOId = recSalesOrder.save({
enableSourcing: false,
ignoreMandatoryFields: true
});
log.debug("SO SAVED - " + strNewSOId)
} catch (e) {
log.error("ERROR SAVING SO - " + recSalesOrder.id, e)
}
}
}
// Added 5/14/21 Update for Prescription Holds
if (updateShipmentRecordsArr.length > 0) {
updateShipmentRecords(updateShipmentRecordsArr, "test");
}
}
}
}
}
} catch (err) {
log.error("ERR", err)
}
}
function updateShipmentRecords(soLineKeysArr, soId) {
log.debug("updateShipmentRecords ENTRY", soLineKeysArr)
var searchFiltersArr = [];
var shipmentRecArr = [];
var shipmentRecObj = {};
for (var x = 0; x < soLineKeysArr.length; x++) {
searchFiltersArr.push([_SPI_SO_LINE_KEY, "is", soLineKeysArr[x]]);
if (x < soLineKeysArr.length - 1) {
searchFiltersArr.push("OR");
}
}
var shipmentRecordBySOLine = search.create({
type: _SHIPMENT_ITEM_RECORD,
filters: searchFiltersArr,
columns:
[
search.createColumn({
name: _SPI_SO_PARENT_SHIPMENT,
summary: "GROUP",
label: "Parent Shipment"
})
]
});
shipmentRecordBySOLine.run().each(function (result) {
var parentShipment = result.getValue({
name: _SPI_SO_PARENT_SHIPMENT,
summary: "GROUP",
})
shipmentRecArr.push(parentShipment);
shipmentRecObj[parentShipment] = soId;
return true;
});
if (shipmentRecArr.length > 0) {
log.debug("Pass to SL Create Shipment (clearSyncFields)", shipmentRecArr);
var urlSuitelet = url.resolveScript({
scriptId: SCRIPTID_CREATE_SHIP,
deploymentId: DEPLOYID_CREATE_SHIP,
returnExternalUrl: true,
params: {
custpage_presc_hold_update: true,
custpage_presc_hold_obj: JSON.stringify(shipmentRecObj)
}
});
var response = https.get({
url: urlSuitelet
});
}
}
function searchItemsUnderPrescription(strPrescriptionId) {
var objSearchItems = search.create({
type: _PRESCRIPTION_RECORD,
filters: [
["internalid", "anyof", strPrescriptionId]
],
columns: [
search.createColumn({
name: _PRESCRIPTION.customer,
summary: "GROUP",
label: "Customer"
}),
search.createColumn({
name: _PRESCRIPTION.itemName,
join: _PRESCRIPTION.prId,
summary: "GROUP",
label: "Item Name"
}),
search.createColumn({
name: _PRESCRIPTION.refillQty,
join: _PRESCRIPTION.prId,
summary: "SUM",
label: "Quantity"
}),
search.createColumn({
name: _PRESCRIPTION.pet,
summary: "GROUP",
label: "Quantity"
})
]
});
var obj = {};
obj["prescriptionid"] = strPrescriptionId;
obj["items"] = []
obj["itemsqtymap"] = [];
objSearchItems.run().each(function (res) {
var numRefillQty = res.getValue({
name: _PRESCRIPTION.refillQty,
join: _PRESCRIPTION.prId,
summary: "SUM"
})
var strItemName = res.getValue({
name: _PRESCRIPTION.itemName,
join: _PRESCRIPTION.prId,
summary: "GROUP"
})
var strCustomer = res.getValue({name: _PRESCRIPTION.customer, summary: "GROUP"})
var strPet = res.getValue({name: _PRESCRIPTION.pet, summary: "GROUP"})
obj["itemsqtymap"].push({
refillquantity: numRefillQty !== "" ? parseFloat(numRefillQty) : 0,
item: strItemName
})
obj["items"].push(strItemName)
obj["customer"] = strCustomer
obj["pet"] = strPet
return true;
});
//we also look into inactive records as it might've been applied to a previous autoship
var objAutoShipLineSearch = search.create({
type: _AUTOSHIP_LINE_RECORD,
filters: [
[_AS_PRESCRIPTION, "anyof", obj.prescriptionid],
"AND",
[_AS_ITEM, "anyof", obj.items]
],
columns: [
search.createColumn({name: _PRESCRIPTION.autoshipQty, summary: "SUM"}),
search.createColumn({name: _AS_ITEM, summary: "GROUP"})
]
});
objAutoShipLineSearch.run().each(function (res) {
var strItem = res.getValue({name: _AS_ITEM, summary: "GROUP"});
var flQuantity = res.getValue({name: _PRESCRIPTION.autoshipQty, summary: "SUM"});
var numObjIndex = findAttributeIndex(obj["itemsqtymap"], "item", strItem);
if (numObjIndex >= 0) {
obj["itemsqtymap"][numObjIndex].refillquantity -= parseFloat(flQuantity);
if (obj["itemsqtymap"][numObjIndex].refillquantity <= 0) {
//remove item to lessen search results when looking for items autoship lines w/o prescription
var itemIndex = obj["items"].indexOf(strItem);
if (itemIndex >= 0) {
obj["items"].splice(itemIndex, 1)
}
//remove the mapping since we can no longer use this for autoship lines w/o prescription
obj["itemsqtymap"].splice(numObjIndex, 1);
}
}
return true;
});
return obj;
}
//only get autoship line record that contains a sales order so that future autoship orders are not considered
//prescription are assigned differently for future autoship
function searchAutoShipLinesWithoutPrescription(arrItems, strCustomerId, strPet) {
var objSearchAutoShipLines = search.create({
type: _AUTOSHIP_LINE_RECORD,
filters: [
[_AS_PRESCRIPTION, "anyof", "@NONE@"],
"AND",
[_AS_ITEM, "anyof", arrItems],
"AND",
[_AS_CUSTOMER_SRC, "anyof", strCustomerId],
"AND",
[_AS_PET, "anyof", strPet],
"AND",
["isinactive", "is", "F"]
],
columns: [
search.createColumn({name: "internalid", label: "Internal ID"}),
search.createColumn({name: _AS_LINE_UNIQUE_KEY, label: "Line Unique Key"}),
search.createColumn({name: _AS_SO_REFERENCE, label: "SO#"}),
search.createColumn({name: _AS_ITEM, label: "Item"}),
search.createColumn({name: _PRESCRIPTION.autoshipQty, label: "Qty"})
]
});
var obj = {};
objSearchAutoShipLines.run().each(function (res) {
obj[res.getValue({name: "internalid"})] = {
item: res.getValue({name: _AS_ITEM}),
quantity: res.getValue({name: _PRESCRIPTION.autoshipQty}),
lineuniquekey: res.getValue({name: _AS_LINE_UNIQUE_KEY}),
salesorder: res.getValue({name: _AS_SO_REFERENCE}),
};
return true;
});
return obj;
}
function findAttributeIndex(array, attr, value) {
for (var i = 0; i < array.length; i += 1) {
if (array[i][attr] === value) {
return i;
}
}
return -1;
}
return {
afterSubmit: afterSubmit
}
}
);