The client would like to attach the drawings of the item stored in the file cabinet to the corresponding item record
Jira Code: GTILC-397
/**
* @NApiVersion 2.1
* @NScriptType MapReduceScript
*/
/*************************************************************************************
***********
* Graph Tech Guitar Labs
*
* GTILC-397 : Automation for adding drawings to its associated items
*
*
*************************************************************************************
***********
*
*
* Author: Jobin and Jismi IT Services LLP
*
* Date Created : 14-July-2023
*
* Description: This script is used to automatically attach drawings pdf to the assembly item record
*
* REVISION HISTORY
*
* @version 1.0 GTILC-397 : 14-July-2023 : Created the initial build by JJ0177
*
*
*************************************************************************************
**********/
define(['N/record', 'N/search', 'N/email', 'N/runtime'],
(record, search, email, runtime) => {
/**
* Function to check whether the field has an empty value or not.
* @param {parameter} parameter - fieldValue
* @returns {boolean} true - if the value is not empty
* @returns {boolean} false - if the value is empty
*/
function checkForParameter(parameter) {
try {
if (parameter != "" && parameter != null && parameter != undefined && parameter != "null" && parameter != "undefined" && parameter != " " && parameter != false && parameter != '' && parameter != ' ') {
return true;
} else {
return false;
}
}
catch (e) {
log.debug({
title: "Error @ empty check Function: ", details: e.name + ' : ' + e.message
});
}
}
/**
* Saved search function to check whether items exist with similar drawings name
* @param drawingPdfName{string}- drawings name
* @returns itemsArray - array containing the items with similar drawings name
*/
function searchItemsWithPdfName(drawingPdfName) {
try {
let itemsArray = [];
let itemSearchObj = search.create({
type: "item",
filters:
[
["type", "anyof", "Assembly"],
"AND",
["name", "contains", drawingPdfName],
"AND",
["custitem_jj_is_attached_gtilc_397", "is", "F"],
"AND",
["isinactive", "is", "F"]
],
columns:
[
search.createColumn({ name: "internalid", label: "Internal ID" })
]
});
itemSearchObj.run().each(function (result) {
let itemId = result.getValue({
name: "internalid",
label: "Internal ID"
})
itemsArray.push(itemId);
return true;
});
return itemsArray;
} catch (error) {
log.debug("error @searchItemsWithPdfName", error);
return [];
}
}
/**
* 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 today = new Date();
let date = String(today.getDate()).padStart(2, '0');
let daysBefore = date - 1;
let month = String(today.getMonth() + 1).padStart(2, '0');
let year = today.getFullYear();
today = month + '/' + date + '/' + year;
let twoDaysBefore = month + '/' + daysBefore + '/' + year;
let fileSearchObj = search.create({
type: "file",
filters:
[
["created", "within", twoDaysBefore, today],
"AND",
["folder", "anyof", "295744"]
],
columns:
[
search.createColumn({
name: "name",
sort: search.Sort.ASC,
label: "Name"
}),
search.createColumn({
name: "internalid",
label: "Internal ID"
})
]
});
let drawingsNameArray = [], drawingsName;
fileSearchObj.run().each(function (result) {
let drawingsObj = {};
drawingsName = result.getValue({
name: "name",
sort: search.Sort.ASC,
label: "Name"
})
let regex = /^(.*?)\s+drawing/;
let match = drawingsName.match(regex);
drawingsObj.newDrawingsName = match ? match[1] : null;
drawingsObj.drawingsId = result.getValue({
name: "internalid",
label: "Internal ID"
})
drawingsNameArray.push(drawingsObj);
return true;
});
return drawingsNameArray;
} catch (error) {
log.debug("error @getInput", error);
}
}
/**
* 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
*/
const reduce = (reduceContext) => {
try {
let missMatchObj = {};
let dataObj = JSON.parse(reduceContext.values[0]);
let drawingsPdfName = dataObj.newDrawingsName;
let drawingPdfId = dataObj.drawingsId;
let pdfNameArray = drawingsPdfName.split("-");
let pdfNameArray1 = pdfNameArray[1];
if (pdfNameArray1.length != 2) {
missMatchObj.missedDrawingPdfName = drawingsPdfName;
}
else {
let isItemsExist = searchItemsWithPdfName(drawingsPdfName);
if (checkForParameter(isItemsExist)) {
for (let i = 0; i < isItemsExist.length; i++) {
record.attach({
record: {
type: 'file',
id: drawingPdfId
},
to: {
type: 'assemblyitem',
id: isItemsExist[i]
}
});
record.submitFields({
type: record.Type.ASSEMBLY_ITEM,
id: isItemsExist[i],
values: {
'custitem_jj_is_attached_gtilc_397': true
},
options: {
enableSourcing: false,
ignoreMandatoryFields: true
}
});
}
}
}
if (checkForParameter(missMatchObj.missedDrawingPdfName)) {
reduceContext.write({
key: 'File error',
value: missMatchObj.missedDrawingPdfName
})
}
} catch (error) {
log.debug("error @reduce", error);
}
}
/**
* 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) => {
let contents = '';
summaryContext.output.iterator().each(function (key, value) {
contents += value + '\n';
return true;
});
email.send({
author: 1143760,
recipients: 'litha.mukunthan@jobinandjismi.com',
subject: 'Inconsistent Drawing File Names Detected',
body: ' Hi,\n\n The file name of Drawings PDF do not follow the desired format. Please review the following files where mismatches have been found:\n' + contents + '\n Thank You'
});
}
return { getInputData, reduce, summarize }
});