Learn how to Automatically add an Attachment to a NetSuite Message Object

NetSuite Technical

Tags: , , ,

This article is relevant if you want to automatically add an attachment to a NetSuite email message object.

Background

We are solving a number of client challenges with our Content Renderer Engine (CRE) which allows you to get much more data to a NetSuite Advanced PDF or HTML template. In many cases, because of the power of this tool, we are replacing the conventional Advanced PDF invoice and other standard transactional objects. Our CRE tool allows you to flexibly create file and email output. A client recently wanted to preserve the native NetSuite message object but they wanted all the goodness of CRE. In this case, they wanted a simple way to ensure that a file attachment was added to the native NetSuite message object so that users could have freedom to craft their own email yet ensure they have branded content as a file attachment.

SuiteScript 1.0 Pattern to Add Attachment to NetSuite Message

The following code pattern can be used as inspiration for any message object that needs a file attachment. At the same time, it illustrates how, with just a few lines of code , you can generate CRE profile based content. In addition, see the code pattern to turn off and hide NetSuite’s default message behavior which will add a transaction attachment.

//------------------------------------------------------------------------------
//Function:		cre_EmailTemplate_BeforeLoad
//Record:		message
//Type:			BeforeLoad
//Description:			On the related transaction, generate the cre attachment and
//				add as attachments to current message
//------------------------------------------------------------------------------
function cre_EmailTemplate_MsgBeforeLoad(type, form, request) {
    //check proper context
	if (type != 'create') return;
    var context = nlapiGetContext();
    if (context.getExecutionContext() != 'userinterface') return;
    if (!request) return;

    // get the query string parameters; this message example only works with transactions
	// ne is a custom function to return back a value if an expression returns back empty
    var recid = ne(request.getParameter("transaction"),'');
    if (recid.length == 0) return;

	//here, we have a custom script parameter holding a JSON structure binding transactions
	//to specific types of CRE profile templates.
    var rectype = nlapiLookupField('transaction', recid, 'type', false);

    var cre_trx_binding = JSON.parse(ne(context.getSetting('SCRIPT', 'custscript_cre_transaction_binding'),'{}'));
    var cre_profileid = cre_trx_binding[rectype];

    //only act on transactions that have a specific binding to CRE
	if (cre_profileid.length == 0) return;

	var error_list = [];

    //produce CRE output (effectively a PDF file)
    try
    {
        var creProfile = new CREProfile(cre_profileid);
        creProfile.Translate(recid);
        creProfile.Execute();
    }
    catch(e)
    {
		var str = "There was trouble generating the CRE file: " + recid + '-->' + cre_profileid; + '; error: ' + e.getCode();
		nlapiLogExecution("ERROR", 'could not create cre ouput', str);
		error_list.push("There was an error creating the CRE file. " + str);
    }

	if (error_list.length > 0){
		return;
	}

	//we should have file output
    var file_obj = null;
    var attachment_list = [];
    var foldername = cre_getFolderName(TEMPLATE_FOLDER_ID);

    if (creProfile.fields.DocumentName.translatedValue) {
        try
         {
          file_obj = nlapiLoadFile(foldername +'/' + creProfile.fields.DocumentName.translatedValue);
         }
         catch(e)
         {
             var str = "There was trouble looking up CRE output file: " + creProfile.fields.DocumentName.Value + '-->' + creProfile.fields.DocumentName.translatedValue; + '; error: ' + e.getCode();
             nlapiLogExecution("ERROR", 'could not create document', str);
             //syntax template does not exist. Return this one.
             error_list.push("There was an error creating the CRE attachment. " + str);
         }
    }

	//get the file object and add it to the attachment list array
    if (file_obj){
        nlapiLogExecution('DEBUG', 'fetched file' + file_obj.getName() + '; id:' +  file_obj.getId() + '; type:' + file_obj.getType() );
        attachment_list.push(file_obj.getId());
    } else {
        nlapiLogExecution('DEBUG', 'Missing fetchd file; return');
        error_list.push("There was an error attaching the CRE file.");
    }

	//add the attachment to the oject
    if (attachment_list.length > 0){
        for (var m=0; m<attachment_list.length; m++){
            nlapiSelectNewLineItem('mediaitem');
            nlapiSetCurrentLineItemValue('mediaitem', 'mediaitem', attachment_list[m]);
            nlapiCommitLineItem('mediaitem');
        }
    } else {
        nlapiLogExecution('DEBUG', 'attachment_list is empty');
        error_list.push("Expected an attachment and found none.");
    }

    // now enhance the default CRE message system to remove the default transaction checkbox so they don't send
    // netsuite's default message.
    var html = "";
    html += '<SCRIPT language="JavaScript" type="text/javascript">\r\n';
    html += "function bindEvent(element, type, handler) {if(element.addEventListener) {element.addEventListener(type, handler, false);} else {element.attachEvent('on'+type, handler);}} \r\n";
    html += "</SCRIPT>\r\n";
    html += '<SCRIPT language="JavaScript" type="text/javascript">\r\n';
    html += "function wload() \r\n{\r\n";
    html += "nlapiSetFieldValue('includetransaction', 'F');\r\n";
    html += "var fld = nlapiGetField('includetransaction');\r\n";
    html += "if (fld){fld.setDisplayType('hidden');};\r\n";
    html += "var fld = nlapiGetField('emailpreference');\r\n";
    html += "if (fld){fld.setDisplayType('hidden');};\r\n";
    if (error_list.length > 0){
        html += "alert('Warning: there appears to be an error fetching attachments. Please review the attachment list before sending.\\n\\n"+error_list.join('\\n')+"');\r\n";
        nlapiLogExecution('ERROR', 'Error fetching attachments', JSON.stringify(error_list));
    }
    html += "}\r\n";
    html += "</SCRIPT>\r\n";
    html += '<SCRIPT language="JavaScript" type="text/javascript">\r\n';
    html += 'bindEvent(window, "load", wload);\r\n';
    html += "</SCRIPT>\r\n";
    var field0 = form.addField('custpage_client_html', 'inlinehtml', '',null, null);
    field0.setDefaultValue(html);
}

