Where do I find additional documentation regarding...
# suitescript
w
Where do I find additional documentation regarding NetSuite Fast-Track Toolkit? I'm trying to add item fields to the SalesOrderBase. The example shows this:
Copy code
class SalesOrder extends so.SalesOrderBase {

      @FieldType.sublist(so.ItemSublist)
      // define a strongly typed item sublist
      item : Sublist<so.ItemSublist>
   }

   var salesorder = new SalesOrder(1234)
   salesorder.item // already a collection of line items with fields defined by so.ItemSublist
If I want to add 'shipgroup' for example, how would I go about that?
s
you need to just derive from
SublistLine
base type and add your fields there. There is a similar example for a
Customer
record and a sublist here https://exploreconsulting.github.io/netsuite-fasttrack-toolkit-ss2/#overview-example
For example
if your goal is adding the 'shipgroup' sublist in a strongly typed way
I didn't see
shipgroup
as a field on the
item
sublist so I assume it's the entire shipgroup sublist you really want?
w
Thanks, I guess I could do the same to get the inventorydetail?
s
InventoryDetailBase
is already defined so you should be able to subclass the so.ItemSublist and add
inventorydetail
as a property
let me grab you an example
w
oh thanks
s
you want to be able to access something like SalesOrder.item[0].inventorydetail (subrecord)?
w
This will be a suitelet to generate a PDF picking ticket, so I will loop thru the lines and grab the details from the SO to print on the PDF
I need to sort by location and shipgroup to clearly show the warehouse staff where to pick from and where to ship to
s
expanding on our previous example, your
SalesOrder.ts
would look something like this.
w
oh so this would be it's own file?
s
It doesn't have to be, but best practice is to put your record type definitions in a single place, we typically put all the class definitions for the sales order under a folder named
RecordTypes
so it would live in
RecordTypes/SalesOrder.ts
w
hey that's a a really good idea I never would have thought of
thanks for your help
s
the reason to have a single representation is it can be easily used by other scripts AND it enforces the fact that there is only one representation of a 'salesorder' logically in the databsae
w
yup I agree
s
so in scripts we just have
import {SalesOrder} from 'RecordTypes/SalesOrder'
w
makes sense!
s
then we're all set to do
const so = new SalesOrder(123)
w
I'll give it a go
👍 1
Can I reach out to you if I run into issues?
s
sure. Writing SuiteScript with NFT is a pleasure compared to the alternatives 🙂
👍 1
the nice thing is this record type definition is only something you do once, then reuse it through that simple import above.
w
I'm just starting to use NFT and Typescript
s
yes, that's a bit ironic in that we were just talking today of moving the actual source internal while still publishing the normal npm package.
w
Open source is probably the way to go
s
it would still be open source (as in, all source available) just not hosted in Github. It's been a bit of a pain to manage the day-to-day NFT source on Github when we host everything else on a different service.
w
oh I see
s
another hint- if you need to sort lines, look to leveraging
_.sortBy()
w
will do. Thank you again
s
one of the big wins with NFT is it makes sublists act as collections for use with libraries like lodash
w
Sorry to bother you, I'm getting the following error:
Copy code
{
  "type": "error.SuiteScriptError",
  "name": "FIELD_1_IS_NOT_A_SUBRECORD_FIELD",
  "message": "Field inventorydetail is not a subrecord field.",
  "stack": [
    "Error",
    " at Object.onRequest (/SuiteScripts/PickingTicketV2/pickingticketV2.js:63:29)"
  ],
  "cause": {
    "name": "FIELD_1_IS_NOT_A_SUBRECORD_FIELD",
    "message": "Field inventorydetail is not a subrecord field.",
    "notifyOff": true
  },
  "id": "",
  "notifyOff": true,
  "userFacing": true
}
Not a subrecord field
s
that's a native netsuite error, so not really NFT related. Most likely you're trying to use 'inventorydetail' in the wrong spot?
If you'd like to share your
SalesOrder.ts
we can take a look
w
Copy code
import { SalesOrderBase, ItemSublist as SalesOrderItemSublist } from '/SuiteScripts/NFT-SS2-7.1.0/DataAccess/SalesOrderBase'
import { Sublist, SublistFieldType, SublistLine } from '/SuiteScripts/NFT-SS2-7.1.0/DataAccess/Sublist'
import { FieldType } from '/SuiteScripts/NFT-SS2-7.1.0/DataAccess/Record'
import { InventoryDetailBase } from '/SuiteScripts/NFT-SS2-7.1.0/DataAccess/InventoryDetailBase'


export class ItemSublist extends SalesOrderItemSublist {

     // shipgroup: string
     @FieldType.subrecord(InventoryDetailBase)
     inventorydetail: InventoryDetailBase
        }

export class ShipGroupSublist extends SublistLine {
    @SublistFieldType.float
    weight: number

    @SublistFieldType.freeformtext
    destinationaddress: string

