Scenario:
Fetch delivery status for each tracking number in an Item Fulfillment
Solution
/**
* @NApiVersion 2.x
* @NScriptType MapReduceScript
* @NModuleScope SameAccount
*/
/**
* Script Description
* This Map Reduce to create file to store the Details of UPS by making API call .
*
/*******************************************************************************
* APC-100 SS UPS Delivery Status
* *******************************************************************************
* $Author: Jobin & Jismi IT Services LLP $
*
* Date: 19 - 12 - 2019
* Revision History*
*
* Date: 27 - May - 2022
* Updated the script logic for considering multple tracking numbers in an IF forexecution
*
* DESCRIPTION
* This Map Reduce to create file to store the Details of UPS by making API call and
* create pdf file in the file cabinent that linked with the respective IF.
*
******************************************************************************/
define(['N/record', 'N/file', 'N/render', 'N/runtime', 'N/search', 'N/email', 'N/encode', 'N/task', 'N/https'],
function (record, file, render, runtime, search, email, encode, task, https) {
var main = {
/*Get inputData for Processing */
getInputData: function () {
try {
var itemfulfillmentSearchObj = search.create({
type: "itemfulfillment",
filters: [
[["type", "anyof", "ItemShip"]],
"AND",
[["shipmentpackage.trackingnumber", "isnotempty", ""]],
"AND",
[["mainline", "is", "T"]],
// "AND",
// [["custbody_jj_ups_pdf_create", "is", "F"]],
"AND",
[[[["tranpickeddate", "onorafter", "daysago30"]], "AND", [["createdfrom.type", "anyof", "SalesOrd"]]], "OR", [[["createdfrom.type", "anyof", "VendAuth"]], "AND", [["trandate", "onorafter", "daysago30"]]]]
],
columns: [
search.createColumn({
name: "trackingnumber",
join: "shipmentPackage",
label: "Tracking Number"
}),
search.createColumn({name: "internalid", label: "Internal ID"})
]
});
var array = [], trackingNum;
var searchResultCount = itemfulfillmentSearchObj.runPaged().count;
if (searchResultCount > 0) {
itemfulfillmentSearchObj.run().each(function (result) {
var obj = {};
obj.id = result.getValue({name: "internalid", label: "Internal ID"})
trackingNum = result.getValue({
name: "trackingnumber",
join: "shipmentPackage",
label: "Tracking Number"
});
obj.tranNum = result.getValue({
name: "trackingnumber",
join: "shipmentPackage",
label: "Tracking Number"
});
if (checkForParameter(obj.tranNum))
array.push(obj)
return true;
});
return array;
} else
return []
}catch (e) {
log.debug("Error@getInput", e)
return []
}
},
/*map Function of map Reduce */
map: function (context){
try{
var resultObject=JSON.parse(context.value);
var IFid= resultObject.id;
context.write({
key:IFid,
value:resultObject
})
}catch (e) {
log.debug("Error@map", e)
return []
}
},
/*Reduce Function of map Reduce */
reduce: function (context){
try {
var dataIF = context.values.map(JSON.parse);
log.debug("dataIF",dataIF)
// var contextData= JSON.parse(context.values[0]) //.values[0].values["GROUP(internalid)"].value)
// log.debug('contextData', contextData)contextData.values["GROUP(internalid)"].value;
var internalid = dataIF[0].id;
//var internalid = context.key
//load IF record
var ifRec = record.load({
type: record.Type.ITEM_FULFILLMENT,
id: internalid,
isDynamic: true
});
var trackingCount = dataIF.length;
log.debug("trackingCount", trackingCount)
for (var j=0; j<dataIF.length; j++){
var trackingNum = dataIF[j].tranNum;
log.debug("trackingNum", trackingNum)
//check whether a custom record entry for this tracking number already exists or not
var recEntryID = searchForCustomrecordEntry(trackingNum, internalid)
if (recEntryID){
var recEntry = record.load({
type: 'customrecord_jj_trackingnum_setup_apc381',
id: recEntryID,
isDynamic: true
});
var delivered = recEntry.getValue({fieldId: 'custrecord_jj_delivered'})
if (delivered == false)
fetchDeliveryStatus(trackingNum, internalid, recEntry)
}
else {
//create custom record entry
var recEntry = record.create({
type: 'customrecord_jj_trackingnum_setup_apc381',
isDynamic: true
});
recEntry.setValue({fieldId: 'name', value: trackingNum})
recEntry.setValue({fieldId: 'custrecord_jj_corresponding_if', value: internalid})
recEntry.setValue({fieldId: 'custrecord_jj_trackingnumber', value: trackingNum})
recEntry.setValue({fieldId: 'custrecord_jj_externalid', value: internalid+'_'+trackingNum})
fetchDeliveryStatus(trackingNum, internalid, recEntry)
}
}
} catch (err) {
log.debug('error@reduce', err.message);
}
},
summarize: function (context) {
try {
} catch (err) {
log.debug("error@summarize", err)
}
},
findfile: function () {
}
}
for (var key in main) {
if (typeof main[key] === 'function') {
main[key] = trycatch(main[key], key);
}
}
/**
* Function that fetches the UPS shipping status
* @param trackingNum
* @param internalid
* @param recEntry
*/
function fetchDeliveryStatus(trackingNum, internalid, recEntry) {
try {
//Call the API to determine UPS shipping status
var jsonBody = {
"UPSSecurity": {
"UsernameToken": {
"Username": "alliedtradinginc",
"Password": "Allied10555"
},
"ServiceAccessToken": {
"AccessLicenseNumber": "7D724FC3C0E4F732"
}
},
"TrackRequest": {
"Request": {
"RequestOption": "1",
"TransactionReference": {
"CustomerContext": "Your Test Case Summary Description"
}
},
"InquiryNumber": trackingNum
}
}
var headerObj = {
"Content-Type": 'application/json',
"Accept": 'application/json'
};
var response = https.post({
url: 'https://onlinetools.ups.com/rest/Track',
headers: headerObj,
body: JSON.stringify(jsonBody),
json: true
});
log.debug('response1111', response)
if (response.code == 200) {
response = JSON.parse(response.body)
log.debug('response1111', response)
if (response.Fault) {
} else {
log.debug("test", 'test')
var ShipmentAddress = response["TrackResponse"]["Shipment"]["ShipmentAddress"]
var deliverToAddress = "";
if (ShipmentAddress[1]) {
var deliverTo = ShipmentAddress[1]["Address"]
for (var key in deliverTo) {
deliverToAddress += deliverTo[key] + "<br/>"
}
}
var service = response["TrackResponse"]["Shipment"]["Service"]["Description"]
var pickupDate = response["TrackResponse"]["Shipment"]["PickupDate"]
if (pickupDate) {
pickupDate = pickupDate.substring(4, 6) + "/" + pickupDate.substring(6, 8) + "/" + pickupDate.substring(0, 4)
}
try {
var activity = response["TrackResponse"]["Shipment"]["Package"]["Activity"]
if (!activity) {
var datatoProcess = response["TrackResponse"]["Shipment"]["Package"]
for (var m = 0; m < datatoProcess.length; m++) {
var activity = datatoProcess[m]["Activity"]
trackingNum = datatoProcess[m]["TrackingNumber"]
var TABLE = " "
/* log.debug("activity", activity) */
for (var i = 0; i < activity.length; i++) {
var ShipmentWeight = datatoProcess["PackageWeight"]
if (ShipmentWeight) {
var unitMeasure = ShipmentWeight["UnitOfMeasurement"]["Code"]
var weight = ShipmentWeight["Weight"] + " " + unitMeasure
}
var address = activity[i]["ActivityLocation"]["Address"]
var finalAddress = "";
for (var key in address) {
finalAddress += address[key] + "<br/>"
}
var dateValue = activity[i]["Date"].substring(4, 6) + "/" + activity[i]["Date"].substring(6, 8) + "/" + activity[i]["Date"].substring(0, 4)
var timeValue = activity[i]["Time"].substring(0, 2) + ":" + activity[i]["Time"].substring(2, 4)
var signedValue = " "
if (activity[i]["ActivityLocation"]["SignedForByName"]) {
signedValue = activity[i]["ActivityLocation"]["SignedForByName"]
} else {
signedValue = " - "
}
var statusStings = activity[i]["Status"]["Description"]
var statusStingsLength = statusStings.length;
if (statusStingsLength > 32) {
var array = statusStings.split(" ");
var statusData = " ";
for (var l = 0; l < array.length; l++) {
if (l % 5 == 0) {
statusData += array[l] + "<br />"
} else {
statusData += array[l] + " "
}
}
statusStings = statusData
}
var strVar = "";
strVar += "<tr>";
strVar += "<td >" + finalAddress + "<\/td>";
strVar += "<td >" + activity[i]["ActivityLocation"]["Description"] + "<\/td>";
strVar += "<td >" + statusStings + "<\/td>";
strVar += "<td >" + dateValue + " " + timeValue + "<\/td>";
// strVar += "<td >" + timeValue + "<\/td>";
strVar += "<td >" + signedValue + "<\/td>";
strVar += "<\/tr>";
strVar = strVar + '\n';
TABLE = TABLE + strVar;
if (activity[i]["Status"]["Description"] == "Delivered") {
var SignedByName = signedValue
var DeliveredOn = dateValue + " " + timeValue
var LeftAt = activity[i]["ActivityLocation"]["Description"]
// var id = record.submitFields({
// type: 'itemfulfillment',
// id: internalid,
// values: {
// custbody_jj_ups_pdf_create: true
// }
// });
recEntry.setValue({fieldId: 'custrecord_jj_delivered', value: true})
if (!deliverToAddress) {
deliverToAddress = finalAddress
}
}
}
recEntry.save();
var myXMLFile = file.load({
id: '176569'
});
var xmlStr = myXMLFile.getContents();
xmlStr = xmlStr.replace('<!-- REPLACEWITHTABLEBODY -->', TABLE);
xmlStr = xmlStr.replace(/<!--REPLACEPACKAGEID-->/g, trackingNum);
xmlStr = xmlStr.replace('<!-- REPLACEWITHDELIVERTO -->', deliverToAddress);
if (weight) {
xmlStr = xmlStr.replace('<!-- REPLACEWITHWEIGHT -->', weight);
xmlStr = xmlStr.replace('<!-- REPLACEWITHWEIGHTWORD -->', "Weight");
}
xmlStr = xmlStr.replace('<!-- REPLACEWITHSERVICE -->', service);
xmlStr = xmlStr.replace('<!-- REPLACEWITHSIGNEDBY -->', SignedByName);
xmlStr = xmlStr.replace('<!-- REPLACEWITHDELIVERON -->', DeliveredOn);
xmlStr = xmlStr.replace('<!-- REPLACEWITHLEFTAT -->', LeftAt);
if (pickupDate) {
xmlStr = xmlStr.replace('<!-- REPLACEWITHPICKUPDATE-->', pickupDate);
xmlStr = xmlStr.replace('<!-- REPLACEWITHPICKUPWORD-->', "Shipped / Billed On");
}
var pdfFile = render.xmlToPdf({
xmlString: xmlStr
});
pdfFile.name = trackingNum + '.pdf'
pdfFile.folder = 131249
var fileID = pdfFile.save();
var attachid = record.attach({
record: {
type: 'file',
id: fileID
},
to: {
type: 'itemfulfillment',
id: internalid
}
});
}
} else {
var datatoProcess = response["TrackResponse"]["Shipment"]["Package"]
var ShipmentWeight = datatoProcess["PackageWeight"]
if (ShipmentWeight) {
var unitMeasure = ShipmentWeight["UnitOfMeasurement"]["Code"]
var weight = ShipmentWeight["Weight"] + " " + unitMeasure
}
for (var i = 0; i < activity.length; i++) {
var address = activity[i]["ActivityLocation"]["Address"]
var finalAddress = "";
for (var key in address)
finalAddress += address[key] + "<br/>"
var dateValue = activity[i]["Date"].substring(4, 6) + "/" + activity[i]["Date"].substring(6, 8) + "/" + activity[i]["Date"].substring(0, 4)
var timeValue = activity[i]["Time"].substring(0, 2) + ":" + activity[i]["Time"].substring(2, 4)
var signedValue = " "
if (activity[i]["ActivityLocation"]["SignedForByName"]) {
signedValue = activity[i]["ActivityLocation"]["SignedForByName"]
} else {
signedValue = " - "
}
var statusStings = activity[i]["Status"]["Description"]
var statusStingsLength = statusStings.length;
if (statusStingsLength > 32) {
var array = statusStings.split(" ");
var statusData = " ";
for (var l = 0; l < array.length; l++) {
if (l % 5 == 0) {
statusData += array[l] + "<br />"
} else {
statusData += array[l] + " "
}
}
statusStings = statusData
}
var strVar = "";
strVar += "<tr>";
strVar += "<td >" + finalAddress + "<\/td>";
strVar += "<td >" + activity[i]["ActivityLocation"]["Description"] + "<\/td>";
strVar += "<td >" + statusStings + "<\/td>";
strVar += "<td >" + dateValue + " " + timeValue + "<\/td>";
// strVar += "<td >" + timeValue + "<\/td>";
strVar += "<td >" + signedValue + "<\/td>";
strVar += "<\/tr>";
strVar = strVar + '\n';
TABLE = TABLE + strVar;
if (activity[i]["Status"]["Description"] == "Delivered") {
var SignedByName = signedValue
var DeliveredOn = dateValue + " " + timeValue
var LeftAt = activity[i]["ActivityLocation"]["Description"]
// var custId = record.submitFields({
// type: 'customrecord_jj_trackingnum_setup_apc381',
// id: internalid,
// values: {
// custbody_jj_ups_pdf_create: true
// }
// });
recEntry.setValue({fieldId: 'custrecord_jj_delivered', value: true})
if (!deliverToAddress) {
deliverToAddress = finalAddress
}
}
}
recEntry.save();
var myXMLFile = file.load({
id: '176569'
});
var xmlStr = myXMLFile.getContents();
xmlStr = xmlStr.replace('<!-- REPLACEWITHTABLEBODY -->', TABLE);
xmlStr = xmlStr.replace(/<!--REPLACEPACKAGEID-->/g, trackingNum);
xmlStr = xmlStr.replace('<!-- REPLACEWITHDELIVERTO -->', deliverToAddress);
if (weight) {
xmlStr = xmlStr.replace('<!-- REPLACEWITHWEIGHT -->', weight);
xmlStr = xmlStr.replace('<!-- REPLACEWITHWEIGHTWORD -->', "Weight");
}
xmlStr = xmlStr.replace('<!-- REPLACEWITHSERVICE -->', service);
xmlStr = xmlStr.replace('<!-- REPLACEWITHSIGNEDBY -->', SignedByName);
xmlStr = xmlStr.replace('<!-- REPLACEWITHDELIVERON -->', DeliveredOn);
xmlStr = xmlStr.replace('<!-- REPLACEWITHLEFTAT -->', LeftAt);
if (pickupDate) {
xmlStr = xmlStr.replace('<!-- REPLACEWITHPICKUPDATE-->', pickupDate);
xmlStr = xmlStr.replace('<!-- REPLACEWITHPICKUPWORD-->', "Shipped / Billed On");
}
var pdfFile = render.xmlToPdf({
xmlString: xmlStr
});
pdfFile.name = trackingNum + '.pdf'
pdfFile.folder = 131249
var fileID = pdfFile.save();
var attachid = record.attach({
record: {
type: 'file',
id: fileID
},
to: {
type: 'itemfulfillment',
id: internalid
}
});
}
} catch (er) {
log.debug("er", er)
}
}
}
} catch (e) {
log.debug("Error@fetch delivery status", e)
}
}
function searchForCustomrecordEntry(trackingNum, itemFulfillment) {
try {
var uniqueKey = itemFulfillment+'_'+trackingNum;
var customrecordSearchObj = search.create({
type: "customrecord_jj_trackingnum_setup_apc381",
filters:
[
["custrecord_jj_externalid", "is", uniqueKey],
],
columns:
[
search.createColumn({name: "internalid", label: "Internal ID"})
]
});
var searchResultCount = customrecordSearchObj.runPaged().count;
log.debug("customrecord_jj_trackingnum_setup_apc381SearchObj result count", searchResultCount);
if (searchResultCount > 0) {
var recId;
customrecordSearchObj.run().each(function (result) {
recId = result.getValue({name: "internalid", label: "Internal ID"})
return true;
});
return recId;
} else
return false;
} catch (e) {
log.debug("Error@searchForCustomrecordEntry", e)
return false;
}
}
/**
* @description Check whether the given parameter argument has value on it or is it empty.
* ie, To check whether a value exists in parameter
* @author Manu Antony
* @param {*} parameter parameter which contains/references some values
* @param {*} parameterName name of the parameter, not mandatory
* @returns {Boolean} true if there exist a value else false
*/
function checkForParameter(parameter, parameterName) {
if (parameter !== "" && parameter !== null && parameter !== undefined && parameter !== false && parameter !== "null" && parameter !== "undefined" && parameter !== " " && parameter !== 'false') {
return true;
} else {
if (parameterName)
log.debug('Empty Value found', 'Empty Value for parameter ' + parameterName);
return false;
}
}
function trycatch(myfunction, key) {
return function () {
try {
return myfunction.apply(this, arguments);
} catch (e) {
log.debug("e in " + key, e);
}
}
}
return main;
});