A physical count is the moment an ERP finds out what is really on the shelves. In Odoo, the screen built for doing it on a handheld scanner is the Barcode app, and the Barcode app is not part of Odoo Community. This article covers what Community gives you for counting, what the OCA offers on each version, and the lessons from building a count screen for handhelds on Corn Belt Aluminum's manufacturing system.
Community can count. The Physical Inventory screen records a counted quantity per product and location and posts the difference when you apply it. It works in a phone browser, and a handheld scanner can type into it. What Community lacks is a scan-first screen: one that starts from a location barcode, counts in the unit people actually count in, and survives a dropped connection. For that you either wait for the OCA's barcode module on your version, or build a small one.
What Odoo Community has
The Community source has no stock_barcode module, and the "Barcode Scanner" option in Community's Inventory settings is shown with Odoo's upgrade widget, which offers Enterprise. Everything below works without it.
The Physical Inventory screen
Inventory, Operations, Physical Inventory lists stock by product and location (in Odoo's terms, one line per quant). Each line has a counted quantity, labelled "Counted Quantity" in 17 and 18 and "Counted" in 19, and a Difference column that Odoo computes as the gap between the quantity it expects and the quantity you counted. On-hand stock does not change while you type. It changes when you press Apply on a line (Apply All, on 18 and 19, applies every line).
Applying creates one stock move per line for the difference only, between the location and the product's inventory adjustment location, and validates it at once. So after Apply, the on-hand quantity at that location equals your count. That is the right behavior for a count, and it is worth knowing before anyone counts a bin twice: the second count replaces the first, it does not add to it.
If stock moved at that location between the count and Apply, Odoo asks for confirmation before applying an outdated count. On 17, only a user with stock manager rights can apply.
Scheduling counts
Each line carries a scheduled date. By default it comes from the company's annual inventory day and month (31 December unless you change it), and a location can have its own counting frequency, which takes priority. "Request a Count" assigns lines to a stock user with a date, so a cycle count can be handed out a few bins at a time.
Locations with barcodes
Turn on Storage Locations in the Inventory settings to track stock by bin. Every location in Community has a barcode field, and the barcode must be unique within a company, so a printed bin label can identify one location without doubt.
Valuation
stock_account, the module that values stock, is part of Community. With automated (perpetual) valuation, which needs Invoicing or Accounting installed, an applied count posts a journal entry for the value of the difference. The accounts it uses are set on the inventory adjustment location and the product category, and Odoo 19 reworked how stock valuation is computed, so check the entries on a test count in your own version before the real one.
What the OCA offers
Two OCA modules come up in every search for this:
| Module | What it does | 17.0 | 18.0 | 19.0 |
|---|---|---|---|---|
stock_barcodes (stock-logistics-barcode) | Barcode scanning screens for Community, including inventory | Not merged | Migration open | Migration open |
stock_inventory (stock-logistics-warehouse) | Groups adjustments into inventory documents with shared traceability, as before Odoo 15 | Yes | Yes | Yes |
Status as of October 9, 2026. stock_barcodes exists on 16.0; the 17.0 migration request was closed without merging, and the 18.0 and 19.0 ones were still open. Check the repository before you plan around it, because migrations land when a contributor finishes them.
Handhelds and phones
The Odoo web client runs in a mobile browser, and Odoo's own documentation recommends installing it as a web app (a PWA). Handheld scanners such as Zebra's Android devices can be set to send each scan as keystrokes into whatever field has focus, with an Enter added at the end (in Zebra's DataWedge, that is Keystroke Output and the "Send ENTER key" option). That is enough to scan into the Physical Inventory screen's search box. It is not a pleasant way to count a warehouse: the screen is a wide list made for a desk, and every count means a search, a tap on the right line and typing a number.
What we learned building a count screen
Corn Belt Aluminum, the manufacturer Allodi was started in, needed a real count and a screen its shop could use on handheld scanners, on its own Odoo 18 system. It is described with the rest of that system on our case study page. The flow is short: pick the product being counted, pick the part on its bill of materials, pick the colour, scan the bin, enter the count, save. The save writes the count through Odoo's own inventory adjustment, so the stock move and the valuation entry are the standard ones. A few rules turned out to matter more than we expected.
Count in the unit people count in
In standard Odoo the counted quantity is always in the product's own unit of measure; the count model has no unit or packaging choice. That is fine for screws in units. It is not fine for aluminum extrusions stocked in inches, which arrive and sit on the rack as sticks. Nobody on a shop floor counts in inches, so Corn Belt's screen takes the count in the purchase unit when that unit is a larger one of the same kind, and converts. When a part has no such unit yet, set one up before the count, not during it.
Round after converting
Unit factors are stored as decimals, and some are inexact. On Corn Belt's system, nine sticks of 161 inches came back as 1,449.001 inches. Round the converted quantity to hundredths and to the stock unit's rounding before it is written, or the count leaves a tiny difference that shows up on every later report.
Start from the bin, and make unknown bins easy
Scanning the location first ties every count to one bin, so the person counting never picks a location from a list. When someone scans a new rack label that is not in Odoo yet, Corn Belt's screen creates the bin under the warehouse's stock location when the count is saved, instead of refusing the scan. A count is the worst time to send someone back to the office to set up a location.
Refuse only what is really wrong
Some scans should be refused: a system location such as input, output or quality control, or the warehouse's top stock location itself, where a count would overwrite stock that belongs to the bins under it. Everything else is better accepted and fixed in the data. Each refusal message should say what to scan instead.
A retried save must not post twice
Handhelds lose Wi-Fi and people press Save again. A count is naturally safe to repeat, because it sets the quantity rather than adding to it. Moves and consumption are not: Corn Belt's move screen gives every save a unique request number, and the server ignores one it has already processed.
Keep a log beside the stock moves
Each count is also written to a small log with the part, the bin, the quantity and the time, viewable under Inventory reporting. When a number looks wrong a week later, the log answers "what was counted, where, and what Odoo showed before" faster than the stock moves do.
Test without touching real stock
A count screen changes on-hand quantities and the books. Build and test it on a copy of the database, then run a first real count on one rack and check the stock and the journal entries before the whole building counts.
Build, wait, or buy
On Odoo Community, the choices are the Physical Inventory screen as it is, the OCA's stock_barcodes once it reaches your version, or a small custom screen built around your own products and units. On Enterprise, the Barcode app does this job. If you are deciding between them as part of a move from Enterprise to Community, our Odoo 19 Enterprise vs Community table covers the other apps in the same way, and our services page covers having us build the screen.
Questions people ask
Does Odoo Community have a barcode app?
No. The Barcode app is not in the Community source, and Community's Inventory settings offer it as an Enterprise upgrade. Community can still read barcodes typed by a scanner into search fields, and locations and products have barcode fields.
How do you do a physical inventory count in Odoo Community?
Open Inventory, Operations, Physical Inventory, enter the counted quantity on each product and location line, and press Apply (on 18 and 19, Apply All applies every line). Odoo posts the difference as a stock move, so the on-hand quantity at that location becomes the count.
Does a second count add to the first?
No. Applying a count posts only the difference between what Odoo expected and what was counted, so the latest applied count is what the location holds.
Can you count in boxes or sticks instead of the stock unit?
Not on the standard screen. The counted quantity is in the product's own unit of measure. A custom count screen can take the count in a larger unit and convert it before applying.
Is OCA stock_barcodes available for Odoo 18 or 19?
Not as of October 9, 2026. It is released on 16.0, and migration requests for 18.0 and 19.0 were open but not merged.
Sources
- Odoo documentation: Count products (Odoo 18)
- Odoo source: stock_quant.py (18.0)
- Odoo source: stock_location.py (18.0)
- Odoo source: Inventory settings view (17.0)
- Odoo source: stock_account manifest (18.0)
- Odoo documentation: Inventory valuation configuration (Odoo 18)
- Odoo documentation: Mobile apps (Odoo 18)
- OCA stock-logistics-barcode: stock_barcodes, 16.0
- OCA stock-logistics-barcode: stock_barcodes migration pull requests
- OCA stock-logistics-warehouse: stock_inventory, 19.0
- Zebra DataWedge: Keystroke Output
- Zebra DataWedge: Basic Data Formatting