define([‘N/search’, ‘N/record’], function(search, record) {
function getInputData() {
return search.create({
type: “itemfulfillment”,
filters: [
[“type”, “anyof”, “ItemShip”],
“AND”,
[“status”, “anyof”, “ItemShip:C”],
“AND”,
[“taxline”, “is”, “F”],
“AND”,
[“shipping”, “is”, “F”],
“AND”,
[“cogs”, “is”, “F”],
“AND”,
[“createdfrom”, “anyof”, “2898721”],
“AND”,
[“mainline”,“is”,“T”],
“AND”,
[“createdfrom.status”,“noneof”,“SalesOrd:G”],
“AND”,
[“createdfrom.type”,“anyof”,“SalesOrd”]
],
columns: [
search.createColumn({ name: “createdfrom”, label: “Created From” }),
search.createColumn({ name: “tranid”, label: “Document Number” }),
search.createColumn({ name: “statusref”, label: “Status” }),
search.createColumn({ name: “item”, label: “Item” }),
search.createColumn({ name: “quantity”, label: “Quantity” }),
search.createColumn({ name: “line”, label: “Line ID” }),
search.createColumn({ name: “lineuniquekey”, label: “Line Unique Key” })
]
});
}
function map(context) {
let searchResult = JSON.parse(context.value);
log.debug(“searchResult”,searchResult);
let createdFrom = searchResult.values.createdfrom.value;
context.write({
key: createdFrom,
value: searchResult
});
}
function reduce(context) {
let salesOrderId = context.key;
let fulfillments = context.values.map(function(value) {
return JSON.parse(value);
});
try {
// Log the sales order ID we are transforming
log.debug(‘Transforming Sales Order’, ‘Sales Order ID: ‘ + salesOrderId);
let invoice = record.transform({
fromType: record.Type.SALES_ORDER,
fromId: salesOrderId,
toType: record.Type.INVOICE
});
let invoiceLines = invoice.getLineCount({ sublistId: ‘item’ });
log.debug(‘Invoice Line Count’, ‘Invoice Lines: ‘ + invoiceLines);
// Load the sales order to access its lines
let salesOrder = record.load({
type: record.Type.SALES_ORDER,
id: salesOrderId
});
let salesOrderLines = salesOrder.getLineCount({ sublistId: ‘item’ });
// Object to store quantities based on order line
let orderLineQuantities = {};
// Sum quantities based on order lines encountered in item fulfillments
for (let j = 0; j < fulfillments.length; j++) {
let fulfillment = record.load({
type: record.Type.ITEM_FULFILLMENT,
id: fulfillments[j].id
});
let fulfillmentLines = fulfillment.getLineCount({ sublistId: ‘item’ });
for (let k = 0; k < fulfillmentLines; k++) {
let orderline = fulfillment.getSublistValue({
sublistId: ‘item’,
fieldId: ‘orderline’,
line: k
});
let quantity = fulfillment.getSublistValue({
sublistId: ‘item’,
fieldId: ‘quantity’,
line: k
});
if (orderLineQuantities.hasOwnProperty(orderline)) {
// If order line already encountered, add quantity to existing sum
orderLineQuantities[orderline] += quantity;
} else {
// If order line encountered for the first time, initialize the sum
orderLineQuantities[orderline] = quantity;
}
// Add debug log to track quantities being accumulated
log.debug(‘Order Line: ‘ + orderline, ‘Quantity: ‘ + quantity + ‘, Accumulated Quantity: ‘ + orderLineQuantities[orderline]);
}
}
// Set total quantity to the corresponding invoice line if order line matches
for (let i = 0; i < invoiceLines; i++) {
let invoiceLineId = invoice.getSublistValue({
sublistId: ‘item’,
fieldId: ‘orderline’,
line: i
});
// Check if the order line is found in the accumulated quantities
if (orderLineQuantities.hasOwnProperty(invoiceLineId)) {
let totalQuantity = orderLineQuantities[invoiceLineId];
// Find the corresponding line in the Sales Order
for (let m = 0; m < salesOrderLines; m++) {
let salesOrderLineId = salesOrder.getSublistValue({
sublistId: ‘item’,
fieldId: ‘line’,
line: m
});
if (salesOrderLineId == invoiceLineId) {
// Get the value from the Sales Order line field
let salesOrderLineFieldValue = salesOrder.getSublistValue({
sublistId: ‘item’,
fieldId: ‘quantitybilled’, // Replace with the actual field ID from Sales Order
line: m
});
// Subtract this value from the total quantity
totalQuantity -= salesOrderLineFieldValue;
log.debug(‘Adjusted Quantity for Invoice Line’, ‘Original Quantity: ‘ + orderLineQuantities[invoiceLineId] + ‘, Sales Order Line Field Value: ‘ + salesOrderLineFieldValue + ‘, Adjusted Quantity: ‘ + totalQuantity);
break;
}
}
// Set the adjusted quantity on the Invoice line
invoice.setSublistValue({
sublistId: ‘item’,
fieldId: ‘quantity’,
line: i,
value: totalQuantity
});
} else {
log.debug(‘No Match Found for Invoice Line’, ‘Removing Line’);
invoice.removeLine({
sublistId: ‘item’,
line: i
});
}
}
log.debug(‘Before Save Invoice’, ‘Attempting to save invoice’);
let invoiceId = invoice.save({ignoreMandatoryFields: true});
log.debug(‘Invoice Created’, ‘Invoice ID: ‘ + invoiceId);
} catch (e) {
// Log detailed error message
log.error(‘Error Transforming Sales Order to Invoice’, ‘Sales Order ID: ‘ + salesOrderId + ‘, Error: ‘ + e.name + ‘ – ‘ + e.message);
}
}
function summarize(summary) {
log.audit(‘Summary’, ‘Usage Consumed: ‘ + summary.usage);
log.audit(‘Summary’, ‘Concurrency: ‘ + summary.concurrency);
log.audit(‘Summary’, ‘Number of Yields: ‘ + summary.yields);
summary.output.iterator().each(function(key, value) {
log.audit(‘Reduce Result’, ‘Key: ‘ + key + ‘, Value: ‘ + value);
return true;
});
if (summary.inputSummary.error) {
log.error(‘Input Error’, summary.inputSummary.error);
}
summary.mapSummary.errors.iterator().each(function(key, error) {
log.error(‘Map Error’, ‘Key: ‘ + key + ‘, Error: ‘ + error);
return true;
});
summary.reduceSummary.errors.iterator().each(function(key, error) {
log.error(‘Reduce Error’, ‘Key: ‘ + key + ‘, Error: ‘ + error);
return true;
});
}
return {
getInputData: getInputData,
map: map,
reduce: reduce,
summarize: summarize
};
});