Beer route-to-market

Design a returnables ledger that actually reconciles

TL;DRModel empties as an event-sourced ledger, not a monthly report. Every outlet carries a live deposit-and-container balance updated by movement events: goods and empties out on delivery, empties in on pickup, deposits netted on the next invoice, collections planned into routes. SAP still posts the journals; the balance is current by construction.

Model empties as an event-sourced ledger, not a monthly report. Give every outlet a running deposit-and-container balance that moves only when a physical event fires: full goods and empties out on delivery, empties collected on pickup, deposits netted on the next invoice. Route planning reads that balance to schedule collections, and SAP keeps posting the journals. Reconciliation stops being a spreadsheet you rebuild every month and becomes a number that is current by construction.

Why don't empties balances reconcile today?

Because the balance is a report, not a fact. The standard tool in beverage distribution is a running out/in tally per customer — the Keg Container and Deposit Activity Report, which, as documented in Encompass's keg-tracking guidance, works out what was shipped out and what was returned and treats the net difference as what is on hand at your customers. That is a periodic reconstruction from delivery and pickup documents, run monthly or quarterly, and it drifts the moment anything is missed.

Three forces pull it apart. The balance is bilateral: you count the kegs on the customer's premises, the customer counts the kegs on yours, and the two numbers rarely agree until someone signs. Loads are mixed: returnable and one-way deposit SKUs ride the same truck at different deposit rates, so a single delivery touches several balances at once. And containers simply vanish — the US industry loses roughly 400,000 kegs a year, at an estimated 0.46 to 1.37 dollars per barrel produced. A monthly report absorbs all of that as unexplained shrinkage.

The deposit does not save you either. A cash deposit is typically only 15 to 20 percent of the keg's replacement cost, so it is a weak incentive, not collateral. The balance itself is the only real control — which means a balance you cannot trust is an open liability you cannot size.

What does a first-class empties ledger look like?

An append-only event stream, one per outlet, keyed by container type and deposit class. You never overwrite the balance; you append immutable movements, and the current balance is the fold over them. That inversion is the whole design. A report answers what do we think the balance was as of last close; a ledger answers what has physically happened, in order, and derives the balance from it. Every event carries who, when, where, how many, which container and which deposit class — enough to defend the number in an audit without a spreadsheet.

Each physical touch emits one movement:

Movement eventEmitted whenEffect on the outlet balance
Containers deliveredDelivery confirmed on the driver's deviceIncreases containers held at the outlet; charges deposit at the class rate
Empties collectedPickup confirmed at the outletDecreases containers held; credits deposit
Warehouse receiptEmpties booked in at the depotCloses the in-transit leg; confirms condition and count
Deposit nettedNext invoice generatedPosts the net deposit movement to SAP
AdjustmentSigned count dispute resolvedCorrects the balance with a new event, never an edit

Because corrections are themselves events, the history stays intact: a disputed count six weeks ago is a visible adjustment, not a silently rewritten cell. That is the difference between a ledger you can hand an auditor and a report you have to explain.

How does deposit netting actually work?

Every delivery emits container movements, and the deposit rides on them rather than living in a separate memo. When a driver drops full kegs and lifts empties, the visit appends both a delivery and a collection movement, each carrying a deposit at its class rate. The next invoice reads the outlet's current balance and nets the deposits charged against the deposits credited, so the customer sees one settled figure instead of a deposit column nobody reconciles. SAP posts the resulting journal — it is genuinely good at that — but it is no longer asked to be the system that remembers how many kegs sit in a specific cellar.

The complication is that a deposit is a liability with structure: per outlet, per container type, per deposit class, and often at more than one rate in the same market. Those rates are jurisdictional and they change, which is exactly the kind of market-specific rule that, hard-coded into each country's build, guarantees that every OpCo rollout restarts from zero. Model the deposit class as versioned reference data and a rate change becomes a configuration edit, not a code release in fourteen markets.

