Learn NetSuite SuiteScript 2.0 to Process Dynamic Sublists

This article is relevant primarily to a NetSuite SuiteScript developer who would like to be able to create dynamic sublist data and then process user input server side.   However, a business user may be interested to learn how you can receive NetSuite item groups on item receipts.

Background

For a client that is heavily using item groups in its supply chain, inventory and sales operations, they wanted the features of item groups but to hide the complexities of working with it during receiving operations.  Accordingly, we created a mechanism that allows users to perform NetSuite item receipts at the item group level.

The mechanism relies on a couple key structures:

  1. Item Group Receipts: A dynamic “receipts” tab on a NetSuite item receipts record.  This tab allows the user to receive at the item group level.  It is dynamic without an underlying record structure; we create the tab automatically when we draw the item receipt record based on a mapped structure we hold in the related purchase order.  Note, readers may want to follow my article, Understand NetSuite Item Groups vs. Kits to Produce Superior Reporting
  2. User Input Map to Member Items: A beforesubmit user event server side script that unpacks the users “receipts” tab information so that we can map it back to NetSuite’s item group structure and perform a normal item receipt as if the user handled the complex item group member operation themselves.

Video for How To Receive on NetSuite Item Groups

See accompanied video (1:41) to get a feel for how we receive at the item group level.  This will help facilitate your understanding of the work the code snippet is performing.

SuiteScript 2.0 Code to Read Dynamic Sublist Data

The code example below is important to the SuiteScript developer.  Many times, we want to get dynamic information from the user but we do not want an underlying record structure.  In this case, we need sublist data.   What we learned is that in SuiteScript 2.0, the scriptContext object supplied in a BeforeSubmit operation is carrying along the dynamic data submitted by the user; however you can’t access it with NetSuite sublist library operators.  Yet, you can parse the custom sublist information and act on the data as a standard JavaScript object.

In the case below, our sublist is called  “custpage_receipts” and represents the typical way you would bind a dynamic custom sublist into a standard NetSuite form.

/*
 * Expose Item Group Qty from custom 'Receipts' sublist to item
 * 
 * @param {object} scriptContext
 *
 * BeforeSubmit 2.0 Script 
 *
 * Author: Carl Z. Prolecto Resources, Consultant with
 * Marty Zigman
 */

function pri_itemrcpt_exposeItmGrpQty(scriptContext) {

	var currentRecord = scriptContext.newRecord;
	
	// look for the custom "receipts" sublist on the scriptContext object; if there, we have work
	var objCurRec = JSON.parse(JSON.stringify(currentRecord));
	var objSublists = objCurRec.sublists ? objCurRec.sublists : '';
	var objCustReceipts = objSublists.custpage_receipts ? objSublists.custpage_receipts : '';
	
	if (!objCustReceipts) return true;

	// we have receipts data; let's now go to work;
	
	// first, remove the temporary selection of a row on the standard item that we hand
	// to turn on at the client to allow us to submit the record.

	// un-check receive column
	var intLnItemCount = currentRecord.getLineCount('item');
	for (var lnIdx = 0; lnIdx<intLnItemCount; lnIdx++)
		currentRecord.setSublistValue('item', 'itemreceive', lnIdx, false);

	var bolNoReceiptQty = true;
	

	// now review the data provided by the receipts sublist; we are either receiving
	// a native inventory item or an item group which requires special handling

	for (var objLn in objCustReceipts){
		
		// get the quantity received and referece to the PO Line ID so we know 
		// which item we are working on relative to the purchase order.
		var numGrpQtyReceived = objCustReceipts[objLn].custpage_receipts_received;
		var intProdPoLineId = objCustReceipts[objLn].custpage_receipts_polineid;
		
		if(!numGrpQtyReceived || !intProdPoLineId)
			continue;
		
		
		// Get PO Line Member Info via library function as we have stored in our special
		// JSON structure representing a map; 
		var clsProdPoLine = new CNTPMLIB.PRODPOLINE(intProdPoLineId);
		var objPOLnFlds = search.lookupFields({
			type : IDLIB.REC.CNTPRODMGMTLN.ID,
			id : intProdPoLineId,
			columns : [ IDLIB.REC.CNTPRODMGMTLN.HOLDPRICEDATA,
					IDLIB.REC.CNTPRODMGMTLN.ITEMTYPE ]
		});
		var strItemMembData = objPOLnFlds[IDLIB.REC.CNTPRODMGMTLN.HOLDPRICEDATA];
		var arrItemMembData = strItemMembData ? JSON
				.parse(strItemMembData) : null;
		var arrLockedItemStruct = clsProdPoLine.getPoLineLockedStruct(arrItemMembData);
		
		// inspect the structure.  If an item group, then handle; else standard
		// inventory item  

		if (util.isArray(arrLockedItemStruct)) {
			for (var memIdx = 0; memIdx< arrLockedItemStruct.length; memIdx++){
				
				// in this structure, we know the formula to unpack item group member
				// quantities [eg. member group item has 3 quantity; if group receipt is 2, 
				// receive 6]

				var intItemId = arrLockedItemStruct[memIdx].MEMBERITEM;
				var numMemQty = arrLockedItemStruct[memIdx].MEMBERQTY;
				var numReceiveQty = numMemQty * numGrpQtyReceived;
				
				// Set member line checked to receive and place the quantity on the respective
				// NetSuite native item receipt line
				for(var lnIdx = 0; lnIdx<intLnItemCount; lnIdx++){
					
					var intPOLnId_tmp = currentRecord.getSublistValue('item', IDLIB.REC.N_ITEMRCPT.COL_CNTPMPO, lnIdx);
					var intItemId_tmp = currentRecord.getSublistValue('item', 'item', lnIdx);
					if (intPOLnId_tmp != intProdPoLineId || intItemId_tmp !=intItemId)
						continue;
					
					currentRecord.setSublistValue('item', 'itemreceive', lnIdx, true);
					currentRecord.setSublistValue('item', 'quantity', lnIdx, numReceiveQty);
				}
			}

		// we are receiving a native NetSuite inventory item.  Simply pass through the data but
		// respect that we are holding structural data about the nature of the item group

		} else { 
			var intItemId = arrLockedItemStruct.MEMBERITEM;
			var numMemQty = arrLockedItemStruct.MEMBERQTY;
			var numReceiveQty = numMemQty * numGrpQtyReceived;
			
			// Set member line checked to receive
			for(var lnIdx = 0; lnIdx<intLnItemCount; lnIdx++){
				
				var intPOLnId_tmp = currentRecord.getSublistValue('item', IDLIB.REC.N_ITEMRCPT.COL_CNTPMPO, lnIdx);
				var intItemId_tmp = currentRecord.getSublistValue('item', 'item', lnIdx);
				if (intPOLnId_tmp != intProdPoLineId || intItemId_tmp !=intItemId)
					continue;
				
				currentRecord.setSublistValue('item', 'itemreceive', lnIdx, true);
				currentRecord.setSublistValue('item', 'quantity', lnIdx, numReceiveQty);
			}
		}
	}
}

Be Recognized for NetSuite Innovation and Leadership

The article illustrates how we bring valuable innovations to our clients.  Our clients say we think differently; we say “Yes!” when others say “no”.  We can do that because we leverage NetSuite’s platform against a solid of standard of the native built-in capacities.  If you would like to be part of a team that will appreciate you for your unique ability to solve complex NetSuite challenges, 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

| Tags: , | Category: NetSuite, Technical | Leave a comment

Leave a Reply

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