Chidi Okwudire IT Professional. ERP Enthusiast. NetSuite Certified (Administrator, SuiteCloud Developer II, and ERP Consultant). Celigo Certified (Level 4+). Passionate About Empowerment Through Knowledge Sharing. Always Eager to Learn.

Learn How to Programmatically Attach a User Note to a Custom Record Without Hardcoding the Record ID

5 min read

Last updated on February 13, 2023.

Challenge

The mission is simple: Via SuiteScript, add a user note to a custom record.

You look up the SuiteScript record browser [I]NetSuite. SuiteScript Records Browser (version 2022.2) for the Note record. Available at: https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2022_2/script/record/note.html. [Accessed: … Continue reading, Google it, or ask ChatGPT and you come up with the following code. (I actually tried ChatGPT for the fun of it; more on that at the end of the article.)

define(['N/record'], function(record) {
    function linkNoteToCustomRecord(customRecordId, noteText) {
        record.create({ type: record.Type.NOTE })
            .setValue('note', noteText)
            .setValue('record', customRecordId)
            .setValue('recordtype', 'customrecord_abc_123')
            .save();
    }

    return {
        linkNoteToCustomRecord: linkNoteToCustomRecord
    };
});

But, surprisingly, you get an error:

You have entered an Invalid Field Value customrecord_abc_123 for the following field: recordtype

It turns out that the recordtype field expects the Internal ID of the record type, not the script ID! Annoyingly, that is not explicit in the documentation and the error message is not very helpful. Anyway, somehow, you figured it out. Thus, the next challenge is getting the custom record type’s internal ID.

NSI Error linking note to custom record explained.

You’re tempted to just go find it from the record customization page (Customization > Lists, Records, & Fields > Record Types) and hardcode it but the voice of your undergrad software design lecturer rings in your head, saying “Hardcoding is a poor software practice, avoid it whenever you can”. Besides that nagging voice in your head, you also that there’s a practical constraint: Internal IDs are environment-specific and chances are that, if this is a new record type that you’ve created in Sandbox, the internal ID might change when you deploy it to Production which will break your code. Essentially, the same problem we’ve described (and solved) before but in a different context.

As a (NetSuite) developer, you should feel uneasy every time you find yourself hardcoding values especially if they are environment-specific. And, if there’s no way around it, be sure to add a comment explaining why it was necessary.

A Better Way

SuiteQL offers a CustomRecordType table [II]Tim Deitrich (August 23, 2021). NetSuite: Use SuiteQL to Query for Custom Record Types and Custom Fields. Available at … Continue reading which you can query to get the internal ID of a custom record:

let customRecordType = query.runSuiteQL({
    query: 
        `SELECT internalid 
         FROM CustomRecordType 
         WHERE scriptid = 'CUSTOMRECORD_ABC_123'`
    // Note: The scriptid must be UPPERCASE
}).asMappedResults()[0].internalid;

You revise your code accordingly and it works!

define(['N/query', 'N/record'], function(query, record) {
    function linkNoteToCustomRecord(customRecordId, customRecordScriptId, noteText) {
        let customRecordType = query.runSuiteQL({
            query: 
                `SELECT internalid 
                FROM CustomRecordType 
                WHERE scriptid = ?`,
            params: [customRecordScriptId.toUpperCase()]
        }).asMappedResults()[0].internalid;

        record.create({ type: record.Type.NOTE })
            .setValue('note', noteText)
            .setValue('record', customRecordId)
            .setValue('recordtype', customRecordType)
            .save();
    }

    return {
        linkNoteToCustomRecord: linkNoteToCustomRecord
    };
});

You’ve quieted the voice in your head by doing the right thing and your future self has one less thing to fuss about. The learning continues…

Learn SuiteQL

I’ve written a few articles about how SuiteQL opens doors to solving problems that previously were difficult or impossible to solve. The list continues to grow. If you are a NetSuite developer and you’re still avoiding learning SuiteQL, you’re limiting yourself.

Related Posts


Experiments with Chat GPT

After solving the problem, I was curious if Open AI’s ChatGPT could have been useful in getting to this solution and if it could have gotten me there faster. Spoiler alert: Mission failed.

ChatGPT’s Take on the Cause of the Error

In trying to understand the cause of the issue, the bot was quite helpful in mentioning that I need a valid internal ID. As an aside, the sample code it claimed to be SuiteScript 2.0 was actually SuiteScript 1.0, and, as far as I know, it is not possible to set the recordtype field on any record. Moreover, the path Setup > SuiteCommerce > Advanced > Record Types is not where you would go to find record types. Nevertheless, I consider this a generally helpful response as it pointed me in the right direction regarding the need for an Internal ID.

ChatGPT provides a reasonable pointer to the cause of the issue.

ChatGPT’s Solutions to the Error

ChatGPT was unable to provide a reasonable answer to the challenge. I tried formulating the question in different ways, to no avail. I aborted the mission after about half a dozen attempts. Here are a few of the interactions.

ChatGPT incorrectly assumes a user note is a custom field on the record.

As an aside, to set a body field, it is more efficient (in terms of performance and governance usage) to use record.submitFields instead of loading and saving the record.

The above answer incorrectly assumes that user notes is a custom field on the custom record. Moreover, it offers an inefficient way to set a field on a record. I figured I needed to formulate the query differently, so I tried the following:

ChatGPT invents a new API for adding notes.

This time, ChatGPT disturbingly offered a non-existent record.addNotes() method to get the job done. Of course, this is invalid. Equally disturbing is the fact that the catch block of the sample code suppresses any errors that might occur. This is poor practice.

Next, I finally got a formulation of the request that got the bot on the right track. But, the answer was still incomplete:

As I mentioned, the above answer is in the right direction in that it creates a note record and even sets the record field. However, running this code will produce no errors but not give the desired result as I explain in the next paragraph. Moreover, the answer does not address the question of getting the record type’s internal ID. Also, notice the inefficiency of loading the custom record to get its ID which we already had and used to load it in the first place!

ChatGPT’s answer above led me to something weird (I think it’s a NetSuite glitch): If you try creating a note without setting record and recordtype (and without setting any other references like transaction or entity), you’ll get the error “You cannot create a standalone note record.” which is reasonable. However, if you set the record but omit the recordtype, you’ll get no error and a standalone note will get created but not attached to the specified record. Clearly, that is not so useful as the note will not be visible on the target record.

define(['N/record'], function(record) {
    function linkNoteToCustomRecord(customRecordId, noteText) {
        record.create({ type: record.Type.NOTE })
            .setValue('note', noteText)
            .setValue('record', customRecordId)
            //.setValue('recordtype', 'customrecord_abc_123')
            // If we set 'record' but not 'recordtype', there wil be no error
            // and a (useless) standalone note will be created.
            .save();
    }

    return {
        linkNoteToCustomRecord: linkNoteToCustomRecord
    };
});

Reflection

While this experiment was not intended to be a comprehensive evaluation of ChatGPT and should not be interpreted as such, a few things come to light:

  1. Writing natural language queries that ChatGPT correctly interprets to produce the right answer is not always trivial.
  2. At this stage, ChatGPT is not strong in handling non-trivial SuiteScript queries.
  3. ChatGPT might produce and/or reinforce anti-patterns based on the sample code it produces e.g. unnecessarily loading and saving records, or suppressing errors in the catch block. These kinds of practices will ultimately produce weaker developers.
  4. ChatGPT sounds confident and authoritative in its explanation of the answers it provides even when they are really off. This is disturbing in a general sense because when anything or anyone sounds very confident while sharing inaccuracies, it often opens the door for deceit.

On AI and the future

There are lots of speculations about how AI-driven solutions like ChatGPT will change the world. It is really not a question of “if” but of “when” and “how”. Regardless of how things unfold, I hope you keep faith in and continue to cultivate what is arguably your most important asset – your mind. The human ability to reason and make assessments should never be underestimated. In the world of the future, I believe this capacity will become even more important in distinguishing quality professionals from others as bots become the authority and more humans trade in their superior capacities for the convenience and perhaps fantasy of AI. In the meantime, keep on honing your skills and applying sound judgment in deciding when to engage the services of bots. And whether you’re getting answers from Google, a bot, or somewhere else, do not apply a solution if you do not understand it.

As a rule of thumb, do not copy/use any (SuiteScript) code fragment if you do not understand how and why it works.

On a personal note, it’s an exciting time to live in and I am curious to see how things unfold. On Chat GPT specifically, I would really love its answers to include references/sources of the information. I’m curious how it came up with the stuff above. I could not find the code samples on Google and I suspect that it actually somehow pieces information out there together to generate its own code (and even define non-existent NetSuite API functions as it deems fit).

If you are a NetSuite manager wondering whether bots offer an alternative to NetSuite professionals, I hope you see that we’re not anywhere close to that. I argue that even as bots get “smarter”, they will not replace high-caliber NetSuite professionals. If you have a NetSuite challenge and need a competent team to talk to, reach out to us at Prolecto Resources Inc.


NetSuite Insights is on a mission to raise the standards around NetSuite practices, one insight at a time. If that resonates with you, learn how you can become an author/collaborator here.

Don’t miss a beat – subscribe to our no-nonsense email list to have these game-changing insights hit your inbox as soon as they’re published. Ignorance? Nah, you’ve got a smarter option. Choose wisdom, choose insights!


Further Reading[+]

Chidi Okwudire IT Professional. ERP Enthusiast. NetSuite Certified (Administrator, SuiteCloud Developer II, and ERP Consultant). Celigo Certified (Level 4+). Passionate About Empowerment Through Knowledge Sharing. Always Eager to Learn.

7 Replies to “Learn How to Programmatically Attach a User Note to a Custom Record Without Hardcoding the Record ID”

    1. Thanks for sharing! Your article addresses the reverse use case of getting the script ID given the internal ID which can also be solved via SuiteQL. I didn’t realize that there is a customrecordtype search.

  1. Hey Chidi, thanks for the article! What do you think about wrapping that in a cache loader to improve performance? Also, any thoughts on error management there? The unconditional reference to [0] is a bit concerning. I only mention it, because you mention similar points later on – I definitely understand sample code is sample code :D, but maybe mentioning those 2 things would help others as they use this article to learn SuiteScripting.

    Thanks for all the information you make available!

    1. Hi Stephen, you have raised good points for readers to contemplate. I opted for brevity over writing production-level code.

  2. Chidi, great article! I love how you write technical articles in a way that laymen (with some reasonable NetSuite knowledge) can understand. I too tested ChatGPT to try to produce SQL queries, and came up disappointed and relieved – disappointed in the bot’s missteps; relieved to see that my brain is not yet obsolete.

Leave a Reply

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

×