Home SuiteQL: Boms, Assemblies, and Revisions
Post
Cancel

SuiteQL: Boms, Assemblies, and Revisions

Introduction

This post assumes you are using advanced BOMs.

Before tackling how we can use SuiteQL to query BOM components, we need to discuss how we can deduce the active BOM Revision(s) for a given item with SuiteQL.

In NetSuite, Assemblies can have multiple BOMs associated with them. Each BOM can be marked as “Master Default” or can be marked as “Default for Location”. There can be multiple BOMs without either of these fields populated.

Each BOM can have multiple revisions. The active revision is the one that is marked as “Active” and the current date is between the “Start Date” and “End Date” fields on the BOM revision or the current date is more than the start date and there is no effective end date.

There are three tables that we need to discuss in order to understand how NetSuite deduces the active BOM Revision(s) for a given item:

  • BomAssembly
  • BomRevision
  • BomAvailableLocationMap
  • Bom

BomAssembly

This table contains the boms selected for a given item on the “Manufacturing” tab of the item record.

ColumnDescriptionType
canbemasterIndicates whether the item can be used as a master default in an itemBoolean
masterdefaultIndicates whether the item is the master default in an itemBoolean
billofmaterialsThe Bill of Materials selectedInteger (Internal ID)
assemblyThe AssemblyInteger (Internal ID)

BomAvailableLocationMap

This table represents the locations that a given bom is available for use in. This is also selected on the “Manufacturing” tab of the item record.

This table contains only two columns:

ColumnDescriptionType
bomThe Bill of Materials selectedInteger (Internal ID)
locationThe location that the bom is available for use inInteger (Internal ID)

Bom

This table contains the data for the bom itself.

There are many columns such as name, usedonassembly, etc. The only column that we are concerned with is the column BomRevision.

This column contains a comma separated list of the internal IDs of the bom revisions that are associated with the bom. In terms of figuring out which bom revision is active, we need to look at the BomRevision table.

BomRevision

This table contains the data for the bom revision record. It does not contain the components of the bom revision, that is contained in the BomRevisionComponentMember table which we will discuss in a separate post.

The columns relevant to deducing the active bom revision are:

ColumnDescriptionType
bomThe Bill of MaterialsInteger (Internal ID)
effectivestartdateThe date that the bom revision becomes activeDate
effectiveenddateThe date that the bom revision becomes inactiveDate

Writing the query

We’ll assume that we have the internal ID of the location that we want to get the active bom revision for. We will use ${locationid} to represent this value.

First we’ll join the tables that we’ll be needing together Note(we won’t join the BomAvailableLocationMap if we have a masterdefault):

1
2
3
4
FROM BomAssembly
inner join bom on BomAssembly.billofmaterials = Bom.id
inner join BomRevision on BomRevision.billofmaterials = Bom.id
LEFT JOIN BomAvailableLocationMap on BomAvailableLocationMap.bom = Bom.id and Bom.masterdefault = 'F'

Then we’ll filter the results to only include boms that are marked as the master default or are available for the location we are interested in:

1
WHERE (BomAssembly.masterdefault = 'T' OR BomAvailableLocationMap.location = ${locationid})

Then we’ll filter the results to only include boms that are active for the current date:

1
2
3
4
5
AND (
    (BomRevision.effectivestartdate <= SYSDATE AND BomRevision.effectiveenddate IS NULL) OR
    (BomRevision.effectivestartdate <= SYSDATE AND BomRevision.effectiveenddate >= SYSDATE)
    )

Putting it all together:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM
  BomAssembly
  INNER JOIN Bom ON BomAssembly.billofmaterials = Bom.id
  INNER JOIN BomRevision ON BomRevision.billofmaterials = Bom.id
  LEFT JOIN BomAvailableLocationMap ON BomAvailableLocationMap.bom = Bom.id
  AND BomAssembly.masterdefault = 'F'
WHERE
  (
    BomAssembly.masterdefault = 'T'
    OR BomAvailableLocationMap.location = ${locationid}
    AND (
      ( BomRevision.effectivestartdate <= SYSDATE AND BomRevision.effectiveenddate IS NULL) OR
      ( BomRevision.effectivestartdate <= SYSDATE AND BomRevision.effectiveenddate >= SYSDATE)
    )
  )

Now we can select the fields that we want to return (make sure to replace ${locationid} with the internal ID of the location that you want to get the active bom revision for):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT
  BUILTIN.DF(BomAssembly.assembly) AS itemid,
  Bom.name AS bomname,
  BomRevision.name AS BomRevisionname
FROM
  BomAssembly
  INNER JOIN Bom ON BomAssembly.billofmaterials = Bom.id
  INNER JOIN BomRevision ON BomRevision.billofmaterials = Bom.id
  LEFT JOIN BomAvailableLocationMap ON BomAvailableLocationMap.bom = Bom.id
  AND BomAssembly.masterdefault = 'F'
WHERE
  (
    BomAssembly.masterdefault = 'T'
    OR BomAvailableLocationMap.location = ${locationid}
    AND (
      ( BomRevision.effectivestartdate <= SYSDATE AND BomRevision.effectiveenddate IS NULL) OR
      ( BomRevision.effectivestartdate <= SYSDATE AND BomRevision.effectiveenddate >= SYSDATE)
    )
  )

Conclusion

Getting the active bom revision for a given item is a bit more complicated than it seems at first glance. Using a saved search may be simpler for your use case.

I use it primarily when I need to get the components which I usually do with SuiteQL.

This is discussed in the next post

This post is licensed under CC BY 4.0 by the author.

SuiteQL: Budgets Machine

SuiteQL: Bill of Material Components