/**
*@NApiVersion 2.1
*@NScriptType MapReduceScript
*/
define(['N/search', 'N/record', 'N/runtime', 'N/file', 'N/email'], function (search, record, runtime, file, email) {
const SCRIPT_PARAM = "custscript_grw_005_search_id";
const SCRIPT_PARAM_FOLDER_ID = "custscript_grw_005_csv_folder_id"
const CUST_TO_BE_AUTOINV = "custrecord_grw_005_cust_auto_inv";
const CUST_ORDER_SEARCH = "custrecord_grw_005_order_queue";
const CUST_INV_BATCH_MAP_REC = "customrecord_grw_005_inv_batch_mapping"
const CUST_ADYEN_AMT_OVERRIDE = "custrecord_grw_005_3_amt_override"
const CUST_ADYEN_SUPPRESS_BILL_ADDRESS = "custrecord_grw_005_3_suppres_billaddress"
const CUST_CHILD_REC_CURRENCY = "custrecord_grw_005_4_parent.custrecord_grw_005_4_tran_currency.id"
const CUST_CHILD_REC_ADYEN_PBL_CONFIG = "custrecord_grw_005_4_parent.custrecord_grw_005_4_adn_pbl_config.id"
const ADYEN_AMT_OVERRIDE = "custbody_es_adyen_auth_amount_override"
const ADYEN_SUPPRESS_BILL_ADDRESS = "custbody_es_adyen_suppress_billaddress"
const ADYEN_PAY_BY_LINK_CONFIG = "custbody_es_adyen_pbl_config"
const ADYEN_PAY_BY_LINK_URL_COPY = "custbody_ota_paybylinkurlcopied"
const ADYEN_PAY_BY_LINK_URL = "custbody_es_adyen_pbl_url"
const ADYEN_PAY_BY_LINK_EXPIRES_ON = "custbody_es_adyen_pbl_expiry"
const SO_EXTERNALID = "custbody_ota_salesforcerecordid"
const INV_INVOICE_BATCH = "custbody_ota_invoicebatchcustomer"
const OTA_SF_SYNC_STATUS = "custbody_ota_salesforcesynchstatus"
const SF_SYNC_STATUS_VAL = "1"
const SCRIPT_PARAM_SENDER_ID = "custscript_grw_005_sender_id"
const SCRIPT_PARAM_RECIPIENT_ID = "custscript_grw_005_recipient_id"
function getInputData() {
try {
let savedSeachId = runtime.getCurrentScript().getParameter({ name: SCRIPT_PARAM });
log.debug("savedSeachId", savedSeachId);
let batchMapSeachObj = search.load({ id: savedSeachId });
let batchMapSearchResults = [];
batchMapSeachObj.run().each(function (result) {
let otherField = result.getValue(CUST_TO_BE_AUTOINV);
let orderSearchId;
if (otherField) {
// Get the sales order search ID and any other data you need from the search result
orderSearchId = result.getValue(CUST_ORDER_SEARCH);
}
batchMapSearchResults.push({ orderSearchId });
return true;
});
log.debug("batchMapSearchResults", batchMapSearchResults)
let soDetails = []
for (let index = 0; index < batchMapSearchResults.length; index++) {
let soSearch = batchMapSearchResults[index].orderSearchId
let orderList = getOrderList(soSearch);
if (!isEmpty(orderList)) {
soDetails = soDetails.concat(orderList)
}
}
log.debug("soDetails", soDetails)
return soDetails;
} catch (Err) {
log.debug("Error @getInputData on record save", Err)
log.error("Error @getInputData on record save", Err)
}
}
function reduce(context) {
let successCount = 0
let errCount = 0
let errorMessage = ""
let soId
try {
log.debug("ENTERED REDUCE", "-----------ENTERED REDUCE---------------")
let soKey = context.key;
let orderList = JSON.parse(context.values);
log.debug("orderList", orderList)
soId = orderList.internalId
log.debug("soId", soId)
let soDocNum = orderList.tranId
let soDocDate = orderList.docDate
let extId = (orderList.externalId != "- None -") ? orderList.externalId : ""
let sopblUrl = (orderList.pblUrl != "- None -") ? orderList.pblUrl : ""
let termsId = (orderList.customerTerms == "- None -" || isEmpty(orderList.customerTerms)) ? "" : Number(orderList.customerTerms)
let customerInvBatch = orderList.invBatch
if (soId == "10499") {
try {
let id = record.submitFields({
type: record.Type.SALES_ORDER,
id: soId,
values: {
terms: termsId,
paymentoption: ""
},
options: {
enableSourcing: false,
ignoreMandatoryFields: true
}
});
log.debug("Entered to Transformation of so:", id)
let soRecObj = record.load({
type: record.Type.SALES_ORDER,
id: soId,
isDynamic: true,
});
let soLineCount = soRecObj.getLineCount({
sublistId: 'item'
})
let soArray = []
for (let i = 0; i < soLineCount; i++) {
let solineIndex = i
let soOrderLine = soRecObj.getSublistValue({
sublistId: 'item',
fieldId: 'line',
line: i
});
let soTaxAmt = soRecObj.getSublistValue({
sublistId: 'item',
fieldId: 'tax1amt',
line: i
});
soArray.push({ soOrderLine, soTaxAmt, solineIndex })
}
let invRec = record.transform({
fromType: record.Type.SALES_ORDER,
fromId: id,
toType: record.Type.INVOICE
});
if (soDocNum) {
invRec.setValue({
fieldId: 'tranid',
value: soDocNum
})
}
if (extId) {
invRec.setValue({
fieldId: 'externalid',
value: extId
})
}
if (soDocDate) {
invRec.setText({
fieldId: 'trandate',
text: soDocDate
})
}
if (sopblUrl) {
invRec.setValue({
fieldId: ADYEN_PAY_BY_LINK_URL_COPY,
value: sopblUrl
})
}
if (customerInvBatch) {
invRec.setValue({
fieldId: INV_INVOICE_BATCH,
value: customerInvBatch
})
let tranCurrency = null
tranCurrency = invRec.getValue({ fieldId: 'currency' })
log.debug("transaction Currency", tranCurrency)
let InvMapfieldSearchdata = getMappingRecordData(customerInvBatch, tranCurrency);
log.debug("InvMapfieldSearchdata", InvMapfieldSearchdata)
var foundObj = {}
if (!isEmpty(InvMapfieldSearchdata)) {
foundObj = InvMapfieldSearchdata.find(e => e.pblConfig != null);
if (!isEmpty(foundObj)) {
//To autogenerate Adyen PBL in invoices except in Zero amount invoices.
if (!isEmpty(sopblUrl)) {
let invPblConfig = foundObj.pblConfig
log.debug("invPblConfig", invPblConfig)
if (!isEmpty(invPblConfig)) {
invRec.setValue({
fieldId: ADYEN_PAY_BY_LINK_CONFIG,
value: invPblConfig
})
}
}
}
else {
foundObj = InvMapfieldSearchdata[0]
log.debug("foundObj", foundObj)
}
let adyenAmtOverride = foundObj.amtOverride
if (!isEmpty(adyenAmtOverride)) {
invRec.setValue({
fieldId: ADYEN_AMT_OVERRIDE,
value: adyenAmtOverride
})
}
let invSupBillAddress = foundObj.supBillAddress
if (!isEmpty(invSupBillAddress)) {
invRec.setValue({
fieldId: ADYEN_SUPPRESS_BILL_ADDRESS,
value: invSupBillAddress
})
}
}
}
invRec.setValue({
fieldId: OTA_SF_SYNC_STATUS,
value: SF_SYNC_STATUS_VAL
})
let invLineCount = invRec.getLineCount({
sublistId: 'item'
})
if (!isEmpty(soArray)) {
for (let index = 0; index < invLineCount; index++) {
let invOrderLine = invRec.getSublistValue({
sublistId: 'item',
fieldId: 'orderline',
line: index
});
let obj = soArray.find(obj => obj.soOrderLine == invOrderLine);
log.debug("obj", obj)
//set taxamount if orderline matches or null
if (!isEmpty(obj)) {
invRec.setSublistValue({
sublistId: 'item',
fieldId: 'tax1amt',
line: index,
value: obj.soTaxAmt
});
}
}
}
let invoiceRecId = invRec.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
log.debug("invoiceRecId", invoiceRecId)
if (invoiceRecId) {
successCount++;
errorMessage = true
}
} catch (Errin) {
errCount++;
errorMessage = Errin.message
log.debug("errorCount in Errin", errCount)
log.debug("Errin", errorMessage)
}
}
log.debug("successCount", successCount)
context.write({
key: soId,
value: errorMessage
});
} catch (Err) {
errCount++;
log.error("Error @reduce on record save", Err)
}
}
function summarize(summary) {
log.debug("summary", summary)
let errorDetails = []
let flag = 0
let errCount = 0;
let successCount = 0;
let errorMsg1 = "Failed Transformation for these Orders,Reason\n";
summary.output.iterator().each(function (key, value) {
if (value != true && value != 'true') {
flag = 1
errCount++;
errorDetails.push({ key: key, value: value });
errorMsg1 += (key + ' , ' + value + '\n');
}
else {
successCount++
}
return true;
});
log.debug("errorMsg1", errorMsg1)
log.debug("successCount", successCount)
log.debug("errCount", errCount)
let csvContent = `Success Count,Error Count\n${successCount},${errCount}\n`;
if (flag == 1 || errCount > 0) {
csvContent += errorMsg1;
}
log.debug("csvContent", csvContent)
let fileName = "bill_run_summary" + "_" + Math.floor(Date.now() / 1000) + ".csv";
// Create a file object and save the CSV content
let csvResponseFolder = runtime.getCurrentScript().getParameter({ name: SCRIPT_PARAM_FOLDER_ID });
log.debug("csvResponseFolder", csvResponseFolder)
let fileObj = file.create({
name: fileName,
fileType: file.Type.CSV,
contents: csvContent,
folder: csvResponseFolder,
});
let fileId = fileObj.save();
log.debug('CSV File ID', fileId);
let senderId = runtime.getCurrentScript().getParameter({ name: SCRIPT_PARAM_SENDER_ID });
let recipientId = runtime.getCurrentScript().getParameter({ name: SCRIPT_PARAM_RECIPIENT_ID });
email.send({
author: senderId,
recipients: recipientId,
subject: 'Auto-Invoicing Status Update',
body: "<BR />Hi, <BR/> <BR/>This email is to notify you that Invoice creation has completed. <BR/> Please find the status in the attached document.",
attachments: [fileObj],
relatedRecords: {
entityId: recipientId
}
});
}
function getOrderList(soSearch) {
try {
if (soSearch) {
let orderSeachObj = search.load({ id: soSearch });
let salesOrdersResults = [];
orderSeachObj.run().each(function (result) {
let internalId = result.getValue({
name: "internalid",
summary: "GROUP"
});
let customerId = result.getValue({
name: "entity",
summary: "GROUP"
});
let tranId = result.getValue({
name: "tranid",
summary: "GROUP"
});
let externalId = result.getValue({
name: SO_EXTERNALID,
summary: "GROUP"
});
let pblUrl = result.getValue({
name: ADYEN_PAY_BY_LINK_URL,
summary: "GROUP"
});
let pblUrlExp = result.getValue({
name: ADYEN_PAY_BY_LINK_EXPIRES_ON,
summary: "GROUP"
});
let customerTerms = result.getValue({
name: "terms",
join: "customer",
summary: "GROUP"
});
let invBatch = result.getValue({
name: INV_INVOICE_BATCH,
summary: "GROUP"
});
let docDate = result.getValue({
name: "trandate",
summary: "GROUP"
});
salesOrdersResults.push({ internalId, customerId, tranId, externalId, pblUrl, pblUrlExp, customerTerms, invBatch, docDate })
return true;
});
return salesOrdersResults;
}
else {
return
}
} catch (Err) {
log.debug("Err@getOrderList", Err)
log.error("Err@getOrderList", Err)
}
}
/**
* Find value of Adyen Amount override
* @param {string} invBatchNumber
* @returns
*/
function getMappingRecordData(customerInvBatch, tranCurrency) {
try {
let InvMapfieldLookUp = [];
let InvMapfieldSearchObj = search.create({
type: CUST_INV_BATCH_MAP_REC,
filters: ["name", "is", customerInvBatch],
columns:
[
search.createColumn({ name: CUST_ADYEN_AMT_OVERRIDE }),
search.createColumn({ name: CUST_ADYEN_SUPPRESS_BILL_ADDRESS }),
search.createColumn({
name: "formulatext",
formula: `CASE WHEN {${CUST_CHILD_REC_CURRENCY}} = ${tranCurrency} THEN {${CUST_CHILD_REC_ADYEN_PBL_CONFIG}} ELSE NULL END`
})
]
});
let searchResultCount = InvMapfieldSearchObj.runPaged().count;
log.debug("InvMapfieldSearchObj result count", searchResultCount);
InvMapfieldSearchObj.run().each(function (result) {
let amtOverride = result.getValue(InvMapfieldSearchObj.columns[0])
let supBillAddress = result.getValue(InvMapfieldSearchObj.columns[1])
let pblConfig = result.getValue(InvMapfieldSearchObj.columns[2]) || null
InvMapfieldLookUp.push({ amtOverride, supBillAddress, pblConfig })
return true;
});
return InvMapfieldLookUp;
} catch (Err) {
log.error("Err@getMappingRecordData", Err)
return [];
}
}
function isEmpty(value) {
let isEmptyObject = function (a) {
if (typeof a.length === 'undefined') { // it's an Object, not an Array
let hasNonempty = Object.keys(a).some(function nonEmpty(element) {
return !isEmpty(a[element]);
});
return hasNonempty ? false : isEmptyObject(Object.keys(a));
}
return !a.some(function nonEmpty(element) { // check if array is really not empty as JS thinks
return !isEmpty(element); // at least one element should be non-empty
});
};
return (
value == false
|| typeof value === 'undefined'
|| value == null
|| (typeof value === 'object' && isEmptyObject(value))
);
}
return {
getInputData: getInputData,
reduce: reduce,
summarize: summarize
}
});