/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define([‘N/record’, ‘N/email’, ‘N/runtime’, ‘N/search’, ‘N/render’],
/**
* @param{record} record
* @param{email} email
* @param{runtime} runtime
* @param{search} search
* @param{render} render
*/
(record, email, runtime, search, render) => {
/**
* Defines the function definition that is executed after record is submitted.
* @param {Object} scriptContext
* @param {Record} scriptContext.newRecord – New record
* @param {Record} scriptContext.oldRecord – Old record
* @param {string} scriptContext.type – Trigger type; use values from the context.UserEventType enum
* @since 2015.2
*/
const afterSubmit = (context) => {
try {
let fulfillmentRecord = context.newRecord;
let fulfillmentId = fulfillmentRecord.id;
let shipStatus = fulfillmentRecord.getValue({
fieldId: “shipstatus”
})
log.debug(“shipStatus”, shipStatus);
// Check conditions: Status changes to “Shipped” or is directly created in “Shipped”
const oldShipStatus = context.oldRecord ? context.oldRecord.getValue({ fieldId: “shipstatus” }) : null;
const isStatusChangedToShipped = (oldShipStatus === “A” || oldShipStatus === “B”) && shipStatus === “C”;
const isDirectlyShipped = !context.oldRecord && shipStatus === “C”;
if (isStatusChangedToShipped || isDirectlyShipped) {
let createdFromSalesorder = checkCreatedFromType(fulfillmentId);
if (createdFromSalesorder > 0) {
let salesOrderId = fulfillmentRecord.getValue({ fieldId: ‘createdfrom’ });
let soNum = fulfillmentRecord.getValue({ fieldId: ‘sonum’ });
// Proceed only if created from a Sales Order
if (!salesOrderId) return;
// Load the associated Sales Order
let salesOrder = record.load({
type: record.Type.SALES_ORDER,
id: salesOrderId
});
// Get Customer ID
let customerId = salesOrder.getValue({ fieldId: ‘entity’ });
// let customerName = fulfillmentRecord.getText({ fieldId: ‘entity’ });
let customerRecord = record.load({
type: record.Type.CUSTOMER,
id: customerId
});
// Check ‘Exclude IF Emails’ field
let customerName = customerRecord.getValue({ fieldId: ‘altname’ });
log.debug(“customerName”, customerName);
let excludeEmails = customerRecord.getValue({ fieldId: ‘custentity_jj_exclude_if_emails’ });
log.debug(“excludeEmails”, excludeEmails);
if (excludeEmails) return; // Exit if the customer opted out of IF emails
// Determine the email address to use
let ifEmailAddress = customerRecord.getValue({ fieldId: ‘custentity_jj_if_email_address’ });
let primaryEmail = customerRecord.getValue({ fieldId: ’email’ });
let emailToSend = ifEmailAddress || primaryEmail; // Use custom IF email if available, otherwise fallback to primary email
if (!emailToSend) return; // Exit if no email address is found
// Email Content
let poNumber = salesOrder.getValue({ fieldId: ‘otherrefnum’ }) || ‘N/A’;
//let shipMethod, shipcarrier;
let itemfulfillmentSearch = itemFulfillmentDetails(fulfillmentId);
log.debug(“itemfulfillmentSearch”, itemfulfillmentSearch);
let shipcarrier = ”;
shipcarrier = itemfulfillmentSearch.shipCarrier;
log.debug(“shipcarrier”, shipcarrier);
let shipMethod = ”;
shipMethod = itemfulfillmentSearch.shipMethod;
log.debug(“shipMethod”, shipMethod);
let items = itemDetails(fulfillmentRecord);
log.debug(“items”, items)
let emailSubject = ”;
let emailBody = ”;
let package = [];
let trackingNumbers = ‘N/A’;
let trackingLinkHtml = ‘N/A’;
let trackingLinks = ‘N/A’;
if ((shipcarrier == ‘nonups’ && shipMethod == “3”) || (shipcarrier == ‘ups’ && shipMethod == “”) || (shipcarrier == ‘nonups’ && shipMethod == “”)) {
let packageCount = fulfillmentRecord.getLineCount({ sublistId: ‘package’ });
log.debug(“packageCount”, packageCount);
for (let i = 0; i < packageCount; i++) {
package.push({
trackingNumber: fulfillmentRecord.getSublistValue({ sublistId: ‘package’, fieldId: ‘packagetrackingnumber’, line: i }),
});
}
log.debug(“package”, package)
trackingLinks = package.map(pkg => {
if (pkg.trackingNumber) {
return `<a href=”https://tools.usps.com/go/TrackConfirmAction_input?strOrigTrackNum=${pkg.trackingNumber}”
style=”color: blue; text-decoration: underline;”>
${pkg.trackingNumber}
</a>`;
} else {
return ‘N/A’;
}
});
log.debug(“trackingLinks”, trackingLinks);
// If you want to display all the links in a single HTML block, join them with line breaks or commas
trackingLinkHtml = trackingLinks.join(‘<br/>’);
log.debug(“trackingLinkHtml”, trackingLinkHtml);
trackingNumbers = package.length > 0 ? package.map(pkg => pkg.trackingNumber).join(‘, ‘) : ‘N/A’;
log.debug(“trackingNumbers”, trackingNumbers);
}
if ((shipcarrier == ‘ups’ && shipMethod == “686”) || (shipcarrier == ‘ups’ && shipMethod == “685”) || (shipcarrier == ‘ups’ && shipMethod == “4”)) {
log.debug(“Inside UPS Handling”, “Handling UPS tracking details”);
let upsTrackingNumbers = trackingNumber(fulfillmentId);
log.debug(“UPS Tracking Numbers”, upsTrackingNumbers);
// Join all UPS tracking numbers into a single query string
let trackingQueryString = upsTrackingNumbers.map((num, index) => `InquiryNumber${index + 1}=${num}`).join(“&”);
// Create the tracking link
trackingLinkHtml = `<a href=”https://www.ups.com/track?TypeOfInquiryNumber=T&${trackingQueryString}”
style=”color: blue; text-decoration: underline;”>
Track Your Packages
</a>`;
trackingNumbers = upsTrackingNumbers.length > 0 ? upsTrackingNumbers.join(“, “) : ‘N/A’;
log.debug(“UPS Tracking Link HTML”, trackingLinkHtml);
log.debug(“Tracking Numbers”, trackingNumbers);
}
let itemHtml = generateItemTable(items);
log.debug(“itemHtml”, itemHtml);
// Send Email
let senderId = –5;
if (shipcarrier == ‘nonups’ && shipMethod == “”) {
let emailTemplate = render.mergeEmail({
templateId: 14,
entity: {
type: ’employee’,
id: senderId
}
});
emailSubject = emailTemplate.subject;
emailBody = emailTemplate.body
.replace(‘{{CUSTOMER_NAME}}’, customerName)
.replace(‘{{PO_NUMBER}}’, poNumber)
.replace(‘{{ITEM_LIST}}’, itemHtml)
.replace(‘{{salesordertranid}}’, soNum);
} else {
let emailTemplate = render.mergeEmail({
templateId: 13,
entity: {
type: ’employee’,
id: senderId
}
});
emailSubject = emailTemplate.subject;
emailBody = emailTemplate.body
.replace(‘{{CUSTOMER_NAME}}’, customerName)
.replace(‘{{PO_NUMBER}}’, poNumber)
.replace(‘{{ITEM_LIST}}’, itemHtml)
.replace(‘{{salesordertranid}}’, soNum);
if (trackingNumbers !== ‘N/A’ && trackingLinkHtml !== ‘N/A’) {
emailBody = emailBody
.replace(‘{{trackingNumbers}}’, trackingNumbers)
.replace(‘{{TRACKING_LINK}}’, trackingLinkHtml);
} else {
// If no tracking info, remove the lines completely
emailBody = emailBody.replace(‘Tracking numbers:’, ”);
emailBody = emailBody.replace(‘Link to tracking information on carrier website:’, ”);
emailBody = emailBody.replace(‘{{trackingNumbers}}’, ”);
emailBody = emailBody.replace(‘{{TRACKING_LINK}}’, ”);
}
}
email.send({
author: runtime.getCurrentUser().id,
recipients: emailToSend,
subject: emailSubject,
body: emailBody,
relatedRecords: {
transactionId: fulfillmentRecord.id
}
});
}
else {
log.debug(“Item Fulfillment is not created from sales order”, “Item Fulfillment is not created from sales order”)
}
}
} catch (e) {
log.error(‘Error Sending IF Email’, e.toString());
}
}
/**
* Function to check the Item fulfillment is created from Sales Order
* @param {fulfillmentId} fulfillmentId – The internal Id of the item Fulfillment
* @returns {searchResultCount} – Search result count
*/
function checkCreatedFromType(fulfillmentId) {
let itemfulfillmentSearchObj = search.create({
type: “itemfulfillment”,
filters:
[
[“type”, “anyof”, “ItemShip”],
“AND”,
[“createdfrom.type”, “anyof”, “SalesOrd”],
“AND”,
[“internalid”, “anyof”, fulfillmentId]
],
columns:
[
search.createColumn({ name: “tranid”, label: “Document Number” }),
]
});
let searchResultCount = itemfulfillmentSearchObj.runPaged().count;
log.debug(“itemfulfillmentSearchObj result count”, searchResultCount);
return searchResultCount;
}
/**
* Function to get the item details
* @param {fulfillmentRecord} fulfillmentRecord – The fulfillment record
* @returns {items}
*/
function itemDetails(fulfillmentRecord) {
//log.debug(“fulfillmentRecord”, fulfillmentRecord);
let itemDisplayName = ‘N/A’;
let item = [];
let itemCount = fulfillmentRecord.getLineCount({ sublistId: ‘item’ });
for (let i = 0; i < itemCount; i++) {
//let itemId = fulfillmentRecord.getSublistValue({ sublistId: ‘item’, fieldId: ‘item’, line: i });
let itemName = fulfillmentRecord.getSublistValue({ sublistId: ‘item’, fieldId: ‘itemname’, line: i });
log.debug(“itemName”, itemName);
itemDisplayName = fulfillmentRecord.getSublistValue({ sublistId: ‘item’, fieldId: ‘displayname’, line: i });
log.debug(“itemDisplayName”, itemDisplayName);
let quantity = fulfillmentRecord.getSublistValue({ sublistId: ‘item’, fieldId: ‘quantity’, line: i });
log.debug(“quantity”, quantity);
let displayName = itemDisplayName || itemName;
if (quantity > 0) {
item.push({
name: displayName,
description: fulfillmentRecord.getSublistValue({ sublistId: ‘item’, fieldId: ‘itemdescription’, line: i }),
quantity: quantity,
});
}
}
return item;
}
/**
* Function to get the tracking number of package
* @param {fulfillmentId} fulfillmentId – The internal Id of the item Fulfillment
* @returns {shippigDetailsa}
*/
function itemFulfillmentDetails(fulfillmentId) {
let shippigDetails = {}; // Object to store the shipping details
let itemfulfillmentSearchObj = search.create({
type: “itemfulfillment”,
filters: [
[“type”, “anyof”, “ItemShip”], // Item Fulfillment type
“AND”,
[“internalid”, “anyof”, fulfillmentId], // Internal ID of the specific Item Fulfillment
“AND”,
[“mainline”, “is”, “T”] // Mainline filter
],
columns: [
search.createColumn({ name: “shipmethod”, label: “Ship Via” }),
search.createColumn({ name: “shipcarrier”, label: “Shipping Carrier” })
]
});
// Execute the search and process the results
let searchResult = itemfulfillmentSearchObj.run().getRange({ start: 0, end: 1 }); // Fetch the first result
if (searchResult && searchResult.length > 0) {
let result = searchResult[0];
shippigDetails.shipMethod = result.getValue({ name: “shipmethod” }) || ”; // Store ship method
shippigDetails.shipCarrier = result.getValue({ name: “shipcarrier” }) || ”; // Store ship carrier
} else {
log.debug(“No results found for the provided fulfillment ID”, fulfillmentId);
}
log.debug(“Item Fulfillment Details”, shippigDetails);
return shippigDetails; // Return the object with shipping details
}
function generateItemTable(items) {
let itemHtml =
`
<table style=”width: 100%; border-collapse: collapse;”>
<thead>
<tr>
<th style=”padding: 8px; text-align: left; background-color: #f0f0f0;”><b>Item</b></th>
<th style=”padding: 8px; text-align: left; background-color: #f0f0f0;”><b>Description</b></th>
<th style=”padding: 8px; text-align: left; background-color: #f0f0f0;”><b>Quantity</b></th>
</tr>
</thead>
<tbody>
${items.map(item => `
<tr>
<td style=”padding: 8px;”>${item.name}</td>
<td style=”padding: 8px;”>${item.description}</td>
<td style=”padding: 8px;”>${item.quantity}</td>
</tr>
`).join(”)}
</tbody>
</table>`;
return itemHtml;
}
/**
* Function to get the tracking number of package
* @param {fulfillmentId} fulfillmentId – The internal Id of the item Fulfillment
* @returns {trackingNumbers} – Return tracking numbers
*/
function trackingNumber(fulfillmentId) {
// Initialize an array to hold tracking numbers
let trackingNumbers = [];
// Create the search for item fulfillment
var itemfulfillmentSearchObj = search.create({
type: “itemfulfillment”,
settings: [{ “name”: “consolidationtype”, “value”: “ACCTTYPE” }],
filters: [
[“type”, “anyof”, “ItemShip”],
“AND”,
[“internalid”, “anyof”, fulfillmentId],
“AND”,
[“mainline”, “is”, “T”]
],
columns: [
search.createColumn({ name: “tranid”, label: “Document Number” }),
search.createColumn({ name: “trackingnumbers”, label: “Tracking Numbers” }),
search.createColumn({
name: “weightinlbs”,
join: “shipmentPackage”,
label: “Weight In Pounds”
})
]
});
// Execute the search and process the results
itemfulfillmentSearchObj.run().each(function (result) {
// Get the tracking numbers field value
let trackingNumberField = result.getValue({ name: “trackingnumbers” });
// Split the tracking numbers if they are comma-separated
if (trackingNumberField) {
let trackingArray = trackingNumberField.split(‘,’);
trackingNumbers = trackingNumbers.concat(trackingArray.map(num => num.trim()));
}
return true; // Continue to the next result
});
log.debug(“trackingNumbers”, trackingNumbers);
// Return the array of tracking numbers
return trackingNumbers;
}
return { afterSubmit }
});