Part 1 of a series on GRNI reporting and reconciliation in NetSuite
If your GRNI account is carrying a balance you can't explain, you are not alone. It is one of the most common — and most frustrating — reconciliation problems we encounter on NetSuite engagements. The account balance tells you there is a problem. It does not tell you where.
This article covers the fundamentals: what GRNI is, how NetSuite posts to it, and how to build a saved search that breaks the balance down by Purchase Order so you can actually investigate it. Later articles in this series cover getting the balance by item, handling scale, and a deeper approach we developed for clients who need exact receipt-to-bill matching at line level.
What GRNI is and why it exists
GRNI — Goods Received Not Invoiced — is an accrual account. Its job is to bridge the gap between two events that rarely happen on the same day: receiving stock from a supplier, and receiving the supplier's invoice for that stock.
The accounting principle is straightforward. When you receive goods, you have an obligation to pay for them, even if the invoice hasn't arrived yet. You need to recognise that liability. GRNI is where you park it.
When the invoice does arrive and you raise a vendor bill, the liability moves from GRNI to Accounts Payable. At that point, for a fully-received and fully-billed order, the GRNI account should clear to zero.
In practice, it rarely does — at least not cleanly. That is the problem.
How NetSuite posts to the GRNI account
In NetSuite, the purchase-to-pay cycle runs through three transaction types: the Purchase Order, the Item Receipt, and the Vendor Bill. Understanding what each one does to the ledger is the starting point for any GRNI reconciliation.
Purchase Order — no accounting entries. The PO is a commitment document. It records what you have agreed to buy and at what price, but nothing posts to the general ledger until goods move.
Item Receipt — this is where GRNI gets its credit. When you receive stock against a Purchase Order, NetSuite posts:
Dr Inventory Asset [value of goods received]
Cr GRNI / Purchase Accrual [same value]
The Item Receipt in NetSuite is always created from another transaction — in the GRNI context, always from a Purchase Order. The createdfrom field on the receipt links it back to the originating PO. There are no standalone item receipts.
Vendor Bill — this is where GRNI gets its debit. When the supplier's invoice arrives and you raise a vendor bill in NetSuite (created from the Purchase Order), NetSuite posts:
Dr GRNI / Purchase Accrual [invoice amount]
Cr Accounts Payable [same amount]
The result, for a PO that has been fully received and fully billed at the agreed price, is that the GRNI account nets to zero. The credit from the receipt and the debit from the bill cancel each other out.
The diagram below shows the Purchase Order as the central record joining the two transactions:
Why the account balance tells you nothing useful
If the logic is that clean, why is the GRNI balance so difficult to manage in practice?
Because the GRNI account accumulates postings from every Purchase Order across every supplier, every subsidiary, and potentially years of transaction history. Looking at the account balance tells you the total value of stock received but not yet billed across your entire business. That is a useful number for a balance sheet, but it is useless for reconciliation.
To reconcile GRNI, you need to answer a different question: which specific orders are contributing to this balance, and why?
That requires breaking the balance down. The natural grouping is the Purchase Order — since the PO is the transaction that both the receipt and the bill link back to, it is the logical unit of reconciliation. A PO where the receipt and bill amounts fully match should show a zero GRNI balance. Any PO showing a non-zero balance needs investigation.
A saved search to report GRNI by Purchase Order
The simplest approach is a transaction saved search filtered to the GRNI account, grouped by the source PO. The key to making this work is the filter mainline = true, which returns the net transaction-level amount against the account rather than expanding into individual posting lines.
Here is the search:
/** @NApiVersion 2.1 */
const transactionSearchObj = search.create({
type: "transaction",
settings: [{ name: "consolidationtype", value: "NONE" }],
filters: [
["mainline", "any", ""],
"AND",
["posting", "is", "T"],
"AND",
["account", "anyof", "112"] // replace with your GRNI account internal ID
],
columns: [
search.createColumn({ name: "trandate", summary: "GROUP", label: "Date" }),
search.createColumn({ name: "postingperiod", summary: "GROUP", label: "Period" }),
search.createColumn({ name: "tranid", summary: "GROUP", label: "Document Number" }),
search.createColumn({ name: "amount", summary: "SUM", label: "Amount" }),
search.createColumn({ name: "createdfrom", summary: "GROUP", label: "Created From" }),
search.createColumn({ name: "entity", summary: "MAX", label: "Supplier" }),
search.createColumn({ name: "type", summary: "GROUP", label: "Type" }),
search.createColumn({ name: "statusref", summary: "GROUP", label: "Status" })
]
});
A few points on the setup:
Account internal ID —
"anyof", "112"should be replaced with the internal ID of your GRNI or purchase accrual account. You can find this by navigating to your chart of accounts, opening the account record, and reading the internal ID from the URL. Some NetSuite configurations use multiple accrual accounts (for example, separate accounts per subsidiary); you would add all relevant IDs to theanyoflist.Consolidation type NONE — setting consolidationtype to
NONEensures you see each subsidiary's postings independently, rather than a consolidated view. This is important for multi-subsidiary accounts where GRNI is split by subsidiary.mainline = true — this is the filter that gives you the net transaction amount. Without it, you would see individual posting lines, which complicates the grouping.
createdfrom — this column returns the PO that the Item Receipt or Vendor Bill was created from. For item receipts, this is always the source PO. For vendor bills, this is also the PO in straightforward cases — though as we will explain in the next article, a single vendor bill can reference multiple POs, which means this column may not be sufficient for more complex scenarios.
What this search shows — and what it doesn't
This search gives you a clean list of GRNI postings grouped by document, with the source PO visible on each row. You can use it to answer questions like:
- Which POs have outstanding GRNI balances?
- Which POs have been partially billed (receipt posted but bill not yet fully matched)?
- Are there old receipts sitting in GRNI that should have been cleared months ago?
It does not tell you:
- Which item within the PO is driving the balance — the mainline amount is a single net figure per transaction, not split by item
- Which specific receipt lines match which bill lines — particularly relevant when a PO has been partially received across multiple receipts and partially billed across multiple bills
- Why a bill is showing a residual — whether it is a price difference, a quantity difference, or something else
These limitations matter. For a straightforward account — a handful of suppliers, clean one-receipt-one-bill flows — this search may be all you need. For accounts with high transaction volumes, multi-line POs, or suppliers who bill across multiple orders in a single invoice, you need more.
The next article covers exactly that: how to extend this into an item-level GRNI report, why that turns out to be significantly more complex, and the approach we use to handle it correctly.
Fowlers Consulting Services Ltd are an AI-first NetSuite consultancy based in the UK. If you are struggling with GRNI reconciliation — or any other area where NetSuite's standard reporting falls short — get in touch.
Next in this series: GRNI by Item in NetSuite — The Standard Costing Proxy Approach