Workflow action script to validate filenames uploaded under file tab is in correct format ‘Estimate_PO_1236’ and ‘Invoice_PO_1236’
define([‘N/error’, ‘N/file’, ‘N/record’, ‘N/search’, ‘N/runtime’],
/**
* @param{error} error
* @param{file} file
* @param{record} record
* @param{search} search
* @param{runtime} runtime
*/
(error, file, record, search, runtime) => {
“use strict”;
const requiredEstimate = /^Estimate_PO_d+$/; // Regex for ‘Estimate_PO_12356’
const requiredInvoice = /^Invoice_PO_d+$/; // Regex for ‘Invoice_PO_12356’
/**
* Function to retrieve file names attached to a given Purchase Order (PO) ID.
*
* @param {number} poId – The internal ID or array of internal IDs of the Purchase Order(s).
* @returns {Array} searchResults – An array of file names attached to the specified Purchase Order(s).
* Returns false in case of an error during the execution.
*/
function getFiles(poId) {
try {
let purchaseorderSearchObj = search.create({
type: “purchaseorder”,
filters: [
[“type”, “anyof”, “PurchOrd”],
“AND”,
[“internalid”, “anyof”, poId], “AND”,
[“mainline”, “is”, “T”]
],
columns: [
search.createColumn({
name: “name”,
join: “file”,
label: “Name”
})
]
});
let searchResults = [];
purchaseorderSearchObj.run().each(function (result) {
searchResults.push(result.getValue({ name: “name”, join: “file” })
);
return true;
});
return searchResults;
} catch (e) {
log.error(“error @ getFiles”, e.message);
return false
}
}
/**
*
* Function to validate uploaded files against the required naming format for Estimate documents.
*
* @param {Array} files – Array of file objects.
* @returns {number} – Returns `1` if all files meet the required naming format. *
*/
function validateEstimateFiles(files) {
for (let file of files) {
let fileNameWithoutExt = file ? file.replace(/.[^/.]+$/, ”) : ”;
if (requiredEstimate.test(fileNameWithoutExt) === false) {
throw new Error(`Uploaded file does not match the required format ‘Estimate_PO_<number>’.`);
}
}
return 1;
}
/**
* Function to validate uploaded files against required naming formats for Estimate and Invoice documents.
*
* @param {Array} files – Array of file names or file objects.
* @returns {number} – Returns `1` if both Estimate and Invoice file formats are present.
*
*/
function validateInvoiceFiles(files) {
let foundEstimate = false, foundInvoice = false;
for (let i = 0; i < files.length; i++) {
let fileName = files[i] ? files[i].replace(/.[^/.]+$/, ”) : ”; // Extract file name without extension
if (requiredEstimate.test(fileName)) {
foundEstimate = true;
} else if (requiredInvoice.test(fileName)) {
foundInvoice = true;
} else {
throw new Error(`File does not match the required format. Expected formats: “Estimate_PO_<number>” and “Invoice_PO_<number>”.`);
}
}
if (foundEstimate == true && foundInvoice == true) {
return 1;
} else {
throw new Error(“Both ‘Estimate_PO_<number>’ and ‘Invoice_PO_<number>’ file types are required.”)
}
}
/**
* Defines the WorkflowAction script trigger point.
* @param {Object} scriptContext
* @param {Record} scriptContext.newRecord – New record
* @param {Record} scriptContext.oldRecord – Old record
* @param {string} scriptContext.workflowId – Internal ID of workflow which triggered this action
* @param {string} scriptContext.type – Event type
* @param {Form} scriptContext.form – Current form that the script uses to interact with the record
* @since 2016.1
*/
const onAction = (scriptContext) => {
const scriptObj = runtime.getCurrentScript();
const submissionData = {
estimate: scriptObj.getParameter({ name: ‘custscript_jj_sub_type_est’ }),
invoice: scriptObj.getParameter({ name: ‘custscript_jj_sub_type_inv’ }),
}
let newRecObj = scriptContext.newRecord;
let submissionType = newRecObj.getValue(“custbody_jj_submission_type”);
let validationPassed = true;
let filesData = getFiles(scriptContext.newRecord.id);
if (submissionType === submissionData.estimate) {
validationPassed = validateEstimateFiles(filesData);
}
else if (submissionType === submissionData.invoice) {
validationPassed = validateInvoiceFiles(filesData);
}
else {
log.debug(‘Not Valid Submission Type’);
}
return validationPassed;
}
return { onAction };
});