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 Powerful Pattern to Create Rich Links Between Related Transactions

6 min read

NetSuite natively supports linking related transactions, typically via the “Related Records” subtab. This article addresses cases where custom bi-directional links need to be established between related transactions and be visible from both sides without producing duplicate subtabs for the linkage. The pattern described, once understood, can easily be applied to any other record type.

TL;DR

Here’s a snippet of the final result, compared to an alternative approach that captures less information but may be sufficient in some scenarios.

Linked transaction approaches illlustrated

Challenge

If you are already familiar with NetSuite’s powerful “Record is Parent” paradigm[I]NetSuite (March 4, 2011). Parent-Child Record Relationships. Available at: https://netsuite.custhelp.com/app/answers/detail/a_id/10149. [Accessed on November 30, 2021], you will know that NetSuite “automagically” produces a sublist of the child record instances under the parent record when this option is checked. If this does not yet make sense to you, hang on; the pattern will become clearer by the time you get to the end of this article. SuiteAnswers ID 10149 also provides detailed coverage of Parent-Child relationships in NetSuite.

I have run into various situations where a bi-directional link between multiple records is very helpful to a business. For example, finance users might need to perform manual reclassing of transactions. In such cases, it is useful to establish a link between the source transaction and the reclass entry. In a project that I worked on some years ago, the business needed a way to capture informal relationships between customers (e.g. “neighbors”, “family members”, “previous owner of the installation”, etc.). While these links were primarily intended for “small talk” with the customer when on the phone, the links captured useful information that could drive marketing analytics, for example.

The “Record is Parent” approach can be leveraged to link records of different types as well as multiple instances of the same record type. What makes the latter kind of linkage tricky though is that NetSuite ends up drawing two sublists, one for each side of the link as illustrated below. This approach often leaves users confused as it is unclear why there are two subtabs for the same thing and where to check to see if there’s a link. (Tip: If you go with this approach, you’ll need to instruct your users to look out for the tiny dot next to the sublist header which will only be shown when there are entries in that sublist.)

Duplicate subtab issue illustrated
Illustration of duplicate subtabs issue

Solution

The good news is that we can achieve a bi-directional linkage of records of the time, ensure that the link is visible from both sides, and not have duplicate subtabs. Here’s the solution I came up with.

Step 1: Create a Custom Record to Define the Relationship

We use a custom record to capture the relationship (there’s another common approach that we’ll highlight later).

Below is a reference implementation of such a Linked Transactions custom record. The basic fields are the source Transaction, the Related Transaction(s), and the Relationship type (which is driven by a Custom List). I have defined the Related Transaction(s) as a multi-select field to enable one-to-many relationships in a single entry. If this is not desirable, use a single select field instead.

A reference Linked Transactions custom record

The All Transactions Field

In a naïve implementation, we would mark both Transaction and Related Transaction(s) fields as “Record is Parent”. However, this will produce duplicate sublists as illustrated earlier, which we do not want. Marking just one of them is also undesirable as it will limit the visibility of the link to one side thereby causing even more confusion.

Configuration of the “All Transactions” field

To address this concern, we introduce an “All Transactions” field as illustrated above. This field is intended to capture all transactions from both sides. We check the “Record is Parent” option only on this field. Once we can add all the transactions involved in the link to this field (see step 2), we ensure that the link will be visible from all sides.

Fun fact: The first time I created a record linking solution a few years ago, I did not have this insight and I was pretty annoyed by the fact that I ended up with two subtabs and needed to train users on how to figure out which one has data by looking out for small dot. While I was working on a similar challenge recently, this idea just popped into my head! That’s one of the reasons I love working with NetSuite, there’s always something new to learn if you’re curious!

NetSuite is a powerful and extensible platform with so many gems waiting to be uncovered. Keep exploring, keep learning, and keep sharing! Click To Tweet

Step 2: Create a Simple Script to Ensure Visibility of the Relationship From All Sides

Once we have the record set up, all that is left is a way to populate the All Transactions field and make sure it is kept up-to-date whenever changes are made to the link. We cannot depend on or burden end-users with this responsibility. Instead, we create a simple user event script that populates this field. The code is remarkably simple!

function beforeSubmit(context) {
	if (context.type === context.UserEventType.DELETE || context.type === context.UserEventType.XEDIT) {
		return;
	}

	const rec = context.newRecord;
	const sourceTrx = rec.getValue('custrecord_nsi_linked_trx');
	const relatedTrx = rec.getValue('custrecord_nsi_linked_trx_related');

	// Copy all linked transactions into the "all transactions" field which drives the
	// sublist. This ensures that all transactions are visible from both sides regardless
	// of the side from which the link was originally created.
	rec.setValue('custrecord_nsi_linked_trx_all', [sourceTrx].concat(relatedTrx));
}

In a proper implementation, you’ll likely want to do some validation as well as mimic NetSuite’s behavior around inlining the source field when links are added from the sublist using the “New NSI Linked Transactions” button. Since we use the All Transactions field as our record is parent key, NetSuite’s default logic of populating and inlining the source Transaction field won’t trigger. The following code handles that (though I must add that this is purely cosmetics and is not required from a functional perspective).

