A reader produces observations. Odoo needs a decision. Between them sits the least glamorous and most consequential part of an RFID deployment: the code that converts a few hundred thousand EPC reads into a small number of stock adjustments that someone is willing to sign.
Get this wrong and the symptom is not an error message. It is a warehouse that stops trusting the system, and starts keeping a spreadsheet beside it.
What changed: stock.inventory is gone, stock.quant is the model
Much of the advice on the internet still describes a model that Odoo has removed, so start from the current truth.
- The old stock.inventory document was deprecated; from Odoo 15 onward, counting is done on stock.quant records directly.
- A quant is uniquely identified by product, location, lot, package and owner; that tuple is the key your import must match.
- Counting means writing inventory_quantity on the quant, in inventory mode, and then applying the inventory.
- Applying creates stock moves flagged as inventory adjustments, plus valuation layers if the product is valued.
- The adjustment wizard (stock.inventory.adjustment.name) groups one counting session and carries the accounting date, which is what makes a count auditable.
The staging table between reader and ERP
Never let a reader write to production inventory directly; the staging layer is where bad data dies.
- Store raw reads first: EPC, antenna, reader, timestamp, RSSI and the count session identifier.
- Resolve EPC to product only in a separate step, so a mapping correction does not require re-reading the warehouse.
- Keep the resolved row, its confidence and its resolution source, because "we guessed from the prefix" is information audit will ask for.
- Make the staging table idempotent by session, so a re-run of the same count does not double-count.
- Preserve the raw read count per EPC; duplicates are expected and their number is a useful signal about the reader configuration.
Matching EPC to product, lot and location
Matching is where most variance is manufactured, and it is entirely avoidable.
- Resolve EPC through an explicit registry, not by parsing the SGTIN pattern at read time unless the pattern is contractually guaranteed.
- If a product is lot-controlled, the lot must come from the registry or from a packaging relation; an EPC alone rarely carries it.
- Location comes from the session metadata, not from the tag, because tags do not know where they are.
- If one EPC resolves to two products, stop and quarantine the read; a silent first-match rule is how phantom stock appears.
- Record the unmatched EPCs rather than dropping them; unknown tags are the fastest route to finding a process defect.
Expected versus counted: the arithmetic people get wrong
Variance is not counted minus on-hand; it is a three-way comparison, and the third term is reservations.
- On-hand quantity is what the ledger believes is physically present.
- Reserved quantity is already committed to a delivery or manufacturing order and must not be treated as missing.
- Counted quantity is what the reader saw during the session, after deduplication and filter rules.
- Variance equals counted minus on-hand; a negative variance on a reserved line usually means the goods are staged, not lost.
- Report variance in units and in value, because a controller will triage by value even when operations triage by units.
Applying adjustments safely
The write path must be boring, batched and reversible within the session window.
- Write inventory_quantity in inventory mode, then apply per location or per session, not per tag.
- Batch in chunks of a few hundred quants; one transaction per quant is how a 100,000-tag count becomes a two-hour lock.
- Lock order matters: sort quants by product and location before writing, so two concurrent sessions do not deadlock each other.
- Never adjust a location that is currently in a transfer or an open picking; defer those quants to a second pass.
- Keep the adjustment reference in the record so the valuation layer can be traced back to the count session.
Approval, accounting date and the audit trail
The difference between an adjustment and a correction is who approved it and when it hit the books.
- Route adjustments above a value threshold to a second approver; below it, auto-apply but still log the actor.
- Set the accounting date deliberately; a count performed on the 30th and applied on the 3rd belongs to the earlier period, or the month-end story changes.
- Store the count report as an attachment to the adjustment, not in a shared folder that will be reorganized.
- Log the pre-adjustment quantity, the counted quantity, the difference and the reason code for every line.
- Reconcile the sum of adjustments against the valuation report at period close; the two must tell the same story.
Unknown tags, duplicates and repeat counts
These three cases consume most of the support effort, and each has a cheap, explicit policy.
- Unknown tags: park them in a quarantine location with a task, and review weekly; never write them into a real product.
- Duplicates: deduplicate per EPC per session, but keep the raw read count so a reader with a mis-set session can be identified.
- Repeat counts: run the second count on the same session definition and compare counts before adjusting, not after.
- Partial counts: mark the session as partial and adjust only the locations actually walked, or the untouched aisles will be written to zero.
- Missing tags: treat as a recount task on the same shelf before any negative adjustment, because a shielded pallet looks exactly like an empty one.
A rollout that survives the first month-end
Rehearse the whole chain in a copy of the database before the first real adjustment.
- Rehearse on a database copy with the same volume, so timing and lock behaviour are representative.
- Run one full count, apply nothing, and compare the computed variance against the current ledger; the difference is your tooling error.
- Then apply to one location only, close the period, and check the valuation report and the stock moves.
- Only after a clean period-end, extend to a full site and hand the runbook to operations.
- Publish a monthly variance trend per location; a rising trend is a process problem, not a counting problem.
The engineering summary is short: stage raw reads, resolve deterministically, compute a three-way variance, write batched quants in a stable lock order, apply with an explicit accounting date, and keep every intermediate number. Do that, and RFID stops being a counting gadget and becomes the reason the ledger is finally true.






