Odoo stock.quant and RFID: The Gateway Is the Product
Odoo stock.quant and RFID: The Gateway Is the Product
Odoo Integration

Odoo stock.quant and RFID: The Gateway Is the Product

Readers emit thousands of duplicate tag events per second; Odoo writes one row per quant and deadlocks under concurrency. The durable answer is a gateway that parses EPCs deterministically, deduplicates in time windows, aggregates into deltas and applies them idempotently. Architecture, field mapping and the failure modes nobody documents.

12 min· By SpidersRFID Editorial Team

The first version of every RFID-to-Odoo integration looks the same. A reader is configured to POST each tag read to a controller, the controller calls write on stock.quant, and within a week the database is locking, the Odoo workers are saturated, and the inventory is wrong in a way nobody can reproduce.

The mistake is architectural rather than technical. A reader is a sensor, not a transaction source. Between a sensor that reports thousands of times per second and an ERP that expects a considered business event, there has to be something that thinks. That something is the gateway, and in a working deployment it is the part you maintain, version and monitor — the product, not the glue.

Why wiring readers straight into Odoo is an anti-pattern

The numbers make the case before any code is written.

  • A single fixed reader in a doorway emits several hundred TagRead events per second during a pallet pass.
  • Each tag is typically seen five to twenty times inside one second, at different signal strengths.
  • Odoo's ORM computes and writes one quant row per product, location and lot, with row locks and cache invalidation on each write.
  • Concurrent writers on the same quant serialise into lock waits, and multi-row updates in the wrong order produce deadlocks.
  • A reader outage then replays a burst, and the burst arrives at exactly the moment the ERP is least able to absorb it.

The gateway's three jobs: parse, deduplicate, aggregate

A gateway that does these three things well can be two hundred lines. One that does them badly will be rewritten twice.

  • Parse: turn a raw EPC into a product, a lot and a serial without a database lookup on the hot path.
  • Deduplicate: keep one observation per tag per time window, not twenty, and keep the strongest signal with it.
  • Aggregate: convert observations into signed deltas per location and product, which is the only quantity Odoo should ever see.
  • Buffer: hold deltas in a durable spool so a restart loses nothing and a retry is safe.
  • Apply: write to Odoo in batches, with an idempotency key that makes a repeated apply a no-op.

From EPC to product: a deterministic mapping

EPC parsing is where integrations quietly break, because it is done by string manipulation instead of by schema.

  • A 96-bit SGTIN encodes a company prefix, an item reference and a serial; the split point depends on the prefix length, not on the string.
  • Decode the header first, then the partition, then the fields; guessing field widths works until it does not.
  • Keep a cached map from item reference to product and lot; refresh it on a timer rather than on every read.
  • Treat unknown EPCs as an explicit queue, not as nulls; an unknown tag is a labelling or commissioning defect worth seeing.
  • Version the mapping rules, because a supplier changing its tag encoding should not require a code deployment.

Writing stock.quant without deadlocks

The write path is where most projects lose a weekend. The rules are simple and mostly about ordering.

  • Use one writer process per database; concurrency here buys throughput you do not need and deadlocks you do.
  • Prefer the ORM method that performs an atomic quantity update with the correct lock, and never read-modify-write in Python.
  • If you must use SQL, lock rows in a deterministic order — product, then location, then lot — so two transactions cannot cross.
  • Batch by location, not by tag: fifty deltas in one aisle belong in one transaction, not fifty.
  • Record the business reason on every adjustment, because an unexplained quantity change is indistinguishable from a bug during an audit.

Conflict resolution when two truths disagree

The reader and the ERP will disagree, and the design question is which one is allowed to win, and when.

  • A read is evidence about the present; an ERP record is a claim about the past. They are not the same kind of fact.
  • Never let a single read overwrite a quantity; apply a delta only when the observation is complete and the zone is closed.
  • Use event time from the reader, not arrival time at the gateway, so a delayed batch does not look like a new movement.
  • Last-write-wins is unsafe with duplicated events; prefer a monotonic sequence per reader and reject anything older than the last applied.
  • When the disagreement is structural — a whole zone off by ten percent — raise an exception instead of silently correcting.

Throughput engineering at 100,000 events a day

A hundred thousand events is one per second on average and two hundred per second at the dock door, so averages are useless.

  • Size for the peak, then verify the average; the peak is what breaks the system and the average is what makes it look fine in a demo.
  • Batch on a half-second to two-second window; below that you pay transaction overhead, above it you pay latency.
  • Keep the hot path free of ORM computed fields, onchange logic and mail threading; none of them belong in an inventory write.
  • Run the apply worker under the job queue with a dedicated channel, so a slow ERP does not stall the reader-facing side.
  • Measure the dedupe ratio; if it is below ten to one, the time window is too short and Odoo is doing unnecessary work.

Observability: what to log and what to alert

An inventory pipeline that cannot be observed will be trusted until the first audit, and then not at all.

  • Log every raw event for a sampled subset, and every applied delta for all events, with the idempotency key attached.
  • Track per-antenna read counts, so a dead antenna looks like a drop in a series rather than a quiet week.
  • Alert on apply latency above a threshold, on spool depth growth, and on a rising rate of rejected events.
  • Reconcile daily: compare gateway deltas against Odoo quantity changes and explain every gap larger than a threshold.
  • Keep a replayable event archive, because the most common incident is not a crash but a wrong rule applied for three days.

Deployment sequence and rollback

The safe way to introduce a write path into an ERP is to make it earn the right to write.

  • Stage one: shadow mode. Compute deltas, log them, write nothing, and compare against expected results for two weeks.
  • Stage two: write to a sandbox database with production traffic, and run the reconciliation report against it.
  • Stage three: enable writes for one zone with a feature flag, and keep the old process running in parallel.
  • Stage four: widen by zone, watching the exception rate rather than the success rate.
  • Rollback is not a database restore: stop the writer, replay the spool into a corrected rule, and reapply idempotently.
Odoo RFID Integration — one-stop solution

We use cookies to improve your browsing experience, analyze site traffic and personalize content. Click “Accept All” to consent to all cookies, or choose “Necessary Only”. See our Privacy Policy for more details.