function beforeLoad(context) {
	if (context.type === context.UserEventType.CREATE || context.type === context.UserEventType.COPY) {
		const rec = context.newRecord;
		var allTrx = rec.getValue('custrecord_nsi_linked_trx_all');

		if (allTrx.length === 1) {
			// This will happen if the link was triggered from the sublist on a transaction record.
			// In that case, we mimic NetSuite's behavior of populating and making the source field read-only.
			// Note that the actual source field (record is parent) is the hidden all trx field so we have to get the value from there.
			rec.setValue('custrecord_nsi_linked_trx', allTrx[0]);

			var sourceTrxField = context.form.getField({
				id: 'custrecord_nsi_linked_trx'
			});

			if (sourceTrxField) {
				sourceTrxField.updateDisplayType({
					displayType: serverWidget.FieldDisplayType.INLINE
				});
			}

			log.debug(arguments.callee.name, 'Successfully mimicked NS source-field behavior for record created via "New XXX" sublist button');
		}
	}
}

A Word About Link Types

It is completely up to you to define link types that match your business needs. What I have found useful is to define relationships that are: (1) not too specific; and (2) directionless/applicable in both directions, as they read better. For example, if capturing a relationship between family members, “Sibling” would read better from both sides than “Brother” or “Sister”.

Additionally, it is common to define an “Other” relationship type as a catch-all. This could become a slippery slope. Here’s my take:

  • If you add an “Other” option, be sure to make the description field mandatory so users are at least forced to say something about this custom relationship.
  • Review this description from time to time; typically new relationship types will emerge that need to be added to the list.
  • If you can, avoid catch-all options because they often bite later when it comes to analytics (even if you add the mandatory description, analytics on free-form text is often much harder than on a well-defined list). Instead, if a user needs to create a new relationship type, encourage them to reach out to have the new option added to the list.

An Alternative Approach: Using A Good Old Custom Field

While the solution described above is rich and somewhat more involved, there are use cases where all you need is “a good old custom field”. In that case, all you need is a Related Transactions transaction body custom field of type List/Record or Multiple Select. I see this approach used quite often and there is nothing wrong with it if it meets the needs. However, my experience is that businesses quickly realize that this approach is very limiting.

Both approaches illustrated

Comparison of Approaches Discussed

Here’s a quick comparison to help you decide on which approach to take for your next record linking task:

FunctionalityUsing Custom FieldUsing Linked Transactions Pattern
Links to existing can be added during creation of a new transaction.Yes

Since a body field is used, it can be directly set during transaction creation.
No

NetSuite does not show “Record is Parent” sublists until the transaction is saved.
In case of multi-select related transactions, individual transactions can be opened by clicking the links (see screenshot above for illustration).Yes

Each transaction is shown on a separate line and clickable without issues.
No

Clicking the link produces an error. This is a known annoyance with multi-select fields in NetSuite sublists.
Links can be added after the fact, even when a transaction is locked for editing (e.g. approved or posted to a locked period).No

If the transaction cannot be edited, the link cannot be edited too as it is a body field.
Yes

Links are captured via a custom record and can be created or edited independent of the statuses of the transactions that they link together.
Links are visible from both sides.No

By default, this approach produces a uni-directional link which is often problematic. Scripting can be employed to address this but such scripts are also often tricky to write and maintain.
Yes

Additionally, by applying the “All Transactions” pattern described in this article, we can avoid the duplicate subtab issue.
Rich information such as link type can be easily captured.No

The best offer here is a multi-select field that allows linking multiple transactions. However, the user is left to infer the link type.
Yes

Any desired metadata, e.g. relationship types specific to the business process, can be defined and used as needed.
Facilitates advanced business analytics e.g. via saved searches and queries.No

While the custom field can be searched for, it will be very difficult, if not impossible to properly bucket items e.g. based on link type.
Yes

Thanks to the fact that we can capture any information we need via the linkage custom record, we can perform advanced analytics.
Linkage is easy to set up (“easy” is somewhat subjective here).Yes

Compared to the other approach, set-up effort is less.
No

A custom record is required as well as a small script. However, for a seasoned NetSuite professional, this is as easy as it gets.
Comparison of both approaches

Conclusion

While this article has described the process of linking multiple instances using the transaction record, the approach is applicable to any record type. I hope you found it meaningful and it will help you in making sound trade-offs between your options for creating record links with rich information. Have you found other ways to achieve similar results? Please share them!

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.

6 Replies to “Learn Powerful Pattern to Create Rich Links Between Related Transactions”

  1. Hi there,

    I have implemented the above pattern, but I am not getting the reciprocal linkage between records. The script is not adding both of the transactions to the “all transactions field” before record submit/save. Is this script still applicable?

    Thank you.

    1. Hi Lauren,

      Please check your implementation and verify that your user events are indeed firing. If necessary, add some debug lines to help you track down the problem.

      Cheers

  2. Good day,

    Thanks for your article, I thought of this before.
    I’ve got a few questions if you don’t mind.

    1. Regarding the script deployment, should it trigger on the desired transaction records or on the ‘NSI Linked Transactions’ custom record?
    2. From a usability point, should the user create the custom records and populate the ‘NSI Linked Transactions’ record or should this happen automatically from the script’s side?

    Many thanks,
    J

    1. Hi Jarrid,

      Thanks for dropping by.

      Re: 1) The script is deployed to the NSI Linked Transactions record.

      Re: 2) Creating an NSI Linked Transactions directly from the sub list on existing transactions is probably more user-friendly and is my preferred approach. However, nothing stops users from doing so via the custom record if they so desire.

      Cheers

Leave a Reply

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

×