A map reduce script for auto populate the body level location in the invoice record from the line one of related item fulfillment record’s line level location.
/**
* @NApiVersion 2.1
* @NScriptType MapReduceScript
*/
define([‘N/record’, ‘N/runtime’, ‘N/search’],
/**
* @param{record} record
* @param{runtime} runtime
* @param{search} search
*/
(record, runtime, search) => {
/**
* @description Retrieves the location from the first line of the specified item fulfillment record.
* @param {string} itemFulfillmentId – The internal ID of the item fulfillment record.
* @returns {string|null} The internal ID of the location from the first line of the item fulfillment record, or null if not found.
*/
const getItemFulfillmentLocation = (itemFulfillmentId) => {
let location;
let itemFulfillmentSearchObj = search.create({
type: “itemfulfillment”,
filters: [
[“internalid”, “anyof”, itemFulfillmentId]
],
columns: [
search.createColumn({
name: “internalid”,
summary: “GROUP”,
label: “Internal ID”
}),
search.createColumn({
name: “location”,
summary: “GROUP”,
label: “Location”
})
]
});
itemFulfillmentSearchObj.run().each(function (result) {
location = result.getValue({
name: “location”,
summary: “GROUP”,
label: “Location”
});
return false;
});
return location;
};
/**
* @description Retrieves the internal ID of an invoice record given its document number.
* @param {string} invoiceDocumentNumber – The document number of the invoice.
* @returns {string|null} The internal ID of the invoice, or null if not found.
*/
const getInvoiceInternalId = (invoiceDocumentNumber) => {
let invoiceId;
let invoiceSearchObj = search.create({
type: “invoice”,
filters: [
[“tranid”, “is”, invoiceDocumentNumber]
],
columns: [
search.createColumn({
name: “internalid”,
label: “Internal ID”
})
]
});
invoiceSearchObj.run().each(function (result) {
invoiceId = result.getValue({
name: “internalid”,
label: “Internal ID”
});
return false;
});
return invoiceId;
};
/**
* Defines the function that is executed at the beginning of the map/reduce process and generates the input data.
* @param {Object} inputContext
* @param {boolean} inputContext.isRestarted – Indicates whether the current invocation of this function is the first
* invocation (if true, the current invocation is not the first invocation and this function has been restarted)
* @param {Object} inputContext.ObjectRef – Object that references the input data
* @typedef {Object} ObjectRef
* @property {string|number} ObjectRef.id – Internal ID of the record instance that contains the input data
* @property {string} ObjectRef.type – Type of the record instance that contains the input data
* @returns {Array|Object|Search|ObjectRef|File|Query} The input data to use in the map/reduce process
* @since 2015.2
*/
const getInputData = (inputContext) => {
try {
let searchResultCount, invoiceInternalId, invoiceRef, locationInvoice;
var itemfulfillmentSearchObj = search.create({
type: “itemfulfillment”,
filters:
[
[“type”, “anyof”, “ItemShip”],
“AND”,
[“subsidiary”, “anyof”, “3”],
“AND”,
[“status”, “anyof”, “ItemShip:C”],
“AND”,
[“mainline”, “is”, “T”],
“AND”,
[“custbody_jj_ee_invoice_reference”, “noneof”, “@NONE@”],
“AND”,
[“internalid”, “is”, “48647”]
],
columns:
[
search.createColumn({
name: “internalid”,
summary: “GROUP”,
label: “Internal ID”
}),
search.createColumn({
name: “custbody_jj_ee_invoice_reference”,
summary: “MAX”,
label: “Invoice ref #”
}),
search.createColumn({
name: “location”,
join: “CUSTBODY_JJ_EE_INVOICE_REFERENCE”,
summary: “GROUP”,
label: “Location”
})
]
});
let itemFulfillmentResultArray = [];
searchResultCount = itemfulfillmentSearchObj.runPaged().count;
log.debug(“itemfulfillmentSearchObj result count”, searchResultCount);
itemfulfillmentSearchObj.run().each(function (result) {
invoiceInternalId = result.getValue({
name: “internalid”,
summary: “GROUP”,
label: “Internal ID”
});
invoiceRef = result.getValue({
name: “custbody_jj_ee_invoice_reference”,
summary: “MAX”,
label: “Invoice ref #”
});
locationInvoice = result.getValue({
name: “location”,
join: “CUSTBODY_JJ_EE_INVOICE_REFERENCE”,
summary: “GROUP”,
label: “Location”
})
if (!locationInvoice) {
itemFulfillmentResultArray.push({
itemFulfillmentId: invoiceInternalId,
invoiceRef: invoiceRef
});
}
return true;
});
log.debug(“itemFulfillmentResultArray”, itemFulfillmentResultArray)
return itemFulfillmentResultArray;
} catch (e) {
log.error(‘Error in getInputData stage’, e);
}
}
/**
* Defines the function that is executed when the reduce entry point is triggered. This entry point is triggered
* automatically when the associated map stage is complete. This function is applied to each group in the provided context.
* @param {Object} reduceContext – Data collection containing the groups to process in the reduce stage. This parameter is
* provided automatically based on the results of the map stage.
* @param {Iterator} reduceContext.errors – Serialized errors that were thrown during previous attempts to execute the
* reduce function on the current group
* @param {number} reduceContext.executionNo – Number of times the reduce function has been executed on the current group
* @param {boolean} reduceContext.isRestarted – Indicates whether the current invocation of this function is the first
* invocation (if true, the current invocation is not the first invocation and this function has been restarted)
* @param {string} reduceContext.key – Key to be processed during the reduce stage
* @param {List<String>} reduceContext.values – All values associated with a unique key that was passed to the reduce stage
* for processing
* @since 2015.2
*/
const reduce = (reduceContext) => {
try {
reduceContext.values.forEach(value => {
let searchResult = JSON.parse(value);
log.debug(“searchResult”, searchResult)
let itemFulfillmentId = searchResult.itemFulfillmentId;
log.debug(“itemFulfillmentId”, itemFulfillmentId)
let invoiceNumber = searchResult.invoiceRef;
log.debug(“invoiceNumber”, invoiceNumber)
let location, invoiceId;
let invoiceDocumentNumber = invoiceNumber.replace(“Invoice #”, “”);
log.debug(“Clean Invoice Number”, invoiceDocumentNumber);
if (itemFulfillmentId) {
location = getItemFulfillmentLocation(itemFulfillmentId);
}
if (invoiceDocumentNumber) {
invoiceId = getInvoiceInternalId(invoiceDocumentNumber);
}
if (invoiceId && location) {
// Update the Invoice with the location
record.submitFields({
type: record.Type.INVOICE,
id: invoiceId,
values: {
location: location
},
options: {
enableSourcing: false,
ignoreMandatoryFields: true
}
});
log.debug(`Updated Invoice ${invoiceId} with location ${location}`);
}
else {
log.error(`Missing data for updating Invoice ${invoiceId}`, {
invoiceId: invoiceId,
location: location
});
}
});
} catch (e) {
log.error(‘Error in reduce stage’, e);
}
}
return { getInputData, reduce }
});