Where do empties pickups fit into the route?

Reverse logistics is not a separate operation; it is a field on the same visit. When an outlet's empties balance crosses a threshold — a full load's worth of crates, a keg overdue past its deposit horizon — the ledger raises a collection task against that outlet's next scheduled delivery, so the van that drops full goods lifts the empties on the same stop. Backhaul that would otherwise run empty carries returns; the driver confirms the count on the device and the balance updates before the truck leaves the kerb.

This is also where the human exceptions land. Most collections are routine, but disputed counts, refused deposits and overdue kegs need a person — which is precisely the work an exceptions desk should handle instead of routine order entry. And because you now hold a defensible per-outlet number, the argument over what is owed is a five-minute confirmation, not a quarterly reconciliation project whose result nobody quite trusts — the same after-the-fact accounting that lets trade promotions lose money before anyone notices.

How do you build a returnables ledger that reconciles?

  1. Make the outlet balance the source of truth. Define one append-only stream per outlet, keyed by container type and deposit class. Retire the monthly report as the system of record; keep it, at most, as a view over the ledger.
  2. Emit a movement from every physical touch. Delivery confirmation, pickup and warehouse receipt each append a signed movement, captured on the driver's device and offline-first, because the cellar with no signal is exactly where the count gets lost.
  3. Model deposits as versioned reference data. Deposit class and rate become configuration with an effective date per market, so a scheme change is an edit, not a release in every country at once.
  4. Net on the invoice; never reprice history. The invoice reads the current balance and nets deposits; SAP posts the journal. Past events stay immutable.
  5. Feed the balance into route planning. Threshold-triggered collection tasks attach to the next scheduled visit, and backhaul capacity is planned against expected returns.
  6. Reconcile by signed confirmation, and age disputes. A disputed count becomes an adjustment event with a signature, not an overwrite; overdue balances age like receivables.

The part that does not go smoothly is the first mile. Drivers under time pressure miscount, scan the wrong container class, or skip the confirmation when the app stalls — and every missed event is drift you pay for at reconciliation. Budget for it explicitly: reconciliation items on the exception queue, periodic signed stock-takes to reset the balance, and a device flow fast enough that confirming a count is quicker than skipping it. Built that way, the ledger runs on the event-bus architecture while SAP stays the financial core, and the two stop fighting over who owns the empties.

The direction of travel makes this urgent rather than tidy. Deposit return schemes keep widening to cover more one-way containers, each adding a deposit class and another balance to defend, and smart-keg sensors are starting to emit location and fill events on their own — movements a ledger can ingest but a monthly report cannot. The operations that treat a physical container movement as a first-class event will spend the next few years extending one balance; the ones still reconstructing a report will spend it explaining shrinkage.

Frequently asked questions

Why don't our keg and empties balances ever reconcile?

Because the balance is a periodic report rebuilt from delivery and pickup documents, not a live fact. It drifts whenever a movement is missed, the count is bilateral, and mixed returnable and one-way loads touch several deposit classes at once. An event-sourced ledger derives the balance from immutable movements, so it stays current.

What is deposit netting on the invoice?

Each delivery and pickup emits a container movement carrying a deposit at its class rate. The next invoice reads the outlet's current balance and nets deposits charged against deposits credited, showing one settled figure. SAP posts the resulting journal, but is no longer asked to remember how many kegs sit in each cellar.

Do we have to replace SAP to do this?

No. Keep SAP as the financial core posting the deposit journals it handles well. The returnables ledger runs alongside on an event bus, owning the per-outlet container balance SAP was never designed to model. The two integrate through movement and netting events, so neither is asked to do the other's job.

Stuck with exactly this?

BrewOS builds the full route-to-market stack for global brewers — order capture, stock, loyalty, returnables, delivery and analytics on one event bus, run by a team of ~20 engineers. Bring us the feature that’s been stuck the longest and we’ll show you how we’d ship it in days.

Book a 30-minute walkthrough