    @SublistFieldType.freeformtext
    id: string

    @SublistFieldType.freeformtext
    shippingcarrier: string

    @SublistFieldType.freeformtext
    shippingmethod: string
}

export class SalesOrder extends SalesOrderBase {
    @FieldType.sublist(ShipGroupSublist)
    shipgroup: Sublist<ShipGroupSublist>

    @FieldType.sublist(ItemSublist)
    item: Sublist<ItemSublist>
}
I'm also not sure on how to add the shipgroup field to the item sublist
s
at least according to the records browser, I'm not seeing a
shipgroup
field on the item sublist https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2022_2/script/record/salesorder.html
perhaps that's controlled by enabling features in NS - same can be said for the inventorydetail
I don't remember the features off the top of my head but for inventory detail and IIRC for shipgroup you'll need to have features enabled in the NS account. I want to say
shipgroup
needs the Multiple Ship To feature but don't quote me on that.
or maybe it's Multiple Shipping Routes?
w
We use Multiple Ship To, and I have done this in SS1, but it's an older script and needs updating to SS2.
Here is my SS1 code regarding inventorydetail that is currently in use on production:
Copy code
function getInvDetail(record,i) {			//Returns Array of serial numbers from inventorydetail subrecord
	record.selectLineItem('item', i);
	var strItem = record.getCurrentLineItemValue('item', 'item');
	nlapiLogExecution("DEBUG", "strItem", strItem);
	var intCommitted = record.getCurrentLineItemValue('item', 'quantitycommitted');
	nlapiLogExecution("DEBUG", "intCommitted", intCommitted);
	var invDetailSubrecord = record.viewCurrentLineItemSubrecord('item', 'inventorydetail');
	nlapiLogExecution("DEBUG", "invDetailSubrecord", record.viewCurrentLineItemSubrecord('item', 'inventorydetail'));
	if (invDetailSubrecord != null) {
		try {
			var cnt = invDetailSubrecord.getLineItemCount('inventoryassignment');
			nlapiLogExecution("DEBUG", "invDetailSubrecord, cnt", invDetailSubrecord + ', ' + cnt);

			//Get the serial/lot number details
			var sn = [];
			var a = 0;
			for (var j = 1; j <= cnt; j++) {
				invDetailSubrecord.selectLineItem('inventoryassignment', j);
				var serialno = invDetailSubrecord.getCurrentLineItemValue('inventoryassignment', 'issueinventorynumber');
				if (serialno) {
					var strSerial = nlapiLookupField('inventorynumber', serialno, 'inventorynumber');
					nlapiLogExecution('DEBUG', 'Serial# : ' + strSerial);
					sn.push(nlapiEscapeXML(strSerial));
					nlapiLogExecution("DEBUG", 'sn, typeof', sn + ', ' + typeof (sn));
					//nlapiLogExecution("DEBUG",'receipt #: ' + invDetailSubrecord.getCurrentLineItemValue('inventoryassignment','receiptinventorynumber') + ', invassign line# ' + j);
					//nlapiLogExecution("DEBUG",'issue #: ' + invDetailSubrecord.getCurrentLineItemValue('inventoryassignment','issueinventorynumber'));
				}
			}
			return sn;
		}
This is what native SS2 returns when I get the items from the Sales Order record:
Copy code
[
	{
		"item": "3932",
		"inventorydetailavail": "T",
		"isserial": "F",
		"item_display": "3002PGGMN",
		"shipgroup": "1",
		"quantitycommitted": "1700",
		"isnumbered": "T",
		"fulfillable": "true",
		"description": "iClass 16K/16 SE Access Card- J.O'Brien Stock Cards",
		"units_display": "ea",
		"rate": "5.39",
		"quantity": "2500",
		"itemtype": "InvtPart",
		"location": "3"
	},
	{
		"item": "3952",
		"inventorydetailavail": "T",
		"isserial": "F",
		"item_display": "MC-1000",
		"shipgroup": "1",
		"quantitycommitted": "1700",
		"isnumbered": "T",
		"fulfillable": "true",
		"description": "Corporate 1000 Maintenance Fee",
		"units_display": "ea",
		"quantity": "2500",
		"itemtype": "InvtPart",
		"location": "3"
	},
	{
		"item": "3331",
		"inventorydetailavail": "F",
		"isserial": "F",
		"item_display": "8555",
		"shipgroup": "2",
		"isnumbered": "F",
		"fulfillable": "true",
		"description": "Economy Vinyl Strap Clip",
		"units_display": "pk100",
		"rate": "12",
		"quantity": "2500",
		"itemtype": "InvtPart",
		"location": "1"
	},
	{
		"item": "109285",
		"inventorydetailavail": "F",
		"isserial": "F",
		"item_display": "Molex 5/8 Custom Lanyard with All Plastic Clip",
		"shipgroup": "3",
		"isnumbered": "F",
		"fulfillable": "true",
		"description": "Custom Printed 5/8 Inch Tubular Silk Screened Lanyard, 2 Side, 1 Color, Breakaway with All Plastic Clip, Red",
		"units_display": "ea",
		"rate": "1.92",
		"quantity": "2500",
		"itemtype": "InvtPart",
		"location": "3"
	}
]
"shipgroup" and "location" are internal ids on each line item
s
if the output above is just the JSON.stringify() of the native
Record
that's actually undefined and unsupported - in other words you cannot rely on that output as it's not part of the NetSuite API
However, your `SalesOrder`definition looks ok to me. We have lots of code that uses both
inventorydetail
and
inventoryassignment
this way without issue. It's quite pleasant actually to be able to access the main record, subrecord, and subrecord sublist all with simple dot notation and/or lodash methods.
w
@Shawn Talbert I've made some headway with this, thanks for your input. I'm now trying to get the member sublist for kit items on a sales order, but I'm running into an issue where NFT does not recognize a sublist of a sublist. The IDE shows an error :
Property sublist does not exist on typeof SublistFieldType
Copy code
import {SalesOrderBase, ItemSublist as SalesOrderItemSublist} from '/SuiteScripts/NFT-SS2-7.1.0/DataAccess/SalesOrderBase'
import {Sublist, SublistFieldType, SublistLine} from '/SuiteScripts/NFT-SS2-7.1.0/DataAccess/Sublist'
import {FieldType} from '/SuiteScripts/NFT-SS2-7.1.0/DataAccess/Record'
import {InventoryDetailBase, InventoryAssignmentSublist} from '/SuiteScripts/NFT-SS2-7.1.0/DataAccess/InventoryDetailBase'

export class InventoryDetail extends InventoryDetailBase {
    @FieldType.freeformtext
    inventoryassignmentText: string
}

/**
 * 'member' sublist
 */
export class MemberSublist extends SublistLine {
    item: string;
    memberdescr: string;
    memberunit: string;
    quantity: number;
}

export class ItemSublist extends SalesOrderItemSublist {
    @SublistFieldType.sublist       //Property sublist does not exist on typeof SublistFieldType
    member: Sublist<MemberSublist>
    @SublistFieldType.freeformtext
    shipgroup: string
    @SublistFieldType.freeformtext
    item_display: string
    @SublistFieldType.checkbox
    isserial: boolean
    @SublistFieldType.checkbox
    isnumbered: boolean
    @SublistFieldType.freeformtext
    serialnumbers: string
    @SublistFieldType.checkbox
    inventorydetailavail: boolean

    @SublistFieldType.subrecord(InventoryDetail)
    inventorydetail: InventoryDetail
}
Any thoughts?
s
As far as I know, sublists don't have nested sublists in NetSuite.
So again I'd have to ask what leads you to
member
being a sublist on the (documented)`item` sublist? (I don't see it in the records browser)
w
On a kit item, there is a member sublist: https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2022_2/script/record/kititem.html Does that mean I should extend the item class and not the salesorder class?
s
Yes extend AssemblyItemBase - though it should already have the
member
sublist
so
export class AssemblyItem extends AssemblyItemBase {}
and maybe you're all set.
w
It's not an assembly item. We don't have that module
It's a kit item from the Advanced Inventory Module
s
ah, sorry missed that - yes you could define something like
export class KitItem extends Item {...}
w
now, if I'm pulling the item lines from the salesorder, how do I tell it which items are kits, and which are just normal InvtPart (inventory items)
because it seems that it's all one type of item when pulled from the salesorder.item
s
remember
item
sublist lines are NOT item records. But take a look at
itemtype
on that sublist
In general, if you need to get the members for many lines, a (suiteql) search is probably much faster executing and would be generally preferred over loading the item records individually to reach the
member
sublist
w
OK, so is NFT basically loading each item record when it makes these objects?
s
Yes, at least the the NSDAL aspect of NFT, when you do a
new SalesOrder(123)
it's loading NS sales order record 123 - it's really just a thin wrapper around the native NS api
w
Alright. I don't know suiteql. There aren't usually many lines on our sales orders, so loading each record and getting the members shouldn't make it that much slower.
s
your call. I'd recommend perhaps timing it. If you are using NFT's autologging you can easily get timing information from your function calls
w
that's nice
s
in general, we have this boilerplate at the end of our scripts:
// automatically log function entry/exit for diagnostics. Here all functions exported in namespace "X" will autolog LogManager.autoLogMethodEntryExit({ target: X, method: /\w+/ }, { withGovernance: true, })
and we declare interesting functions on a namespace X
this is an example skeleton UE script
w
oh ok cool
s
you can bring up docs in your ide for
autoLogMethodEntryExit
to see all the options (e.g.
withGovernance
etc.)
and to finish that thought - any function you
export
from the
X
namespace will get autologged. So, we break our problems into functions, then export them on
X
to get automagic autologging