Drive NetSuite To Fit Your Specific Requirements

NetSuite’s platform affords us many opportunities to streamline our day-to-day operational usage while increase our capacity to act quickly — this spells into lower cost and higher profits. If you have a unique requirement and wish to get more out the NetSuite platform, let’s have a conversation.

Be Sociable, Share!

Marty Zigman

Holding all three official certifications, Marty is regarded as the top NetSuite expert and leads a team of senior professionals at Prolecto Resources, Inc. He is a former Deloitte & Touche CPA and has held CTO roles. For over 30 years, Marty has produced leadership in ERP, CRM and eCommerce business systems. Contact Marty to set up a conversation.

More Posts - Website - Twitter - Facebook - LinkedIn - YouTube

About Marty Zigman

Holding all three official certifications, Marty is regarded as the top NetSuite expert and leads a team of senior professionals at Prolecto Resources, Inc. He is a former Deloitte & Touche CPA and has held CTO roles. For over 30 years, Marty has produced leadership in ERP, CRM and eCommerce business systems. Contact Marty to set up a conversation.

Biography • Website • X (Twitter) • Facebook • LinkedIn • YouTube

4 thoughts on “Learn how to Automatically add an Attachment to a NetSuite Message Object

  1. onkar gogi says:

    how can I attach a file in the file sublist of any transaction in 2.0. I have tried the below code but its giving error as :”SSS_INVALID_SUBLIST_OPERATION”,”message”:”You have attempted an invalid sublist or line item operation. You are either trying to access a field on a non-existent line or you are trying to add or remove lines from a static sublist.

    Code:
    var attachment_list = new Array();
    attachment_list.push(fileObj.id);
    var nsRecord = record.load({
    type : record.Type.INVOICE,
    id : i_INV_InternalID,
    isDynamic: true
    });
    var lineCount = nsRecord.getLineCount({
    sublistId: ‘mediaitem’
    });
    log.debug(‘lineCount:’,lineCount);
    //return;
    nsRecord.selectNewLine({
    sublistId: ‘mediaitem’
    });

    nsRecord.setCurrentSublistValue({
    sublistId: ‘mediaitem’,
    fieldId: ‘mediaitem’,
    value: attachment_list[0]
    });

    nsRecord.commitLine({
    sublistId: ‘mediaitem’
    });

    var success = nsRecord.save({
    enableSourcing: true,
    ignoreMandatoryFields: true
    });

  2. Marty Zigman says:

    Hello Onkar,

    Sublist operations can be tricky. There are two approaches to use. You may want to try the record.Sublist operation instead of the method you are trying. Here is some SuiteScript 2.0 SuiteLet code where we are in a POST and a file was submitted. We attach it to a purchase order and then we display to the user the name of the file that was submitted.

    if (request.files.file)
    {
    log.debug(request.files.file, request.files.length);
    for (names in request.files.file)
    {
    log.debug(‘file.field:’ + names, request.files.file[names]);
    }

    request.files.file.folder = runtime.getCurrentScript().getParameter({
    name: ‘custscript_pri_trx_app_file_cabinet_loc2’
    });

    request.files.file.name = Date.now() + ‘_’ + request.files.file.name;
    log.debug(request.files.file.folder);

    var internalID = request.files.file.save();

    log.debug(‘file saved’, internalID)
    log.debug(‘tran_id’, tran_id);
    log.debug(‘mode’, mode);

    if (internalID && tran_id) {
    record.attach({
    record: {
    id: internalID,
    type: ‘file’
    },
    to: {
    id: tran_id,
    type: record.Type.PURCHASE_ORDER
    }
    });

    statusFld.defaultValue = ‘Success! ‘ +
    ‘File ‘ + request.files.file.name + ‘ successfully attached to the transaction.
    ‘;
    }
    }

  3. Julius says:

    Hello Marty.

    Thanks for this. Is there a way to automatically include several email addresses in the email window?

    Thanks a lot.

  4. Marty Zigman says:

    I think you would have to manipulate the form via undocumented NetSuite client-side libraries. I have interrogated the email client-side forms (there are two of them) and it is feasible.

    Marty

Leave a Reply

Your email address will not be published. Required fields are marked *