Delete NetSuite Records Utilizing Mass Update

Prior to NetSuite supporting custom scripts on Mass Updates, it was difficult to delete records in bulk.  Since 2009, many NetSuite users in the community have downloaded our NetSuite Bulk Delete Record Utility.  However, with the support of Mass Updates, there is another way to do this that is much more reliable.  The code below is an example program that will remove employees or vendors that were incorrectly assigned to a NetSuite project task.  What is important to see is the pattern used to drive the action.  This pattern can help you develop your own script.  Alternatively, we can help you create a special script for your unique NetSuite delete requirements.

NetSuite Mass Update Utility

The NetSuite Mass Update utility works very similar to a Saved Search.  You define the criteria for which you are searching and the result set is sent to your custom program.   Instead of the entire result set, your program is called once for every record in the result.  The NetSuite governance model allocates the entire 1,000 cycles to one call per record.   This should be sufficient capacity to do the work you need.  For example, if you have 500 records to delete, you will be allotted 500,000 cycles.  Under the traditional model script governance model, you might easily hit the 1,000 limit just looping through your result set before you act on it.  This often is problematic in developing bulk operations via the API.

Instead of giving the exact step-by-step to setup the special Mass Update, I recommend you reference the NetSuite Help Document which provides clear direction on what to do to drive a script.  What is more important is to see our sample script to understand the special work you can do to solve that nasty delete record problem.

Sample Delete Record Program

The following NetSuite program should allow you to see the basic script pattern.  Since this is a one time script, the idea is to watch the NetSuite Script Deployment execution log as it works.  I recommend that you feed only a couple records to your custom script from the Mass Update controller to confirm your script is working well before you give it all the work.

Should you feel that you would like us to build you a custom script, contact us.

//Function: 		MassUpdate_Unwind_TaskAssignees(rec_type, rec_id)
//Record: 		Project Task Assignments
//Script Type: 		Mass update
//Deployment ID:
//Description:  	Remove the Project Task Assignees for each Task passed in that meet these conditions:
//                      1. empty service item
//                      2. actual work = 0
//                      3. estimated work = 0
//                      4. unit cost = 0
//                      that is passed in via the Mass Update controller.
//Input:            The following interface is specified by Mass Update scripts.
//                  rec_type -- the type of record being processed; in this case it always will be project task assignee
//                  rec_id   -- the ID of the record being processed; in this case, it will be the Project Task Assignee ID
//Date:		    SG 20120203
function MassUpdate_Unwind_TaskAssignees(rec_type, rec_id)
    nlapiLogExecution('DEBUG', 'MassUpdate_Unwind_TaskAssignees - starting…');

    perform_update(rec_type, rec_id);

    nlapiLogExecution('DEBUG', 'MassUpdate_Unwind_TaskAssignees - finished.');


function perform_update(rec_type, rec_id) {

    // make sure we are processing correct record type
    if ( rec_type != 'projecttask' ) {
        nlapiLogExecution('DEBUG', 'MassUpdate_Unwind_TaskAssignees should only run for Project Tasks');

    // load up the object
    nlapiLogExecution('DEBUG', 'Load object', rec_type + ' - ' + rec_id);
    var loadedrecord = nlapiLoadRecord(rec_type, rec_id);
    if (!loadedrecord)
        nlapiLogExecution('DEBUG', 'Project Task did not load - ID#' , rec_id);

    // load the project / log the project name
    var projectid = loadedrecord.getFieldValue('company');
    var project_name = '';
    var cust_name = '';
    if (projectid) {
        var loadproj = nlapiLoadRecord('job', projectid);
        if (loadproj) {
            var project_name = loadproj.getFieldValue('companyname');
            var cust_name = loadproj.getFieldText('parent');
             nlapiLogExecution('DEBUG', 'Project' , project_name);
        } else {
            nlapiLogExecution('DEBUG', 'Unable to load project ID', projectid);
    } else {
        nlapiLogExecution('DEBUG', 'ProjectID is empty');

    // loop through each task assignee
    // in reverse order so we preserve the sequence when we remove -- i.e., remove last ones first
    var delete_count = 0;
    var assignee_count = loadedrecord.getLineItemCount('assignee');
    nlapiLogExecution('DEBUG', 'Assignee count', assignee_count);
    for ( var assigneecounter = assignee_count; assigneecounter > 0 ; assigneecounter-- )

        // if the service item has a value for this assignee, skip it
        var service_item = loadedrecord.getLineItemValue('assignee', 'serviceitem', assigneecounter);
        if (!service_item) {
        nlapiLogExecution('DEBUG', 'Service item', service_item);
        if (service_item.length > 0) {

        // if there is estimated work for this assignee, skip it
        var est_work = loadedrecord.getLineItemValue('assignee', 'estimatedwork', assigneecounter);
        if (!est_work) {
            est_work = 0;
        nlapiLogExecution('DEBUG', 'Est Work', est_work);
        if (parseFloat(est_work) > 0) {

        // at this point, we have an assignee to remove
        nlapiLogExecution('DEBUG', 'Getting ready to delete assignee row (assigneecounter):', assigneecounter);
        //nlapiLogExecution('DEBUG', 'right here we would run:', 'loadedrecord.removeLineItem(\'assignee\', ' + assigneecounter + ');')
        loadedrecord.removeLineItem('assignee', assigneecounter);
        nlapiLogExecution('AUDIT', 'Deleted task assignment', cust_name + '\r\n' + project_name + '\r\n' + resource_name + '\r\n' + loadedrecord.getFieldValue('title') + '\r\n loadedrecord.removeLineItem(\'assignee\', ' + assigneecounter + ');')


      // update the task record if necessary
      if ( delete_count > 0 ) {
        nlapiLogExecution('AUDIT', 'SubmitRecord. delete_count:', delete_count)
        nlapiSubmitRecord( loadedrecord );



Be Sociable, Share!

Marty Zigman

Holding all three official certifications, Marty is Southern California's 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 25 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 - Google Plus - YouTube

| Tags: , , , , , , , , , , , , , , , , , , , | Category: NetSuite, Technical | 3 Comments

One Comment

  1. Posted February 17, 2012 at 6:20 am | Permalink

    I have used the same concept before using the following script.

    function delete_records(rec_type, rec_id)
    nlapiDeleteRecord(rec_type, rec_id); // load current record object

    It’s very simple and you need to deploy it to the record types you decide to operate on when setting up the mass update script types.

    Caution, if to execute the mass update there is no rolling back the data. Marty’s script includes extra validation which is more prudent approach. My script above only delete’s one type of record at a time.

    Posted by David Rowley in LinkedIn Discussion

2 Trackbacks

  1. […] Delete NetSuite Records Utilizing Mass Update […]

  2. […] of weeks ago, I read a blog post by Marty Zigman on Delete NetSuite Records Utilizing Mass Update. ¬†His post actually provides a very good explanation on how Mass Update process works in […]

Post a Comment

Your email is never published nor shared. Required fields are marked *


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>