/**
* @NApiVersion 2.1
* @NScriptType RestLet
* @NModuleScope SameAccount
*/
define(['N/record', 'N/search', 'N/runtime', './moment.js', 'N/format', 'N/email', 'N/error'],
function (record, search, runtime, moment, format, email, error) {
const DOCUMENT_DATE = "custbody_document_date"
const DOCUMENT_PDF_LINK = "custbody_ota_documentpdflink"
const SALESFORCE_RECORD_ID = "custbody_ota_salesforcerecordid"
const SALESFORCE_UPDATED_DATE = "custbody_ota_salesforceupdateddate"
const SALESFORCEURL = "custbody_ota_salesforceurl"
const SALESFORCE_SYNCHED_DATE = "custbody_ota_sfsyncheddate"
const SALESFORCE_TRANSACTION_EMAIL_SENT_DATETIME = "custbody_ota_transactionemailsentdate"
const OTA_SERVICE_PERIOD_START_DATE = "custcol_ota_serviceperiodstartdate"
const OTA_SERVICE_PERIOD_END_DATE = "custcol_ota_serviceperiodenddate"
const OTA_INV_BATCH_CUSTOMER_NO = "custbody_ota_invoicebatchcustomer"
const SO_AUTO_INVOICE = "custbody_grw_005_need_auto_invoicing"
const SO_AUTO_PAYMENT = "custbody_grw_005_need_auto_payment"
const OTA_SF_SYNC_STATUS = "custbody_ota_salesforcesynchstatus"
const SF_SYNC_STATUS_VAL = "1"
const STATUS_REC_TYPE_PARAM = '211';
const STATUS_REC_TYPE = "customrecord_grw_003_rec_intgrn_status"
const STATUS_FLD_TRAN_TYPE = "custrecord_grw_003_tran_type"
const STATUS_FLD_ERROR_MSSG = "custrecord_grw_003_json_response"
const STATUS_FLD_RESQUEST_JSON = "custrecord_grw_003_req_json"
const STATUS_STAT_CODE = "custrecord_grw_003_statuscode"
const ENTITY_INVOICE_BATCH = "custentity_ota_invoicebatch"
const ENTITY_PAYMENTMETHOD = "custentity_ota_paymentmethod"
const ENTITY_TERMS = "terms"
const CUST_INV_BATCH_MAP_REC = "customrecord_grw_005_inv_batch_mapping"
const CUST_TO_BE_AUTOINV = "custrecord_grw_005_cust_auto_inv"
const CUST_TO_BE_AUTOPAID = "custrecord_grw_005_cust_auto_pay"
const SCRIPT_PARAM = "custscript_grw_003_adyn_id"
/**
* Post action data handling and triggers so creation
* @param {*} context - json object request from api call
* @returns
*/
function createSalesOrder(context) {
let responseObj = {};
let requestBody = context
log.debug('requestBody', requestBody);
if (!isEmpty(requestBody)) {
let soObjJson = requestBody //requestBody.Salesorder
log.debug('soObjJson', soObjJson);
let user = runtime.getCurrentUser();
let datePref = user.getPreference({
name: 'DATEFORMAT'
});
log.debug("datePref", datePref)
if (!isEmpty(soObjJson)) {
// Get Currency
let soCurrency = soObjJson.currency
log.debug("soCurrency", soCurrency);
// Get Document Date
let soDocDate = soObjJson.custbody_document_date
if (!isEmpty(soDocDate)) {
soDocDate = moment(soDocDate).format(datePref)
}
log.debug("New soDocDate", soDocDate)
// Get Transaction Date
let soTranDate = soObjJson.tranDate
if (!isEmpty(soTranDate)) {
soTranDate = moment(soTranDate).format(datePref)
}
log.debug("New soTranDate", soTranDate);
// Get Due Date
let soDueDate = soObjJson.dueDate
if (!isEmpty(soDueDate)) {
soDueDate = moment(soDueDate).format(datePref)
}
log.debug("soDueDate", soDueDate);
let soDocPdfLink = soObjJson.custbody_ota_documentpdflink
log.debug("soDocPdfLink", soDocPdfLink);
let soSfRecId = soObjJson.custbody_ota_salesforcerecordid
log.debug("soSfRecId", soSfRecId);
// Get value for Salesforce Updated Date
let soSfUpdateDate = soObjJson.custbody_ota_salesforceupdateddate
if (!isEmpty(soSfUpdateDate)) {
soSfUpdateDate = format.format({ value: new Date(soSfUpdateDate), type: format.Type.DATETIME })
}
log.debug("New soSfUpdateDate", soSfUpdateDate)
let soSfUrl = soObjJson.custbody_ota_salesforceurl
log.debug("soSfUrl", soSfUrl);
// Get value for Salesforce Synched Date field
let soSfSyncDate = soObjJson.custbody_ota_sfsyncheddate
if (!isEmpty(soSfSyncDate)) {
soSfSyncDate = format.format({ value: new Date(soSfSyncDate), type: format.Type.DATETIME })
}
log.debug("New soSfSyncDate", soSfSyncDate)
// Get Data for Salesforce Transaction Email Sent DateTime field
let soEmailSentDate = soObjJson.custbody_ota_transactionemailsentdate
if (!isEmpty(soEmailSentDate)) {
soEmailSentDate = format.format({ value: new Date(soEmailSentDate), type: format.Type.DATETIME })
log.debug("New soEmailSentDate", soEmailSentDate)
}
let soEntity = soObjJson.entity
log.debug("soEntity", soEntity);
let soExternalId
//log.debug("soExternalId", soExternalId);
let soItem = soObjJson.item
log.debug("soItem", soItem);
let soMemo = soObjJson.memo
log.debug("soMemo", soMemo);
let soSubsidiary = soObjJson.subsidiary
log.debug("soSubsidiary", soSubsidiary);
let soTranId = soObjJson.tranId
log.debug("soTranId", soTranId);
let soCostCenter = soObjJson.department
log.debug("soCostCenter", soCostCenter);
if (!isEmpty(soSfRecId)) {
soExternalId = "SO" + soSfRecId
log.debug("soExternalId", soExternalId);
//For duplicate detection using External Id
let extId = soAlreadyExits(soExternalId)
log.debug("extId", extId)
if (!extId) {
let soId = createNSSalesOrder(soCurrency, soDocDate, soDocPdfLink, soSfRecId, soSfUpdateDate, soSfUrl, soSfSyncDate, soEmailSentDate, soDueDate, soEntity, soExternalId, soItem, soMemo, soSubsidiary, soTranDate, datePref, soTranId, soCostCenter)
log.debug("soId", soId)
if (Number.isInteger(soId)) {
responseObj.statusCode = "SUCCESS";
responseObj.recordId = soId;
log.debug("log1", "log1")
return JSON.stringify(responseObj);
}
else {
responseObj.statusCode = "FAILURE";
responseObj.error = soId;
log.debug("log2", "log2")
let statusRecId = createStatusRecord(responseObj, requestBody)
}
}
else {
responseObj.statusCode = "FAILURE";
responseObj.error = "This record already exists";
log.debug("log3", "log3")
let statusRecId = createStatusRecord(responseObj, requestBody)
}
}
else {
responseObj.statusCode = "FAILURE";
responseObj.error = "External Id is missing";
log.debug("log4", "log4")
let statusRecId = createStatusRecord(responseObj, requestBody)
}
}
}
}
/**
* creation of sales order
*/
function createNSSalesOrder(soCurrency, soDocDate, soDocPdfLink, soSfRecId, soSfUpdateDate, soSfUrl, soSfSyncDate, soEmailSentDate, soDueDate, soEntity, soExternalId, soItem, soMemo, soSubsidiary, soTranDate, datePref, soTranId, soCostCenter) {
let soResponse;
try {
let soRecord = record.create({
type: record.Type.SALES_ORDER,
isDynamic: true
});
soRecord.setValue({
fieldId: 'entity',
value: soEntity
});
if (!isEmpty(soEntity)) {
let customerfieldLookUp = getCustomerInfo(soEntity)
log.debug("customerfieldLookUp", customerfieldLookUp)
if (!isEmpty(customerfieldLookUp)) {
let soTerms = customerfieldLookUp[0].entityTerms
log.debug("soTerms", soTerms)
let sobatch = customerfieldLookUp[0].entityBatch
log.debug("sobatch", sobatch)
let soPayMethod = customerfieldLookUp[0].entityPaymentMethod
log.debug("soPayMethod", soPayMethod)
if (!isEmpty(sobatch)) {
soRecord.setValue({
fieldId: OTA_INV_BATCH_CUSTOMER_NO,
value: sobatch
});
let InvMapfieldLookUp = getInvoiceMapInfo(sobatch)
if (!isEmpty(InvMapfieldLookUp)) {
let isAutoInvChecked = InvMapfieldLookUp[0].isAutoInv
log.debug("isAutoInvChecked", isAutoInvChecked)
if (isAutoInvChecked) {
soRecord.setValue({
fieldId: SO_AUTO_INVOICE,
value: isAutoInvChecked
});
}
let isAutoPayChecked = InvMapfieldLookUp[0].isAutoPay
log.debug("isAutoPayChecked", isAutoPayChecked)
if (isAutoPayChecked) {
soRecord.setValue({
fieldId: SO_AUTO_PAYMENT,
value: isAutoPayChecked
});
}
}
}
}
}
if (!isEmpty(soSubsidiary)) {
soRecord.setValue({
fieldId: 'subsidiary',
value: soSubsidiary
});
}
if (!isEmpty(soCurrency)) {
soRecord.setValue({
fieldId: 'currency',
value: soCurrency
});
}
if (!isEmpty(soExternalId)) {
soRecord.setValue({
fieldId: 'externalid',
value: soExternalId
})
}
if (!isEmpty(soTranDate)) {
soRecord.setText({
fieldId: 'trandate',
text: soTranDate
})
}
else {
soRecord.setValue({
fieldId: 'trandate',
value: new Date()
})
}
log.debug("soTranId", soTranId)
if (!isEmpty(soTranId)) {
soRecord.setValue({
fieldId: 'tranid',
value: soTranId
});
}
if (!isEmpty(soCostCenter)) {
soRecord.setValue({
fieldId: 'department',
value: soCostCenter
});
}
try {
if (!isEmpty(soDocDate)) {
soRecord.setText({
fieldId: DOCUMENT_DATE,
text: soDocDate
});
}
if (!isEmpty(soDocPdfLink)) {
soRecord.setValue({
fieldId: DOCUMENT_PDF_LINK,
value: soDocPdfLink
});
}
if (!isEmpty(soSfRecId)) {
soRecord.setValue({
fieldId: SALESFORCE_RECORD_ID,
value: soSfRecId
});
}
if (!isEmpty(soSfUpdateDate)) {
soRecord.setText({
fieldId: SALESFORCE_UPDATED_DATE,
text: soSfUpdateDate
});
}
if (!isEmpty(soSfUrl)) {
soRecord.setValue({
fieldId: SALESFORCEURL,
value: soSfUrl
});
}
if (!isEmpty(soSfSyncDate)) {
soRecord.setText({
fieldId: SALESFORCE_SYNCHED_DATE,
text: soSfSyncDate
});
}
if (!isEmpty(soEmailSentDate)) {
soRecord.setText({
fieldId: SALESFORCE_TRANSACTION_EMAIL_SENT_DATETIME,
text: soEmailSentDate
});
}
if (!isEmpty(soDueDate)) {
soRecord.setText({
fieldId: 'duedate',
text: soDueDate
})
}
if (!isEmpty(soMemo)) {
soRecord.setValue({
fieldId: 'memo',
value: soMemo
})
}
// soRecord.setValue({
// fieldId: OTA_SF_SYNC_STATUS,
// value: SF_SYNC_STATUS_VAL
// })
} catch (e) {
log.debug("Err@skipcustomFields", e)
}
if (!isEmpty(soItem)) {
let soItems = soItem.items
log.debug("soItems", soItems);
if (!isEmpty(soItems)) {
let itemLineCount = soItems.length
log.debug("itemLineCount", itemLineCount);
for (let index = 0; index < itemLineCount; index++) {
let lineItem = soItems[index].item
if (!isEmpty(lineItem)) {
soRecord.selectNewLine({
sublistId: 'item'
});
soRecord.setCurrentSublistValue({
sublistId: 'item',
fieldId: 'item',
value: lineItem,
ignoreFieldChange: false,
forceSyncSourcing: true
});
soRecord.setCurrentSublistValue({
sublistId: 'item',
fieldId: 'quantity',
value: soItems[index].quantity
});
soRecord.setCurrentSublistValue({
sublistId: 'item',
fieldId: 'rate',
value: soItems[index].rate
});
soRecord.setCurrentSublistValue({
sublistId: 'item',
fieldId: 'tax1amt',
value: soItems[index].taxamount
});
try {
let servicePeriodStartdate = soItems[index].custcol_ota_serviceperiodstartdate
if (!isEmpty(servicePeriodStartdate)) {
servicePeriodStartdate = moment(servicePeriodStartdate).format(datePref)
log.debug("servicePeriodStartdate", servicePeriodStartdate)
soRecord.setCurrentSublistText({
sublistId: 'item',
fieldId: OTA_SERVICE_PERIOD_START_DATE,
text: servicePeriodStartdate
});
}
let servicePeriodEnddate = soItems[index].custcol_ota_serviceperiodenddate
if (!isEmpty(servicePeriodEnddate)) {
servicePeriodEnddate = moment(servicePeriodEnddate).format(datePref)
log.debug("servicePeriodEnddate", servicePeriodEnddate)
soRecord.setCurrentSublistText({
sublistId: 'item',
fieldId: OTA_SERVICE_PERIOD_END_DATE,
text: servicePeriodEnddate
});
}
if (!isEmpty(soItems[index].department)) {
soRecord.setCurrentSublistValue({
sublistId: 'item',
fieldId: 'department',
value: soItems[index].department
});
}
} catch (Err) {
log.debug("Errskipcustomlinefields", Err)
}
soRecord.commitLine({
sublistId: 'item'
});
}
}
}
}
let recordID = soRecord.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
log.debug("recordID", recordID);
if (recordID) {
let payId = runtime.getCurrentScript().getParameter({ name: SCRIPT_PARAM });
log.debug("payId", payId);
var id = record.submitFields({
type: record.Type.SALES_ORDER,
id: recordID,
values: {
orderstatus: 'F',
paymentoption: payId,
paymentoperation: "AUTHORIZATION",
handlingmode: "PROCESS"
},
options: {
enableSourcing: false,
ignoreMandatoryFields: true
}
});
}
soResponse = recordID
}
catch (Err) {
soResponse = Err.message;
log.debug("Err@Sales Order Creation", Err)
log.error("Err@Sales Order Creation", Err)
}
return soResponse;
}
/**
* Duplicate validation of transaction using external id
* @param {*} soExtId
* @returns
*/
function soAlreadyExits(soExtId) {
let resultval;
let salesorderSearchObj = search.create({
type: "salesorder",
filters:
[
["type", "anyof", "SalesOrd"],
"AND",
["externalid", "anyof", soExtId]
],
columns:
[
search.createColumn({
name: "internalid",
summary: "GROUP",
label: "Internal ID"
})
]
});
let searchResultCount = salesorderSearchObj.runPaged().count;
log.debug("salesorderSearchObj result count", searchResultCount);
salesorderSearchObj.run().each(function (result) {
resultval = result.getValue({
name: "internalid",
summary: "GROUP",
label: "Internal ID"
});
log.debug("resultval", resultval)
return false;
});
return resultval ? resultval : false;
}
/**
* Custom record creation for error handling
* @param {*} reponseJson
* @param {*} requestBody
* @returns
*/
function createStatusRecord(reponseJson, requestBody) {
let statusRecObj = record.create({
type: STATUS_REC_TYPE,
isDynamic: true
});
statusRecObj.setValue({
fieldId: STATUS_FLD_TRAN_TYPE,
value: "Sales Order Generation API"
});
statusRecObj.setValue({
fieldId: STATUS_FLD_ERROR_MSSG,
value: reponseJson.error
});
statusRecObj.setValue({
fieldId: STATUS_STAT_CODE,
value: reponseJson.statusCode
});
statusRecObj.setValue({
fieldId: STATUS_FLD_RESQUEST_JSON,
value: requestBody
});
let statusRecId = statusRecObj.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
log.debug("statusRecId", statusRecId);
sendEmailNotification(statusRecId)
let missingIdError = error.create({
name: reponseJson.statusCode,
message: reponseJson.error,
notifyOff: true
});
missingIdError.toString = function () { return missingIdError.message };
throw missingIdError;
}
/**
* Send Email if errors blocks transaction creation
* @param {integer} statusRecId
*/
function sendEmailNotification(statusRecId) {
let senderId = runtime.getCurrentUser().id;
let recipientId = -5; //113; // For now we set the receipient Employee JJ Consultant 3, will be updated as -5 later;
let accId = runtime.accountId;
log.debug('Account ID', accId);
let nsBaseUrl = 'https://' + accId + '.app.netsuite.com/app/common/custom/custrecordentry.nl?rectype=';
let recLink = '<a href="' + nsBaseUrl + STATUS_REC_TYPE_PARAM + '&id=' + statusRecId + '"> View Record </a>';
//let recLink = '<a href="' + NS_BASE_URL + STATUS_REC_TYPE_PARAM + '&id=' + statusRecId + '"> View Record </a>';
log.debug("recLink", recLink)
let emailSubject = "Alert: Sales Order Creation API Failure"
let emailBody = "<BR />Hi, <BR/> <BR/>This email is to notify you that a Sales Order Generation triggered from SalesForce is failed exceution. <BR/> Please find the failure reason from the below record" + " " + recLink + "."
email.send({
author: senderId,
recipients: recipientId,
subject: emailSubject,
body: emailBody,
relatedRecords: {
entityId: recipientId
}
});
}
/**
* Information required from Customer record
* @param {integer} soEntity
* @returns
*/
function getCustomerInfo(soEntity) {
try {
let customerSearchObj = search.create({
type: "customer",
filters:
[
["internalidnumber", "equalto", soEntity]
],
columns:
[
search.createColumn({ name: ENTITY_INVOICE_BATCH }),
search.createColumn({ name: ENTITY_PAYMENTMETHOD }),
search.createColumn({ name: ENTITY_TERMS })
]
});
let searchResultCount = customerSearchObj.runPaged().count;
log.debug("customerSearchObj result count", searchResultCount);
let customerLookup = [];
let entityBatch, entityPaymentMethod, entityTerms;
customerSearchObj.run().each(function (result) {
entityBatch = result.getValue(ENTITY_INVOICE_BATCH);
entityPaymentMethod = result.getValue(ENTITY_PAYMENTMETHOD);
entityTerms = result.getValue(ENTITY_TERMS);
customerLookup.push({ entityBatch, entityPaymentMethod, entityTerms });
return true;
});
log.debug("customerLookup", customerLookup)
return customerLookup;
} catch (Err) {
log.debug("Err@getCustomerInfo", Err)
log.error("Err@getCustomerInfo", Err)
}
}
function getInvoiceMapInfo(sobatch) {
try {
let mappingRecSearchObj = search.create({
type: CUST_INV_BATCH_MAP_REC,
filters:
[
["internalidnumber", "equalto", sobatch]
],
columns:
[
search.createColumn({ name: CUST_TO_BE_AUTOINV }),
search.createColumn({ name: CUST_TO_BE_AUTOPAID })
]
});
let searchResultCount = mappingRecSearchObj.runPaged().count;
log.debug("mappingRecSearchObj result count", searchResultCount);
let mappingRecLookup = [];
let isAutoInv, isAutoPay;
mappingRecSearchObj.run().each(function (result) {
isAutoInv = result.getValue(CUST_TO_BE_AUTOINV);
isAutoPay = result.getValue(CUST_TO_BE_AUTOPAID);
mappingRecLookup.push({ isAutoInv, isAutoPay });
return true;
});
log.debug("mappingRecLookup", mappingRecLookup)
return mappingRecLookup;
} catch (Err) {
log.debug("Err@getInvoiceMapInfo", Err)
log.error("Err@getInvoiceMapInfo", Err)
}
}
/**
* validating variable values has value or not
* @param {*} value
* @returns
*/
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 {
'post': createSalesOrder
}
});