Global Searchable External Id

Published January 29, 2023

Getting things started here with one of the more common customizations I've been asked about.
"Can we search for transactions by their external id using the top search bar?"
This tripped me up pretty hard in my early days.

Here I'll show a User Event script that will set a custom text field that has the global search option checked.
In the script, we'll assume that an entity field and a transaction body field have been created and that have the "Global Search" checkbox checked. The script can handle additional custom fields for other record types as well as needed.

I have this script running in CREATE deployment as external ids shouldn't change all that often, and it's good to reduce the amount of User Event scripts where possible.
In a future article, I'll share a Map/Reduce script that will handle external id changes.

Assuming there is an entity and transaction body field created and deployed to the records useful to you, we start with a simple Array of the custom fields you want to set the external id with on create.

The entry point of this script will be afterSubmit(). That's because the external id field is not set yet during beforeSubmit(). We need the record to exist first before we can leverage the external id.

To determine which custom field we want to update we need to leverage the Record.getFields() method. This method will return all the fields on the context.newRecord object. Fun note, if you call this method on the newRecord during an inline edit (XEDIT) it will only return the fields that were part of the update. That can be very painful if you are comparing the newRecord against the oldRecord while trying to determine a delta.

Once we have the custom field we want to set, it's as simple as getting the value and then leveraging my favorite updating method record.submitFields(). record.submitFields() can only make changes to the body level of any record, but it's incredibly cheap compared to a record.load() and a Record.save().

One last note, the reason we can't just leverage a Record.setValue() on the custom field is that the newRecord is read-only during the afterSubmit() entry point. That's why we're leveraging the cheap record.submitFields().

/**
 *@NApiVersion 2.1
 *@NScriptType UserEventScript
 */
define([
    'N/record'
],
    (record) => {
        //Array of the custom external id fields
        const customFields = [
            'custbody_globalexternalid',
            'custentity_globalexternalid'
        ];

        const afterSubmit = context => {
            let newRec = context.newRecord;
            log.audit('Entry Point', `afterSubmit(${context.type})[${newRec.type}][${newRec.id}]`)
            //Preference is this should only be used on CREATE
            if (context.type !== context.UserEventType.CREATE) {
                return;
            }
            //Get the record fields
            let newRecFields = newRec.getFields();
            //Check that the externalid field exists (XEDIT only has fields that were sent in the newRec.getFields())
            if (newRecFields.indexOf('externalid') === -1) {
                return;
            }
            let custFieldIndex = -1;
            //Loop our custom fields and determine if they exist on this record.
            for (let i = 0; i < customFields.length; i++) {
                custFieldIndex = newRecFields.indexOf(customFields[i]);
                if (custFieldIndex > -1) {
                    break;
                }
            }

            //If the custom field exists on the record, let's updated it. Else nothing to do.
            if (custFieldIndex >= 0) {
                //Get the externalid value
                let externalId = newRec.getValue({
                    fieldId: 'externalid'
                });
                log.debug('External Id', externalId);
                try {
                    record.submitFields({
                        type: newRec.type,
                        id: parseInt(newRec.id),
                        values: {
                            [newRecFields[custFieldIndex]]: externalId
                        },
                        options: {
                            enablesourcing: false,
                            ignoreMandatoryFields: true
                        }
                    });
                } catch (e) {
                    log.error('Set Global Ext Id Error', e);
                }
            }
        };

        return {
            afterSubmit: afterSubmit
        };
    }
);