Bundles and Grouped Items: One Code, Several Things
You sell a laptop, a sleeve and a three-year warranty as one thing at one price. In BigLedger that is a bundle: an item code of its own, with children, that behaves like a product on the screen and like a recipe underneath.
The first thing to know about it is the thing nobody is told, and everything else on this page follows from it:
A bundle has no stock of its own. There is no balance anywhere with a bundle’s name on it. Every question about whether you can sell one is answered by looking at the children.
Thirty-two of the 90 live tenants have bundle items — about 11,000 of them between them — and 19 tenants actually put bundles on documents, so this is a mainstream feature that has never had a page.
How many bundles do I have? The arithmetic, exactly
For one bundle at one location, BigLedger works out:
for each child: floor(that child's balance at this location ÷ how many the bundle needs)
then: the smallest of those numbers.
GadgetSphere’s GS-KV-01 sells a “work-from-anywhere” bundle: 1 ultraportable laptop, 1 sleeve, 2
USB-C cables. At that branch the shelves hold 14 laptops, 40 sleeves and 5 cables.
| Child | Balance at GS-KV-01 | Needed per bundle | Bundles this child supports |
|---|---|---|---|
| Ultraportable laptop | 14 | 1 | 14 |
| Sleeve | 40 | 1 | 40 |
| USB-C cable | 5 | 2 | 2 |
You have two bundles, not fourteen and not five. The cable decides it, and it decides it by two because the bundle needs two of them. This is the whole of “bundle parent code but child has zero stock”: the parent is never the constraint, some child always is.
Three details in that calculation that change the answer:
- It is per location. A bundle is available where all of its children are. Nine cables at Penang do not help Klang Valley, and a bundle can be sellable at one branch and refused at the next.
- Only stock-carrying children count. A child that is a service, a warranty or a coupon rather than a stocked item is not part of the arithmetic at all — which is correct, and means a laptop-plus-warranty bundle is limited by the laptop alone.
- A child with no stock-balance row at that location is skipped entirely. It is not counted as zero — it drops out of the comparison, so it cannot be the smallest and cannot constrain the bundle. A child that has never been stocked at that branch is therefore invisible to this calculation. If no child produces a row at all, the answer comes back as −1 and the bundle is refused outright. This one matters and it is covered again below.
“Cannot final — not enough stock for bundle item”
This is the message the corpus reports most, and it is a refusal at finalise, not at save. You can build the document, print it, sit on it; the check runs at the moment the document is about to become an accounting fact.
What it checks is the arithmetic above, at the line’s own location — the delivery location if the line has one, otherwise the line’s store — against the quantity that line is taking out.
The message names the bundle, and never the child that ran out. That is the single most frustrating thing about it, and it is worth saying plainly rather than leaving a reader to discover it: BigLedger knows which child was the constraint and does not put it in the message. (The made-to-order equivalent does exactly the opposite and names the child, so this is not a rule of the platform — it is how this one check is written. Recorded as P-0616.)
So find the child yourself. Open the bundle’s item record, list its children with their per-bundle quantities, and check each child’s balance at the branch on the document. Divide, round down, take the smallest — the one that comes out below the quantity you are trying to sell is the one to go and buy.
The check has a hole worth knowing about. Because a child with no stock-balance row at the document’s location drops out of the comparison rather than counting as zero, a bundle can pass this check while one of its children has never been stocked at that branch at all — and the unwrap then posts that child out anyway, taking it negative. If a bundle sale leaves a child at a negative balance, this is how. The defence is the same one that protects everything else: make sure every child of a bundle has been received at least once at every branch that sells the bundle. (Recorded as P-0617.)
A second caution, because it bites quietly. Each bundle line is checked on its own. Two lines of the same bundle on the same document — three and three, say — are each measured against the full availability, so a document asking for six can pass when only three exist. Ordinary stock items are checked as a total. Keep a bundle’s quantity on one line and you will not meet this. (Also P-0616.)
What happens when you finalise: one line becomes several
Finalise starts a fan-out of background jobs, and one of the subscribers is the bundle unwrap. It rewrites the document:
- Every bundle line is expanded into one child line per child, positioned under the parent as
1001-0001,1001-0002and so on, each linked back to the bundle line it came from. - Each child line carries quantity only: the bundle’s quantity multiplied by how many that child needs. Every money field on a child line is zero.
- The bundle line keeps the money.
- Both the bundle line and the document are then stamped as unwrapped, so it can never happen twice.
Money on the parent, quantity on the children. That is the sentence to remember, and it is what makes the rest of the system behave as you would want: your revenue reports see one sale of one bundle at one price, and your stock ledger sees the laptop, the sleeve and the two cables leave the shelf individually with their own costs.
It also explains a document that looks different after finalising than it did before. Nothing has gone wrong: the children were always implied and are now written down.
Two consequences:
- The printed document shows the children only while the document is in draft. Before finalise the printable expands the bundle for display; afterwards it does not need to, because the children are real lines. A format that shows children before finalising and not after is behaving correctly.
- Changing a bundle’s recipe does not reach back into finalised documents. The children were resolved when the document was unwrapped, and where the document line carried its own snapshot of the children — including which serial numbers went into this particular bundle — that snapshot is what was used.
If the unwrap fails, the document is marked with a failed bundle-posting state rather than silently skipped. It is the field to look at when a finalised bundle sale has not moved any stock.
Where the per-child quantities actually come from
Normally, from the bundle’s child list: each child row carries how many of it one bundle needs, and a quantity left at zero is stored as one.
There is a second, older convention that will surprise anyone who meets it. If the bundle’s item
code contains a ], the per-child quantities are read out of the code text itself, in the form
[BND]{CHILD-CODE,2}{OTHER-CODE,1}. A child not named in the code defaults to one. This is the
convention the Shopify integration uses to decide that an incoming product is a bundle at all — a SKU
matching that pattern is created as a bundle, anything else as an ordinary item.
It is worth knowing for one practical reason: if you use that code convention, the code is the recipe. Editing the child list without editing the code, or the other way round, gives you a bundle whose quantities depend on which path resolved them.
Two ways to price a bundle
Either the bundle has a price of its own in the price book — the ordinary case, and the one that lets a bundle be cheaper than its parts — or its pricing-scheme link has child pricing switched on, in which case its price is derived: the sum of each child’s scheme price times how many the bundle needs, recomputed whenever one of those children is repriced.
Derived pricing is the right choice when a bundle is a convenience rather than a deal (a kit assembled from full-price parts) and the wrong one when the bundle is the offer, because a child’s price rise will quietly carry the bundle up with it.
A grouped item is not a bundle
They share a parent-child table and nothing else, and conflating them wastes a lot of time.
| Bundle | Grouped item | |
|---|---|---|
| What it is | several things sold as one | one catalogue entry for several variants |
| Children may be | stocked items only | stocked items or bundles |
| On a document | expands into child lines at finalise | does not expand |
| Stock | none of its own; derived from children | not a stock concept |
| Pricing | its own, or the sum of its children’s | pushed down to the children |
The everyday grouped item is a product with sizes or colours: one entry a shopper browses, several real items that are actually sold and counted. It is what the Shopify integration creates for a product with variants. Nineteen tenants have grouped items; ten put them on documents at all, which fits — a grouped item is mostly a catalogue device.
The one behaviour to watch is the pricing push. Repricing a grouped item can propagate that price onto every child, creating a price-book entry for a child that had none. If a child fails, the failure is logged and swallowed and the parent’s own update still succeeds — so a propagation can be partial and nothing on the screen says so. After repricing a grouped item, spot-check two or three children rather than assuming.
What it will not do
- A bundle will not hold stock, be counted in a stock take, or appear in a stock balance report as a quantity. There is nothing to count.
- A bundle of a bundle is not allowed. The parent-child import refuses any bundle child that is not a stocked item, and the availability arithmetic counts only stocked children in any case, so a child of another kind added by some other route is simply ignored. Nesting belongs to a grouped item, which may have bundles as children.
- The refusal will not tell you which child ran out.
- The storefront number and the invoice check are not computed the same way. The e-commerce channel also derives a bundle’s availability from the smallest child, but the arithmetic is not identical to the finalise check, so a storefront can accept an order that the invoice later refuses. Treat the finalise check as the authority. (Recorded as Q-1067 — whether the two are meant to agree is a product question, not something source can settle.)
- A storefront cart will not take anything but a stocked item, a bundle or a coupon — a grouped item cannot be added to a cart; one of its children has to be.
Checking one in thirty seconds
- Open the bundle’s item record and read its child list — codes and per-bundle quantities.
- For each child, look up its balance at the branch on the document. Divide, round down.
- The smallest answer is how many bundles you have. If it is below what you are selling, you have found your child.
- If the document is already final, scroll its lines: the children are there, positioned under the parent, carrying quantity and no money. If they are not, the unwrap has not run or has failed.