The client needs to send sales order line-level details to Dispatch Tracker, the lines will be scheduled at different times. The lines scheduled at a time need to send to the dispatch tracker and create as single order in the Dispatch tracker.
Scheduled Script To Send Sales Order Line Level Details To Dispatch Tracker.
/**
* @NApiVersion 2.1
* @NScriptType MapReduceScript
*/
/************************************************************************************************
* * Map/Reduce Script For Sending SO Details to Delivery Dispatcher **
*
*
* **********************************************************************************************
*
* Author: Jobin and Jismi IT Services
*
* Date Created : 26-August-2022
*
* Created By: Athul Krishna, Jobin and Jismi IT Services
*
* Description : Map/Reduce Script For Sending SO Details to Delivery Dispatcher
*
* REVISION HISTORY
*
*
*
*
***********************************************************************************************/
define(['N/error', 'N/http', 'N/record', 'N/runtime', 'N/search', 'N/url', '../Library/JJ CM Dispatch Tracker API AHAP-14.js', '../Library/JJ CM NS Utility'],
/**
* @param{error} error
* @param{http} http
* @param{record} record
* @param{runtime} runtime
* @param{search} search
* @param{url} url
*/
(error, http, record, runtime, search, url, dispatchTracker, JJ_CM_NS_Utility) => {
/**
* 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 {
const currentEnv = JJ_CM_NS_Utility.envMethods.init();
if (!currentEnv?.envType?.PRODUCTION)
return [];
let salesorderSearchObj = search.create({
type: "transaction",
filters: [
[
[
["type", "anyof", "TrnfrOrd"],
"AND",
["transactionlinetype", "anyof", "ITEM"]
],
"OR",
["type", "anyof", "RtnAuth", "SalesOrd"]
],
"AND",
["status", "anyof", "RtnAuth:B", "RtnAuth:D", "RtnAuth:E", "RtnAuth:F", "SalesOrd:B", "SalesOrd:D", "SalesOrd:E", "SalesOrd:F", "TrnfrOrd:B", "TrnfrOrd:F", "TrnfrOrd:E", "TrnfrOrd:G"],
"AND",
["mainline", "is", "F"],
"AND",
["custcol_sent_2_dt", "isempty", ""],
"AND",
["custcol_dt_order", "isnotempty", ""],
"AND",
["custcol_del_conf", "is", "F"]
],
columns: [
search.createColumn({name: "item", label: "Item"}),
search.createColumn({
name: "formulatext",
formula: "{internalid}||':'||{item}",
label: "Line Key"
}),
search.createColumn({
name: "line",
sort: search.Sort.ASC,
label: "Line ID"
}),
search.createColumn({name: "custcol_dt_order", label: "DT Order"}),
search.createColumn({name: "custcol_sched_del_date", label: "Req Del Date"}),
search.createColumn({
name: "displayname",
join: "item",
label: "Display Name"
}),
search.createColumn({name: "quantity", label: "Quantity"}),
search.createColumn({name: "custcol_trans_route", label: "Route"}),
search.createColumn({
name: "externalid",
join: "customer",
label: "External ID"
}),
search.createColumn({
name: "firstname",
join: "customer",
label: "First Name"
}),
search.createColumn({
name: "lastname",
join: "customer",
label: "Last Name"
}),
search.createColumn({
name: "phone",
join: "customer",
label: "Phone"
}),
search.createColumn({
name: "mobilephone",
join: "customer",
label: "Mobile Phone"
}),
search.createColumn({name: "email", label: "Email"}),
search.createColumn({
name: "shipaddress1",
join: "customer",
label: "Shipping Address 1"
}),
search.createColumn({
name: "shipaddress2",
join: "customer",
label: "Shipping Address 2"
}),
search.createColumn({
name: "shipcity",
join: "customer",
label: "Shipping City"
}),
search.createColumn({
name: "shipstate",
join: "customer",
label: "Shipping State/Province"
}),
search.createColumn({
name: "shipzip",
join: "customer",
label: "Shipping Zip"
}),
search.createColumn({
name: "shipphone",
join: "customer",
label: "Shipping Phone"
}),
search.createColumn({name: "memomain", label: "Memo (Main)"}),
search.createColumn({
name: "internalid",
join: "location",
label: "Location"
}),
//search.createColumn({name: "custcol_line_notes", label: "Line Notes"}),
search.createColumn({name: "salesrep", label: "Sales Rep"}),
search.createColumn({
name: "formulatext",
formula: "TO_CHAR(sysdate,'M/D/YYYY')",
label: "Sent To DT"
}),
search.createColumn({name: "custcol_dt_acct", label: "DT Account"}),
search.createColumn({
name: "internalid",
join: "customer",
label: "Customer Internal"
}),
search.createColumn({name: "custcol_sched_del_date", label: "Req Del Date"}),
search.createColumn({
name: "itemid",
join: "item",
label: "Name"
}),
search.createColumn({name: "amount", label: "Amount"}),
//search.createColumn({ name: "custcol_aha_item_description", label: "Item Description" }),
search.createColumn({name: "custcol_trans_route", label: "Route"}),
search.createColumn({
name: "custbody_jj_delivery_instructions",
label: "Delivery Instructions"
}),
search.createColumn({name: "custbody_jj_type_of_delivery", label: "Type of Delivery"}),
search.createColumn({name: "custbody_jj_property_type", label: "Property Type"}),
search.createColumn({name: "custbody_jj_house_type", label: "House Type"}),
search.createColumn({name: "custbody_delivery_floor_level", label: "Delivery Floor Level"}),
search.createColumn({name: "custbody_jj_number_of_stairs", label: "Number of Stairs"}),
search.createColumn({name: "custbody_jj_labor_requirements", label: "Labor Requirements"}),
search.createColumn({name: "custbody_jj_fuel_type", label: "Fuel Type"}),
search.createColumn({
name: "salesdescription",
join: "item",
label: "Description"
}),
search.createColumn({
name: "custitem30",
join: "item",
label: "Height (IN)"
}),
search.createColumn({
name: "custitem29",
join: "item",
label: "Width (IN)"
}),
search.createColumn({
name: "custitem28",
join: "item",
label: "Depth (IN)"
}),
search.createColumn({
name: "formulanumeric",
formula: "CASE WHEN ((TO_NUMBER({item.custitem28}) IS NULL OR TO_NUMBER({item.custitem28})=0) AND (TO_NUMBER({item.custitem29}) IS NULL OR TO_NUMBER({item.custitem29})=0) AND (TO_NUMBER({item.custitem30}) IS NULL OR TO_NUMBER({item.custitem30})=0)) THEN 0 ELSE NVL(TO_NUMBER({item.custitem29}),1)*NVL(TO_NUMBER({item.custitem28}),1)*NVL(TO_NUMBER({item.custitem30}),1)END",
label: "Formula (Numeric)"
}),
search.createColumn({
name: "custitem44",
join: "item",
label: "Installation Time"
}),
search.createColumn({name: "custcol_dt_acct", label: "DT Account"}),
search.createColumn({name: "type", label: "Type"}),
search.createColumn({name: "tranid", label: "Document Number"}),
search.createColumn({name: "memo", label: "Memo"}),
search.createColumn({name: "salesrep", label: "Sales Rep"}),
search.createColumn({name: "custcol_trans_route", label: "Route"}),
search.createColumn({name: "shipcity", label: "Shipping City"}),
search.createColumn({name: "shipaddress1", label: "Shipping Address 1"}),
search.createColumn({name: "shipaddress2", label: "Shipping Address 2"}),
search.createColumn({name: "shipstate", label: "Shipping State/Province"}),
search.createColumn({name: "shipzip", label: "Shipping Zip"}),
search.createColumn({name: "shipcountry", label: "Shipping Country"}),
search.createColumn({
name: "altname",
join: "customer",
label: "Name"
}),
search.createColumn({name: "custcol_jj_scheduled_by", label: "Scheduled By"}),
search.createColumn({name: "custbody15", label: "Driver Call Ahead Number"}),
search.createColumn({name: "custbody8", label: "Bill to Main Number"}),
search.createColumn({name: "location", label: "Location"})
]
});
let searchResultCount = salesorderSearchObj.runPaged().count;
log.debug("salesorderSearchObj result count", searchResultCount);
if (searchResultCount > 0) {
return salesorderSearchObj
} else {
return []
}
} catch (e) {
log.error("error@getInput", e);
}
}
/**
* Defines the function that is executed when the map entry point is triggered. This entry point is triggered automatically
* when the associated getInputData stage is complete. This function is applied to each key-value pair in the provided
* context.
* @param {Object} mapContext - Data collection containing the key-value pairs to process in the map stage. This parameter
* is provided automatically based on the results of the getInputData stage.
* @param {Iterator} mapContext.errors - Serialized errors that were thrown during previous attempts to execute the map
* function on the current key-value pair
* @param {number} mapContext.executionNo - Number of times the map function has been executed on the current key-value
* pair
* @param {boolean} mapContext.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} mapContext.key - Key to be processed during the map stage
* @param {string} mapContext.value - Value to be processed during the map stage
* @since 2015.2
*/
const map = (mapContext) => {
try {
let searchResult = JSON.parse(mapContext.value);
//log.debug("ssearchResult",searchResult)
if (searchResult && searchResult?.values?.custcol_dt_order) {
let dtOrderNumber = searchResult.values.custcol_dt_order;
//log.debug("dtOrderNumber",dtOrderNumber)
mapContext.write({
key: dtOrderNumber,
value: searchResult
});
}
} catch (e) {
log.debug("error@Map", e)
}
}
function checkForParameter(parameter) {
if (parameter !== "" && parameter !== null && parameter !== undefined && parameter !== false && parameter !== "null"
&& parameter !== "undefined" && parameter !== " " && parameter !== 'false') {
return true;
} else {
log.debug("empty")
return false;
}
}
function dispatchTrackerIntegrationLogSearch(dtNUmber) {
try {
let customrecord_jj_dispatcher_log_ahap14SearchObj = search.create({
type: "customrecord_jj_dispatcher_log_ahap14",
filters: [
["custrecord_jj_dt_number_ahap_14", "is", dtNUmber]
],
columns: [
search.createColumn({name: "custrecord_jj_dt_number_ahap_14", label: "DT Number"}),
search.createColumn({name: "custrecord_jj_resolved_check_box_ahap_14", label: "Resolved"}),
search.createColumn({name: "internalid", label: "Internal ID"})
]
});
let searchResultCount = customrecord_jj_dispatcher_log_ahap14SearchObj.runPaged().count;
if (searchResultCount > 0) {
let internalID = false;
log.debug("customrecord_jj_dispatcher_log_ahap14SearchObj result count", searchResultCount);
customrecord_jj_dispatcher_log_ahap14SearchObj.run().each(function (result) {
internalID = result.getValue({
name: "internalid", label: "Internal ID"
})
return false;
});
return internalID;
} else {
return false;
}
} catch (e) {
log.debug("error@dispatchTrackerIntegrationLogSearch", e);
return false;
}
}
function escapeXMLData(data) {
if (data?.toString()?.trim()) {
return data.toString().trim().replaceAll('&', " ").replaceAll('<', ' ').replaceAll('>', ' ').replaceAll('?', ' ').replaceAll('%', ' ').replaceAll('{', ' ').replaceAll('}', ' ').replaceAll('\n\r', ' ').replaceAll('\r\n', ' ').replaceAll('\n', ' ').replaceAll('\r', ' ').replaceAll('"', ' ').replaceAll('\'', ' ')
}
return ''
}
/**
* 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 {
let key = reduceContext.key
log.debug("key", key)
let reduceData = reduceContext.values.map(JSON.parse);
log.debug("reduce data", reduceData)
let address1 = reduceData[0].values["shipaddress1"]
let state = reduceData[0].values["shipstate"]
let city = reduceData[0].values["shipstate"]
let zip = reduceData[0].values["shipzip"]
if (address1 && state && city && zip) {
let delivery_Type = ''
if (reduceData[0].values["custbody_jj_type_of_delivery"] && reduceData[0].values["custbody_jj_type_of_delivery"]?.text) {
delivery_Type = reduceData[0].values["custbody_jj_type_of_delivery"]?.text;
if ((delivery_Type.toLowerCase()).includes('pick up')) {
delivery_Type = "Pickup"
} else {
delivery_Type = "Delivery"
}
} else {
delivery_Type = "Delivery"
}
let emailId = reduceData[0].values["email"];
let firstName = reduceData[0].values["firstname.customer"];
if (firstName == '' || !firstName) {
firstName = reduceData[0].values['altname.customer'];
}
if (!firstName && reduceData[0].recordType == 'transferorder' && reduceData[0].values.custcol_jj_scheduled_by?.value) {
let customerEmail = search.lookupFields({
type: search.Type.EMPLOYEE,
id: reduceData[0].values.custcol_jj_scheduled_by.value,
columns: ['email', 'altname']
});
emailId = customerEmail.email;
firstName = customerEmail.altname;
if ((!firstName || firstName === "") && emailId) {
firstName = emailId.split("@")[0];
}
}
log.debug("emailId,firstName", {emailId, firstName});
let dtAccount = reduceData[0].values["custcol_dt_acct"].text;
//let type=delivery_Type
log.debug("delievery Type", delivery_Type)
let headerObj = {
number: reduceData[0].values.custcol_dt_order,
account: "trialsairporthomeappliance",
service_type: delivery_Type,
description: escapeXMLData(reduceData[0].values['custbody_jj_delivery_instructions']),
customer_id: reduceData[0].values["internalid.customer"].value,
first_name: firstName,
last_name: reduceData[0].values["lastname.customer"],
email: emailId,
phone1: reduceData[0].values["custbody15"],
phone2: reduceData[0].values["custbody8"],
address1: escapeXMLData(reduceData[0].values["shipaddress1"]),
address2: escapeXMLData(reduceData[0].values["shipaddress2"]),
city: escapeXMLData(reduceData[0].values["shipcity"]),
state: reduceData[0].values["shipstate"],
zip: reduceData[0].values["shipzip"],
latitude: "",
longitude: "",
email_opt_out: "false",
preferred_contact_method: "EMAIL",
}
let footerObj = {
preferred_contact_method: "ALL",
request_delivery_date: reduceData[0].values["custcol_sched_del_date"],
service_unit: reduceData[0].values["custcol_trans_route"]?.text,
af_route_label: "Daily",
af_account: reduceData[0].values["custcol_dt_acct"].text
}
let sales_person = reduceData[0].values['salesrep']?.text
if (!checkForParameter(sales_person)) {
sales_person = ''
}
let additionField = {
delivery_instruction: escapeXMLData(reduceData[0].values["custbody_jj_delivery_instructions"]),
property_type: reduceData[0].values["custbody_jj_property_type"].text,
house_type: reduceData[0].values["custbody_jj_house_type"].text,
delivery_floor_level: reduceData[0].values["custbody_delivery_floor_level"].text,
number_of_stairs: reduceData[0].values["custbody_jj_number_of_stairs"].text,
delivery_type: reduceData[0].values["custbody_jj_type_of_delivery"].text,
fuel_type: reduceData[0].values["custbody_jj_fuel_type"].text,
ns_type: reduceData[0].recordType,
internal_id: reduceData[0].id,
account: dtAccount,
sales_person: escapeXMLData(sales_person),
document_number: reduceData[0].values['tranid'],
memo: escapeXMLData(reduceData[0].values['memo']),
route_label: reduceData[0].values['custcol_trans_route'].text
}
let itemsArray = [];
for (let i = 0; i < reduceData.length; i++) {
log.debug("cube", reduceData[i].values['formulanumeric'])
let quantity = reduceData[i].values["quantity"];
let description = escapeXMLData(reduceData[i].values['salesdescription.item'])
if (reduceData[0].recordType == 'transferorder')
quantity = Math.abs(quantity)
itemsArray.push({
line: reduceData[i].values["line"],
itemCode: escapeXMLData(reduceData[i].values["item"].text + ":" + reduceData[i].values["line"]),
sale_sequence: reduceData[i].values["line"],
item_id: escapeXMLData(reduceData[i].values["item"].text),
description: escapeXMLData(description),
line_item_notes: "", //escapeXMLData(reduceData[i].values["custcol_line_notes"]),
quantity: quantity,
location: reduceData[i].values["location"].text,
price: reduceData[i].values["amount"],
setup_time: reduceData[i].values['custitem44.item'],
cube: reduceData[i].values['formulanumeric'],
})
}
let mainRequest = dispatchTracker.serviceOrder.generateRequestBody(headerObj, itemsArray, footerObj, additionField)
log.debug("Main Request in Reduce", mainRequest)
if (mainRequest) {
// let apiResponse = DISPATCH_API.createServiceOrder.sendAPIRequest(mainRequest);
let apiResponse = dispatchTracker.serviceOrder.createServiceOrder(mainRequest, dtAccount)
log.debug("apiResponse", apiResponse);
let resposneCode = apiResponse.status
if (resposneCode == 200) {
//let type=reduceData[0]
let currentRecord = record.load({
type: reduceData[0].recordType,
id: reduceData[0].id,
isDynamic: false
});
let lineCount = currentRecord.getLineCount({sublistId: 'item'})
for (let i = 0; i < lineCount; i++) {
let soID = currentRecord.getSublistValue({
sublistId: 'item',
fieldId: 'custcol_dt_order',
line: i
})
if (key == soID) {
currentRecord.setSublistValue({
sublistId: 'item',
fieldId: 'custcol_sent_2_dt',
value: new Date(),
line: i
});
}
}
currentRecord.save({
ignoreMandatoryFields: true
});
let integrationLogRecord = dispatchTrackerIntegrationLogSearch(key)
if (integrationLogRecord && integrationLogRecord != false) {
let logRecord = record.load({
type: 'customrecord_jj_dispatcher_log_ahap14',
id: integrationLogRecord,
isDynamic: false
});
logRecord.setValue({
fieldId: 'custrecord_jj_resolved_check_box_ahap_14',
value: true
});
logRecord.save({
ignoreMandatoryFields: true
});
log.debug("");
}
} else {
let integrationLogRecord = dispatchTrackerIntegrationLogSearch(key)
if (integrationLogRecord && integrationLogRecord != false) {
let logRecord = record.load({
type: 'customrecord_jj_dispatcher_log_ahap14',
id: integrationLogRecord,
isDynamic: false
});
logRecord.setValue({
fieldId: 'custrecord_jj_resolved_check_box_ahap_14',
value: false
});
logRecord.setValue({
fieldId: 'custrecord_jj_error_message_ahap_14',
value: apiResponse.result
})
logRecord.save({
ignoreMandatoryFields: true
});
} else {
let customErrorRecord = record.create({
type: 'customrecord_jj_dispatcher_log_ahap14',
isDynamic: true
});
customErrorRecord.setValue({
fieldId: 'name',
value: reduceData[0].values.custcol_dt_order
})
customErrorRecord.setValue({
fieldId: 'custrecord_jj_dt_number_ahap_14',
value: reduceData[0].values.custcol_dt_order
})
customErrorRecord.setValue({
fieldId: 'custrecord_jj_error_message_ahap_14',
value: apiResponse.result
})
customErrorRecord.setValue({
fieldId: 'custrecord_jj_resolved_check_box_ahap_14',
value: false
});
customErrorRecord.setValue({
fieldId: 'custrecord_jj_transaction_number_ahap_14',
value: reduceData[0].id
});
customErrorRecord.save({
ignoreMandatoryFields: true
})
}
}
}
} else {
log.debug("nothing working")
let integrationLogRecord = dispatchTrackerIntegrationLogSearch(key)
if (integrationLogRecord && integrationLogRecord != false) {
let logRecord = record.load({
type: 'customrecord_jj_dispatcher_log_ahap14',
id: integrationLogRecord,
isDynamic: false
});
logRecord.setValue({
fieldId: 'custrecord_jj_resolved_check_box_ahap_14',
value: false
});
logRecord.setValue({
fieldId: 'custrecord_jj_error_message_ahap_14',
value: "Required fields is missing"
})
logRecord.save({
ignoreMandatoryFields: true
});
} else {
let customErrorRecord = record.create({
type: 'customrecord_jj_dispatcher_log_ahap14',
isDynamic: true
});
customErrorRecord.setValue({
fieldId: 'name',
value: reduceData[0].values.custcol_dt_order
})
customErrorRecord.setValue({
fieldId: 'custrecord_jj_dt_number_ahap_14',
value: reduceData[0].values.custcol_dt_order
})
customErrorRecord.setValue({
fieldId: 'custrecord_jj_error_message_ahap_14',
value: "Required fields is missing"
})
customErrorRecord.setValue({
fieldId: 'custrecord_jj_resolved_check_box_ahap_14',
value: false
});
customErrorRecord.setValue({
fieldId: 'custrecord_jj_transaction_number_ahap_14',
value: reduceData[0].id
});
customErrorRecord.save({
ignoreMandatoryFields: true
})
}
}
} catch (e) {
log.debug("error@Reduce", e)
}
}
/**
* Defines the function that is executed when the summarize entry point is triggered. This entry point is triggered
* automatically when the associated reduce stage is complete. This function is applied to the entire result set.
* @param {Object} summaryContext - Statistics about the execution of a map/reduce script
* @param {number} summaryContext.concurrency - Maximum concurrency number when executing parallel tasks for the map/reduce
* script
* @param {Date} summaryContext.dateCreated - The date and time when the map/reduce script began running
* @param {boolean} summaryContext.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 {Iterator} summaryContext.output - Serialized keys and values that were saved as output during the reduce stage
* @param {number} summaryContext.seconds - Total seconds elapsed when running the map/reduce script
* @param {number} summaryContext.usage - Total number of governance usage units consumed when running the map/reduce
* script
* @param {number} summaryContext.yields - Total number of yields when running the map/reduce script
* @param {Object} summaryContext.inputSummary - Statistics about the input stage
* @param {Object} summaryContext.mapSummary - Statistics about the map stage
* @param {Object} summaryContext.reduceSummary - Statistics about the reduce stage
* @since 2015.2
*/
const summarize = (summaryContext) => {
}
return {getInputData, map, reduce, summarize}
});
Custom Module For API Calling
/**
* @NApiVersion 2.1
*/
/************************************************************************************************
* * API for Dispatch Tracker**
*
*
* **********************************************************************************************
*
* Author: Jobin and Jismi IT Services
*
* Date Created : 26-August-2022
*
* Created By: Athul Krishna, Jobin and Jismi IT Services
*
* Description : Custom module for handling the APIs for Dispatch Tracker
*
* REVISION HISTORY
*
*
*
*
***********************************************************************************************/
define(["require", "exports", "N/https", "N/log", "./JJ XML Parser AHAP-14", "./JJ CM NS Utility", "N/xml"], function (require, exports, https, log, xmlParser, JJ_CM_NS_Utility_1, xml) {
"use strict";
const DISPATCH_API = {
environment: {
production: {
baseUrl: 'https://airporthomeappliance.dispatchtrack.com',
code: 'airporthomeappliance',
accounts: {
'Apogee Home Delivery': '424d4a110915dcd22',
'Home Delivery': '1fac96a8ae2afb8f8',
'Airport Transfer Truck': 'b160e4ee3836a8f49',
'R&S Installation': 'e61ddadfa2fbd965d',
'PRO Installation': 'e8ee40a3b0fc9d2df',
'Installation': 'f81e972db599139bb',
'KPS Installation': 'd6cd0a4949f13af72',
'Same Day Truck': 'afb37d764b4e4d94d',
'AHA Premium': '4cf78ad546a7bd2ef',
'Apogee Transfer Truck': 'c7e5fc698d384ffa5',
'AHA Netsuite Test Account': '66b79590c91449471',
}
},
sandbox: {
baseUrl: 'https://trials.dispatchtrack.com',
code: 'trialsairporthomeappliance',
accounts: {
'Apogee Home Delivery': '6697aed1612f62f65',
'Home Delivery': '6697aed1612f62f65',
'Airport Transfer Truck': '6697aed1612f62f65',
'R&S Installation': '6697aed1612f62f65',
'PRO Installation': '6697aed1612f62f65',
'Installation': '6697aed1612f62f65',
'KPS Installation': '6697aed1612f62f65',
'Same Day Truck': '6697aed1612f62f65',
'AHA Premium': '6697aed1612f62f65',
'Apogee Transfer Truck': '6697aed1612f62f65',
'AHA Netsuite Test Account': '6697aed1612f62f65',
}
}
},
authObj: {
baseUrl: 'https://airporthomeappliance.dispatchtrack.com',
code: 'airporthomeappliance',
accounts: {
'Apogee Home Delivery': '424d4a110915dcd22',
'Home Delivery': '1fac96a8ae2afb8f8',
'Airport Transfer Truck': 'b160e4ee3836a8f49',
'R&S Installation': 'e61ddadfa2fbd965d',
'PRO Installation': 'e8ee40a3b0fc9d2df',
'Installation': 'f81e972db599139bb',
'KPS Installation': 'd6cd0a4949f13af72',
'Same Day Truck': 'afb37d764b4e4d94d',
'AHA Premium': '4cf78ad546a7bd2ef',
'Apogee Transfer Truck': 'c7e5fc698d384ffa5',
'AHA Netsuite Test Account': '66b79590c91449471',
}
},
serviceOrder: {
/**
* To generate the XML schema body for creating Service Order in Dispatch Tracker
* @param {object} headerObj
* @param {string} headerObj.number
* @param {string} headerObj.account
* @param {string} headerObj.service_type
* @param {string} headerObj.customer_id
* @param {string} headerObj.first_name
* @param {string} headerObj.last_name
* @param {string} headerObj.email
* @param {string} headerObj.phone1
*
* @param itemArray
* @param footerObj
* @param additionalFieldsObj
* @returns {String}
*/
generateRequestBody(headerObj, itemArray, footerObj, additionalFieldsObj) {
log.debug("headerObj", headerObj);
log.debug("itemArray", itemArray);
log.debug("footerObj", footerObj);
let requestData = [
`<?xml version="1.0" encoding="UTF-8"?>
<service_orders>
<service_order>
<number>${xml.escape({ xmlText: headerObj.number?.toString()?.trim() ?? '' })}</number>
<account>${xml.escape({ xmlText: headerObj.account?.toString()?.trim() ?? '' })}</account>
<service_type>${xml.escape({ xmlText: headerObj.service_type?.toString()?.trim() ?? '' })}</service_type>
<description>
${xml.escape({ xmlText: headerObj.description?.toString()?.trim() ?? '' })}
</description>
<customer>
<customer_id>${xml.escape({ xmlText: headerObj.customer_id?.toString()?.trim() ?? '' })}</customer_id>
<first_name>${xml.escape({ xmlText: headerObj.first_name?.toString()?.trim() ?? '' })}</first_name>
<last_name>${xml.escape({ xmlText: headerObj.last_name?.toString()?.trim() ?? '' })}</last_name>
<email>${xml.escape({ xmlText: headerObj.email?.toString()?.trim() ?? '' })}</email>
<phone1>${xml.escape({ xmlText: headerObj.phone1?.toString()?.trim() ?? '' })}</phone1>
<phone2>${xml.escape({ xmlText: headerObj.phone2?.toString()?.trim() ?? '' })}</phone2>
<address1>${xml.escape({ xmlText: headerObj.address1?.toString()?.trim() ?? '' })}</address1>
<address2>${xml.escape({ xmlText: headerObj.address2?.toString()?.trim() ?? '' })}</address2>
<state>${xml.escape({ xmlText: headerObj.state?.toString()?.trim() ?? '' })}</state>
<city>${xml.escape({ xmlText: headerObj.city?.toString()?.trim() ?? '' })}</city>
<zip>${xml.escape({ xmlText: headerObj.zip?.toString()?.trim() ?? '' })}</zip>
<latitude>${xml.escape({ xmlText: headerObj.latitude?.toString()?.trim() ?? '' })}</latitude>
<longitude>${xml.escape({ xmlText: headerObj.longitude?.toString()?.trim() ?? '' })}</longitude>
<email_opt_out>${xml.escape({ xmlText: headerObj.email_opt_out?.toString()?.trim() ?? '' })}</email_opt_out>
<preferred_contact_method>${xml.escape({ xmlText: headerObj.preferred_contact_method?.toString()?.trim() ?? '' })}</preferred_contact_method>
</customer>`,
`<items>`,
...itemArray.map(el => {
return `<item>
<sale_sequence>${xml.escape({ xmlText: el["sale_sequence"]?.toString()?.trim() ?? '' })}</sale_sequence>
<item_id>${xml.escape({ xmlText: el["item_id"]?.toString()?.trim() ?? '' })}</item_id>
<description>${xml.escape({ xmlText: el.description?.toString()?.trim() ?? '' })}</description>
<line_item_notes>${xml.escape({ xmlText: el.line_item_notes?.toString()?.trim() ?? '' })}</line_item_notes>
<quantity>${xml.escape({ xmlText: el.quantity?.toString()?.trim() ?? '' })}</quantity>
<location>${xml.escape({ xmlText: el.location?.toString()?.trim() ?? '' })}</location>
<price>${xml.escape({ xmlText: el.price?.toString()?.trim() ?? '' })}</price>
<setup_time>${xml.escape({ xmlText: el.setup_time?.toString()?.trim() ?? '' })}</setup_time>
<cube>${xml.escape({ xmlText: el.cube?.toString()?.trim() ?? '' })}</cube>
</item>`;
}),
`</items>`,
`<preferred_contact_method>${xml.escape({ xmlText: footerObj.preferred_contact_method?.toString()?.trim() ?? '' })}</preferred_contact_method>
<request_delivery_date>${xml.escape({ xmlText: footerObj.request_delivery_date?.toString()?.trim() ?? '' })}</request_delivery_date>
<service_unit>${xml.escape({ xmlText: footerObj.service_unit?.toString()?.trim() ?? '' })}</service_unit>
<af_route_label>${xml.escape({ xmlText: footerObj.af_route_label?.toString()?.trim() ?? '' })}</af_route_label>
<af_account>${xml.escape({ xmlText: footerObj.af_account?.toString()?.trim() ?? '' })}</af_account>
<additional_fields>
<Delivery_Instruction>${xml.escape({ xmlText: additionalFieldsObj.delivery_instruction?.toString()?.trim() ?? '' })}</Delivery_Instruction>
<Property_Type>${xml.escape({ xmlText: additionalFieldsObj.property_type?.toString()?.trim() ?? '' })}</Property_Type>
<House_Type>${xml.escape({ xmlText: additionalFieldsObj.house_type?.toString()?.trim() ?? '' })}</House_Type>
<Delivery_Floor_Level>${xml.escape({ xmlText: additionalFieldsObj.delivery_floor_level?.toString()?.trim() ?? '' })}</Delivery_Floor_Level>
<Number_Of_Stairs>${xml.escape({ xmlText: additionalFieldsObj.number_of_stairs?.toString()?.trim() ?? '' })}</Number_Of_Stairs>
<Delivery_Type>${xml.escape({ xmlText: additionalFieldsObj.delivery_type?.toString()?.trim() ?? '' })}</Delivery_Type>
<Fuel_Type>${xml.escape({ xmlText: additionalFieldsObj.fuel_type?.toString()?.trim() ?? '' })}</Fuel_Type>
<Ns_Internal_Id>${xml.escape({ xmlText: additionalFieldsObj.internal_id?.toString()?.trim() ?? '' })}</Ns_Internal_Id>
<Ns_Type>${xml.escape({ xmlText: additionalFieldsObj.ns_type?.toString()?.trim() ?? '' })}</Ns_Type>
<Account>${xml.escape({ xmlText: additionalFieldsObj.account?.toString()?.trim() ?? '' })}</Account>
<Route_Label>${xml.escape({ xmlText: additionalFieldsObj.route_label?.toString()?.trim() ?? '' })}</Route_Label>
<Sales_Person>${xml.escape({ xmlText: additionalFieldsObj.sales_person?.toString()?.trim() ?? '' })}</Sales_Person>
<Ns_Document_Number>${xml.escape({ xmlText: additionalFieldsObj.document_number?.toString()?.trim() ?? '' })}</Ns_Document_Number>
</additional_fields>
</service_order>
</service_orders>`
].join("");
log.debug("requestData", requestData);
return requestData;
},
createServiceOrder(data, dispatch_tracker_account) {
/*let dispatcherRequest = https.post({
url: `${DISPATCH_API.authObj.baseUrl}/orders/api/add_order?code=${DISPATCH_API.authObj.code}&api_key=${DISPATCH_API.authObj.accounts[dispatch_tracker_account]}&account=${'AHA Netsuite Test Account' || dispatch_tracker_account}&data=${data}`,
headers: {
'Content-Type': 'text/plain',
'api_key': DISPATCH_API.authObj.accounts[dispatch_tracker_account],
},
body: ``,
});
log.debug("createServiceOrder", dispatcherRequest)
if (dispatcherRequest && dispatcherRequest.code == 200)
return {
status: dispatcherRequest.code,
result: xmlParser.xml2json.parser(dispatcherRequest.body)
};
return {
status: dispatcherRequest.code,
result: dispatcherRequest.body
};*/
let dispatcherRequest = https.post({
url: `${DISPATCH_API.authObj.baseUrl}/orders/api/add_order`,
headers: {
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryZAPcZR2prPALkJAB',
'api_key': DISPATCH_API.authObj.accounts[dispatch_tracker_account],
},
body: `------WebKitFormBoundaryZAPcZR2prPALkJAB\r\nContent-Disposition: form-data; name=\"code\"\r\n\r\n${DISPATCH_API.authObj.code}\r\n------WebKitFormBoundaryZAPcZR2prPALkJAB\r\nContent-Disposition: form-data; name=\"api_key\"\r\n\r\n${DISPATCH_API.authObj.accounts[dispatch_tracker_account]}\r\n------WebKitFormBoundaryZAPcZR2prPALkJAB\r\nContent-Disposition: form-data; name=\"account\"\r\n\r\n${dispatch_tracker_account}\r\n------WebKitFormBoundaryZAPcZR2prPALkJAB\r\nContent-Disposition: form-data; name=\"data\"\r\n\r\n${data}\r\n\r\n------WebKitFormBoundaryZAPcZR2prPALkJAB--\r\n`,
});
log.debug("createServiceOrder", dispatcherRequest);
if (dispatcherRequest && dispatcherRequest.code == 200)
return {
status: dispatcherRequest.code,
result: xmlParser.xml2json.parser(dispatcherRequest.body)
};
return {
status: dispatcherRequest.code,
result: false
};
},
fetchServiceOrder(service_order_id, dispatch_tracker_account) {
let dispatcherRequest = https.post({
url: `${DISPATCH_API.authObj.baseUrl}/orders/api/export.xml?code=${DISPATCH_API.authObj.code}&api_key=${DISPATCH_API.authObj.accounts[dispatch_tracker_account]}&account=${dispatch_tracker_account}&service_order_id=${service_order_id}`,
headers: {
'Content-Type': 'text/plain',
'api_key': DISPATCH_API.authObj.accounts[dispatch_tracker_account],
},
body: ``,
});
log.debug("fetchServiceOrder", dispatcherRequest);
if (dispatcherRequest && dispatcherRequest.code == 200)
return {
status: dispatcherRequest.code,
result: xmlParser.xml2json.parser(dispatcherRequest.body)
};
return {
status: dispatcherRequest.code,
result: false
};
},
cancelServiceOrder(service_order_id, dispatch_tracker_account) {
let dispatcherRequest = https.post({
url: `${DISPATCH_API.authObj.baseUrl}/orders/api/delete.xml?code=${DISPATCH_API.authObj.code}&api_key=${DISPATCH_API.authObj.accounts[dispatch_tracker_account]}&account=${dispatch_tracker_account}&order=${service_order_id}`,
headers: {
'Content-Type': 'text/plain',
'api_key': DISPATCH_API.authObj.accounts[dispatch_tracker_account],
},
body: ``,
});
log.debug("cancelServiceOrder", dispatcherRequest);
if (dispatcherRequest && dispatcherRequest.code == 200)
return {
status: dispatcherRequest.code,
result: xmlParser.xml2json.parser(dispatcherRequest.body)
};
return {
status: dispatcherRequest.code,
result: false
};
},
},
};
(0, JJ_CM_NS_Utility_1.applyTryCatch)(DISPATCH_API.serviceOrder, 'DISPATCH_API.serviceOrder@JJ CM Dispatch Tracker API AHAP-14');
return DISPATCH_API;
});