/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
/* *MARUN-164 Custom Pricing management and synchronization**
*
*
* **********************************************************************************************
*
* Author: Jobin and Jismi IT Services
*
* Date Created : 25 November 2024
* Created By: Akshay B Nair, Jobin and Jismi IT Services
* Production movement:
*
* Description : to populate the custom pricing in the standard Item pricing list
*
* REVISION HISTORY
*
*
*
***********************************************************************************************/
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/record', 'N/log', 'N/ui/serverWidget', 'N/search'], (record, log, serverWidget, search) => {
function getItemList(subsidiary) {
try {
let itemArray = []
let itemSearchObj = search.create({
type: "item",
filters:
[
["type", "anyof", "InvtPart", "NonInvtPart", "OthCharge", "Service"],
"AND",
["subsidiary", "is", subsidiary],
"AND",
["isinactive", "is", "F"],
"AND",
["subtype", "anyof", "Resale", "Sale", "@NONE@"]
],
columns:
[
search.createColumn({ name: "itemid", label: "Name" }),
search.createColumn({ name: "internalid", label: "Internal ID" }),
search.createColumn({ name: "displayname", label: "Display Name" }),
search.createColumn({ name: "salesdescription", label: "Description" }),
search.createColumn({ name: "type", label: "Type" }),
search.createColumn({ name: "baseprice", label: "Base Price" }),
]
});
let searchResultCount = itemSearchObj.runPaged().count;
log.debug("itemSearchObj result count", searchResultCount);
itemSearchObj.run().each(function (result) {
itemArray.push({
itemId: result.getValue({ name: "internalid", label: "Internal ID" }),
itemName: result.getValue({ name: "itemid", label: "Name" })
})
// .run().each has a limit of 4,000 results
return true;
});
return itemArray
}
catch (e) {
log.error('error @GetItemList', e)
}
}
function getNewCustomLineData(customerRecord, sublistId, lineCount) {
try {
let newCustomPricingRecords = [];
for (let i = 0; i < lineCount; i++) {
// Get the values from each line in the custom pricing sublist
let currency = customerRecord.getSublistValue({
sublistId: sublistId,
fieldId: 'custrecord_jj_pricelevel_currency', // Replace with actual field ID
line: i
});
let priceLevel = customerRecord.getSublistValue({
sublistId: sublistId,
fieldId: 'custrecord_jj_pricelevel_pricelevel', // Replace with actual field ID
line: i
});
let item = customerRecord.getSublistValue({
sublistId: sublistId,
fieldId: 'custrecord_jj_pricelevel_item', // Replace with actual field ID
line: i
});
let unitPrice = customerRecord.getSublistValue({
sublistId: sublistId,
fieldId: 'custrecord_jj_pricelevel_unit_price', // Replace with actual field ID
line: i
});
// Perform your custom logic here for each custom pricing record
log.debug('Custom Pricing Record', 'Currency: ' + currency + ', Price Level: ' + priceLevel + ', Item: ' + item + ', Unit Price: ' + unitPrice);
let lineData = {
lineId: item + '_' + currency, // Unique identifier based on line number (1-indexed)
currency: currency,
priceLevel: priceLevel,
item: item,
unitPrice: unitPrice
};
// Add the object to the array
newCustomPricingRecords.push(lineData)
}
return newCustomPricingRecords;
}
catch (e) {
log.error('error @getNewCustomLineData', e)
}
}
// Loop through the custom pricing records and perform logic
function getOldCustomLineData(oldRecord, sublistId, oldLineCount) {
try {
let oldCustomPricingRecords = [];
for (let i = 0; i < oldLineCount; i++) {
// Get the values from each line in the custom pricing sublist
let currency = oldRecord.getSublistValue({
sublistId: sublistId,
fieldId: 'custrecord_jj_pricelevel_currency', // Replace with actual field ID
line: i
});
let priceLevel = oldRecord.getSublistValue({
sublistId: sublistId,
fieldId: 'custrecord_jj_pricelevel_pricelevel', // Replace with actual field ID
line: i
});
let item = oldRecord.getSublistValue({
sublistId: sublistId,
fieldId: 'custrecord_jj_pricelevel_item', // Replace with actual field ID
line: i
});
let unitPrice = oldRecord.getSublistValue({
sublistId: sublistId,
fieldId: 'custrecord_jj_pricelevel_unit_price', // Replace with actual field ID
line: i
});
// Perform your custom logic here for each custom pricing record
log.debug('Custom Pricing Record Old', 'Currency: ' + currency + ', Price Level: ' + priceLevel + ', Item: ' + item + ', Unit Price: ' + unitPrice);
let oldlineData = {
lineId: item + '_' + currency,
currency: currency,
priceLevel: priceLevel,
item: item,
unitPrice: unitPrice
};
oldCustomPricingRecords.push(oldlineData)
}
return oldCustomPricingRecords;
// Example of validation or processing logic
}
catch (e) {
log.error('error@getOldCustomLineData', e)
}
}
function getItemPricingLines(customerRecord) {
try {
let itemsublistId = 'itempricing'
let itemPricinglineCount = customerRecord.getLineCount({
sublistId: itemsublistId
})
let itemPricingRecords = [];
// Loop through the custom pricing records and perform logic
for (let i = 0; i < itemPricinglineCount; i++) {
// Get the values from each line in the custom pricing sublist
let currency = customerRecord.getSublistValue({
sublistId: itemsublistId,
fieldId: 'currency', // Replace with actual field ID
line: i
});
let priceLevel = customerRecord.getSublistValue({
sublistId: itemsublistId,
fieldId: 'level', // Replace with actual field ID
line: i
});
let item = customerRecord.getSublistValue({
sublistId: itemsublistId,
fieldId: 'item', // Replace with actual field ID
line: i
});
let unitPrice = customerRecord.getSublistValue({
sublistId: itemsublistId,
fieldId: 'price', // Replace with actual field ID
line: i
});
// Perform your custom logic here for each custom pricing record
log.debug('Item Pricing Record ', 'Currency: ' + currency + ', Price Level: ' + priceLevel + ', Item: ' + item + ', Unit Price: ' + unitPrice);
let lineData = {
lineIndex: i,
lineId: item + '_' + currency, // Unique identifier based on line number (1-indexed)
currency: currency,
priceLevel: priceLevel,
item: item,
unitPrice: unitPrice
};
itemPricingRecords.push(lineData)
// Example of validation or processing logic
}
return itemPricingRecords;
}
catch (e) {
log.error('error @getLineData', e)
}
}
function getcomparedCustomData(getNewCustomLineDetails, getOldCustomLineDetails, getItemPricingDetails) {
try {
// Identify new lines (lineIds present in `getNewCustomLineDetails` but not in `getOldCustomLineDetails`)
let newLines = getNewCustomLineDetails.filter(newLine =>
!getOldCustomLineDetails.some(oldLine => oldLine.lineId === newLine.lineId)
);
log.debug('New Lines:', newLines);
// Copy of `getItemPricingDetails` to be updated
let updatedItemPricingDetails = [...getItemPricingDetails];
// Iterate over new lines and check for updates
newLines.forEach(newLine => {
// Check if the `lineId` exists in `getItemPricingDetails`
let existingLineIndex = updatedItemPricingDetails.findIndex(
existingLine => existingLine.lineId === newLine.lineId
);
if (existingLineIndex > -1) {
// If `lineId` exists, compare unit prices
let existingLine = updatedItemPricingDetails[existingLineIndex];
if (existingLine.unitPrice !== newLine.unitPrice) {
log.debug(`Updating unit price for lineId: ${newLine.lineId}`, {
oldUnitPrice: existingLine.unitPrice,
newUnitPrice: newLine.unitPrice,
});
// Update the unit price in the existing line
updatedItemPricingDetails[existingLineIndex].unitPrice = newLine.unitPrice;
}
} else {
// If `lineId` does not exist, add it as a new line
let newLineToAdd = {
lineIndex: updatedItemPricingDetails.length, // Set index to the next available index
lineId: newLine.lineId,
currency: newLine.currency,
priceLevel: '-1', // Custom price level
item: newLine.item,
unitPrice: newLine.unitPrice,
};
updatedItemPricingDetails.push(newLineToAdd);
}
});
return updatedItemPricingDetails;
} catch (e) {
log.error('Error @getcomparedCustomData:', e);
// Return an empty array in case of error
}
}
function toGetRemovalItemId(getOldCustomLineDetails, getNewCustomLineDetails, getItemPricingDetails) {
try {
let removedLines = getOldCustomLineDetails.filter(oldLine =>
!getNewCustomLineDetails.some(newLine => newLine.lineId === oldLine.lineId)
);
log.debug('Removed Lines:', removedLines);
let removalLines = {};
removedLines.forEach(removedLine => {
let matchingLine = getItemPricingDetails.find(item => item.lineId === removedLine.lineId);
if (matchingLine) {
removalLines[removedLine.lineId] = matchingLine; // Store the matching line object in the `removalLines` object
}
});
log.debug('removalLines inside', removalLines)
return removalLines
}
catch (e) {
log.error('error @toGetRemovalItemId')
}
}
function togetCustomExistingItem(newCustomLineDetails) {
try {
// Initialize duplicate flag
let isError = false;
let uniqueLineIds = new Set();
// Check for duplicates within newCustomLineDetails
newCustomLineDetails.forEach((newLine) => {
if (uniqueLineIds.has(newLine.lineId)) {
isError = true;
log.error('Duplicate Detected in newCustomLineDetails', `Line ID ${newLine.lineId} is duplicated within newCustomLineDetails.`);
} else {
uniqueLineIds.add(newLine.lineId);
}
});
return isError;
} catch (e) {
log.error('Error @togetCustomExistingItem', e);
return false
}
}
function toSetVirtualField(customerRecord) {
try {
let sublistId = 'recmachcustrecord_jj_pricelevel_customer'; // Sublist ID
let lineCount = customerRecord.getLineCount({ sublistId });
let virtualLineData = [];
for (let i = 0; i < lineCount; i++) {
// Get the virtual field value (custom item)
let customItemValue = customerRecord.getSublistValue({
sublistId,
fieldId: 'custpage_custom_items', // Virtual field ID
line: i
});
// Log the custom field value for debugging
log.debug(`Line ${i}: Custom Item Value`, customItemValue);
// Set the retrieved custom item value to the 'custrecord_jj_pricelevel_item' field
if (customItemValue) {
customerRecord.setSublistValue({
sublistId,
fieldId: 'custrecord_jj_pricelevel_item', // Field to set
line: i,
value: customItemValue
});
// Collect data for debugging
virtualLineData.push({
line: i,
customItem: customItemValue,
updatedField: 'custrecord_jj_pricelevel_item'
});
}
}
// Log all updated virtual line data
log.debug('Virtual Line Data Updated', virtualLineData);
} catch (e) {
log.error('Error @toSetVirtualField', e);
}
}
function beforeLoad(scriptContext) {
try {
if (scriptContext.type === scriptContext.UserEventType.CREATE || scriptContext.type === scriptContext.UserEventType.EDIT) {
let recordObj = scriptContext.newRecord;
let form = scriptContext.form;
let itemPricingSublist = form.getSublist({
id: 'recmachcustrecord_jj_pricelevel_customer'
})
let standardField = itemPricingSublist.getField({
id: 'custrecord_jj_pricelevel_item'
});
standardField.updateDisplayType({
displayType: serverWidget.FieldDisplayType.HIDDEN
});
let customItemField = itemPricingSublist.addField({
id: 'custpage_custom_items',
type: serverWidget.FieldType.SELECT,
label: 'Item'
})
itemPricingSublist.insertField({
field: customItemField,
nextfield: 'custrecord_jj_pricelevel_pricelevel'
});
customItemField.isMandatory = true;
let subsidiary = recordObj.getValue({
fieldId: 'subsidiary'
})
if (subsidiary) {
log.debug('subsidiary', subsidiary)
// Ensure the custom field appears after the `custrecord_jj_pricelevel_pricelevel`
let itemDetailList = getItemList(subsidiary);
//log.debug('itemDetailList', itemDetailList)
customItemField.addSelectOption({ value: '', text: '' }); // Default option
itemDetailList.forEach((item) => {
customItemField.addSelectOption({
value: item.itemId,
text: item.itemName
});
});
}
else {
log.debug('the subsidiary is not available in customer creation')
}
let lineCount = recordObj.getLineCount({ sublistId: 'recmachcustrecord_jj_pricelevel_customer' });
for (let i = 0; i < lineCount; i++) {
let existingItem = recordObj.getSublistValue({
sublistId: 'recmachcustrecord_jj_pricelevel_customer',
fieldId: 'custrecord_jj_pricelevel_item', // Field ID for the existing item
line: i
})
// Set the custom field value based on the existing item
itemPricingSublist.setSublistValue({
id: 'custpage_custom_items',
line: i,
value: existingItem || '' // Default to blank if no existing item
});
}
}
// Only add the field in edit mode
if (scriptContext.type === scriptContext.UserEventType.VIEW || scriptContext.type === scriptContext.UserEventType.EDIT) {
let hideFld = scriptContext.form.addField({
id: 'custpage_hide_buttons',
label: 'not shown - hidden',
type: serverWidget.FieldType.INLINEHTML
});
let scr = 'jQuery("#newrecrecmachcustrecord_jj_pricelevel_customer").hide(); jQuery("#newrec626").hide();';
hideFld.defaultValue = `<script>jQuery(function($){require([], function(){${scr};})})</script>`;
}
} catch (e) {
log.error('error@beforeLoad', e);
}
}
/**
* beforeSubmit script to handle custom pricing and item pricing logic.
*/
function beforeSubmit(scriptContext) {
let isError = false;
let errorMsg = 'The item must be unique';
try {
// Define error message and initialize variables
// Validate scriptContext and ensure newRecord exists
let customerRecord = scriptContext.newRecord;
let oldRecord = scriptContext.oldRecord || {}; // Handle null oldRecord gracefully
let customPricingSublistId = 'recmachcustrecord_jj_pricelevel_customer'; // Replace with actual sublist ID
let itemPricingSublistId = 'itempricing'; // Sublist ID for item pricing
// Get the number of custom pricing records
let newLineCount = customerRecord.getLineCount({ sublistId: customPricingSublistId });
let oldLineCount = oldRecord.getLineCount
? oldRecord.getLineCount({ sublistId: customPricingSublistId })
: 0; // Default to 0 if oldRecord is missing
log.debug('Custom Pricing Record Count', { newLineCount, oldLineCount });
// Process custom pricing lines
toSetVirtualField(customerRecord);
let newCustomLineDetails = getNewCustomLineData(customerRecord, customPricingSublistId, newLineCount);
let oldCustomLineDetails = getOldCustomLineData(oldRecord, customPricingSublistId, oldLineCount);
let itemPricingDetails = getItemPricingLines(customerRecord);
log.debug('New Custom Line Details', newCustomLineDetails);
log.debug('Old Custom Line Details', oldCustomLineDetails);
log.debug('Item Pricing Details', itemPricingDetails);
// Check for errors in custom data
isError = togetCustomExistingItem(newCustomLineDetails);
// Identify lines to remove
let removalItemIdDetails = toGetRemovalItemId(oldCustomLineDetails, newCustomLineDetails, itemPricingDetails);
let removalLineIds = Object.keys(removalItemIdDetails);
log.debug('Removal Item ID Details', removalItemIdDetails);
log.debug('Removal Line IDs', removalLineIds);
// Remove matching lines from the item pricing sublist
let itemPricingLineCount = itemPricingDetails.length;
for (let i = itemPricingLineCount - 1; i >= 0; i--) {
let lineId = itemPricingDetails[i].lineId;
if (removalLineIds.includes(lineId)) {
log.debug('Removing Line', { lineIndex: i, lineId });
customerRecord.removeLine({ sublistId: itemPricingSublistId, line: i });
}
}
// Compare and update or add new lines
let updatedItemPricingDetails = getcomparedCustomData(
newCustomLineDetails,
oldCustomLineDetails,
itemPricingDetails
);
log.debug('Updated Item Pricing Details', updatedItemPricingDetails);
newCustomLineDetails.forEach((detail) => {
let existingLineIndex = itemPricingDetails.findIndex(
(line) => line.lineId === detail.lineId
);
if (existingLineIndex > -1) {
// Update existing line if the unit price has changed
let existingLine = itemPricingDetails[existingLineIndex];
if (existingLine.unitPrice !== detail.unitPrice) {
log.debug(`Updating existing line with lineId: ${detail.lineId}`, {
oldUnitPrice: existingLine.unitPrice,
newUnitPrice: detail.unitPrice,
});
customerRecord.setSublistValue({
sublistId: itemPricingSublistId,
fieldId: 'price', // Replace with actual field ID for unit price
line: existingLineIndex,
value: detail.unitPrice,
});
}
} else {
// Add a new line if the lineId does not exist
let lineIndex = customerRecord.getLineCount({ sublistId: itemPricingSublistId });
log.debug('Adding New Line', { lineIndex, detail });
customerRecord.setSublistValue({
sublistId: itemPricingSublistId,
fieldId: 'item', // Replace with actual field ID for item
line: lineIndex,
value: detail.item,
});
customerRecord.setSublistValue({
sublistId: itemPricingSublistId,
fieldId: 'level', // Replace with actual field ID for price level
line: lineIndex,
value: '-1', // Custom price level
});
customerRecord.setSublistValue({
sublistId: itemPricingSublistId,
fieldId: 'currency', // Replace with actual field ID for currency
line: lineIndex,
value: detail.currency,
});
customerRecord.setSublistValue({
sublistId: itemPricingSublistId,
fieldId: 'price', // Replace with actual field ID for unit price
line: lineIndex,
value: detail.unitPrice,
});
}
});
} catch (e) {
log.error('Error @beforeSubmit', e);
}
if (isError === true) {
throw errorMsg
}
}
return {
beforeLoad: beforeLoad,
beforeSubmit: beforeSubmit,
};
});