/**
* @NApiVersion 2.1
* @NScriptType MapReduceScript
*/
/************************************************************************************************
* * Map reduce Script For Creating Quote from Website Data
*
*
* **********************************************************************************************
* BLLF-413: Update- Quote Creation from Website API data
*
* Author: Jobin and Jismi IT Services
*
* Date Created :24 -May-2023
*
* Created By: Linu Paul, Jobin and Jismi IT Services
*
* Description : Map reduce script To create Quote from Website Data
*
* REVISION HISTORY
*
*
***********************************************************************************************/
define(['N/https', 'N/record', 'N/search'],
/**
* @param{https} https
* @param{record} record
* @param{search} search
*/
(https, record, search) => {
"use strict"
/**
* 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 {
let request = https.get({
url: 'https://api.blueleafconnect.com/blueleaf/sandbox/quotes',
headers: {
'Authorization': 'Bearer rdoOdjnTPOkShpSJOix0fMQv8diOHdH2',
'Content-Type': 'application/json',
'Accept': 'application/json',
}
});
let Quote_Details = JSON.parse(request.body);
return Quote_Details;
}
catch (e) {
log.debug(e.message);
}
}
/** Defines the function that is executed to search whether the quote id is already existed.
*
* @param {number} quoteId - the Id of quote to check the existence
*
* */
let request_response = [];
function search_Estimate(quoteId) {
let estimateSearchObj = search.create({
type: "estimate",
filters:
[
["type", "anyof", "Estimate"],
"AND",
["otherrefnum", "equalto", quoteId]
],
columns:
[
search.createColumn({ name: "entity", label: "Name" }),
search.createColumn({
name: "internalid",
join: "customerMain",
label: "Internal ID"
}),
search.createColumn({
name: "internalid",
join: "item",
label: "Internal ID"
}),
search.createColumn({ name: "otherrefnum", label: "PO/Check Number" })
]
}).run().getRange({ start: 0, end: 1 });
return estimateSearchObj;
}
/**
* 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
*/
let customer_Search;
const map = (mapContext) => {
try {
let quoteInfor = JSON.parse(mapContext.value);
let customerId = quoteInfor['account_number'];
let itemId = quoteInfor["variant_code"];
let quotId = quoteInfor["id"];
customer_Search = search.create({ //search for existence of customer
type: search.Type.CUSTOMER,
columns: ['entityid'],
filters: [['entityid', 'is', customerId],"and",["isinactive","is","F"]]
}).run().getRange({ start: 0, end: 1 });
let item_search = search.create({ //search for existence of Item
type: search.Type.ITEM,
columns: ['internalid'],
filters: [['itemid', 'is', itemId],"and",["isinactive","is","F"]]
}).run().getRange({ start: 0, end: 1 });
let iserror = false;
let errormessage = "";
if (customer_Search.length == 0) { // if customer not present
iserror = true;
errormessage = "Invalid Customer Id " + customerId;
log.debug("message", errormessage);
}
if (item_search.length == 0) { // if Item not present
iserror = true;
errormessage = "Invalid item Id " + itemId;
log.debug("message", errormessage);
}
let cusId;
let detail = [];
if (!iserror) {
detail.push(item_search[0].id);
detail.push(quotId);
mapContext.write({
key: customer_Search[0].id,
value: detail
});
let custom_record_search = search.create({
type: "customrecord_jjquotecreationstatus",
filters: ["name", "is", quotId],
columns: ["custrecord_jjerrormessage"]
}).run().getRange({ start: 0, end: 1 });
if (custom_record_search.length > 0) {
let current_customRecord = record.load({
type: "customrecord_jjquotecreationstatus",
id: custom_record_search[0].id
});
current_customRecord.setValue({ fieldId: "custrecord_jjresolved", value: true });
current_customRecord.save({
ignoreMandatoryFields: true
});
}
}
if (iserror) {
let custom_record_search = search.create({
type: "customrecord_jjquotecreationstatus",
filters: ["name", "is", quotId],
columns: ["custrecord_jjerrormessage"]
}).run().getRange({ start: 0, end: 1 });
if (custom_record_search.length > 0) {
let current_customRecord = record.load({
type: "customrecord_jjquotecreationstatus",
id: custom_record_search[0].id
});
current_customRecord.setValue({ fieldId: "custrecord_jjerrormessage", value: errormessage });
current_customRecord.save({
ignoreMandatoryFields: true
})
}
else {
let customRecord = record.create({
type: 'customrecord_jjquotecreationstatus'
});
customRecord.setValue({ fieldId: "name", value: quotId });
customRecord.setValue({ fieldId: "custrecord_jjid", value: quotId });
customRecord.setValue({ fieldId: "custrecord_jjerrormessage", value: errormessage });
customRecord.save({
ignoreMandatoryFields: true
});
}
}
}
catch (err) {
log.error("error@mapfunction", err);
return err.message;
}
}
/**
* 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
*/
let idQuote = []
const reduce = (reduceContext) => {
try {
let i,j;
let reduceKey = reduceContext.key;
let reduceValue = reduceContext.values;
for (i = 0; i < reduceValue.length; i++) {
let parseValue = JSON.parse(reduceContext.values[i]);
for (j = 0; j < parseValue.length; j++) {
if (j == 1) {
idQuote.push(parseValue[j])
}
}
}
let alreadyexists = false;
let estimateSearchObj = search_Estimate(idQuote[0]);// Check for Id existence
if (estimateSearchObj.length > 0) {
alreadyexists = true;
let errormessage = "Quote already Generated for ID " + idQuote[0];
log.debug("message", errormessage);
}
if (!alreadyexists) {
let QuoteRecord = record.create({
type: record.Type.ESTIMATE,
isDynamic: true
});
QuoteRecord.setValue({
fieldId: 'entity',
value: reduceKey
});
for (i = 0; i < reduceValue.length; i++) {
let parseValue = JSON.parse(reduceContext.values[i]);
for (j = 0; j < parseValue.length; j++) {
if (j == 0) {
QuoteRecord.selectNewLine({ //add a line to a sublist
sublistId: 'item' //specify which sublist
});
QuoteRecord.setCurrentSublistValue({ //set item field
sublistId: 'item',
fieldId: 'item',
value: parseValue[j]
});
QuoteRecord.commitLine({ //writes the line entry into the loaded record
sublistId: 'item'
});
}
}
}
QuoteRecord.setValue({
fieldId: 'otherrefnum',
value: idQuote[0]
});
let newQuote = QuoteRecord.save({ //writes record back to database
ignoreMandatoryFields: true
});
let quote_record_info = {
'request_id': idQuote[0],
'status': 'ACCEPTED'
};
request_response.push(quote_record_info);
}
idQuote = [];
reduceContext.write({
key: request_response,
value: request_response
});
}
catch (err) {
log.error("error@reducefunction", err);
return err.message;
}
}
/**
* 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) => {
try {
summaryContext.output.iterator().each(function (key, values) {
let keyDta = JSON.parse(key);
if (keyDta.length > 0) {
log.debug("response date", keyDta);
let response = https.post({
url: 'https://api.blueleafconnect.com/blueleaf/sandbox/quotes',
body: keyDta,
headers: {
'Authorization': 'Bearer rdoOdjnTPOkShpSJOix0fMQv8diOHdH2',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
}
else {
log.debug("No Quote created")
}
return true;
});
}
catch (err) {
log.error("error@summarizefunction", err);
return err.message;
}
}
return { getInputData, map, reduce, summarize }
});