Cannabis Dispensary
Seed-to-sale grams that balance, with the ID, limit and COA checks before the sale.
The short answer
Cannabis Dispensary is an Odoo app for licensed dispensaries that need the custodial answer, not just the commercial one. Every gram is accounted for as dispensed, destroyed, on hand or quarantined, and the till refuses a sale when the ID was not checked, the batch has no passing lab result, or the day's running total would cross the legal cap.
Last updated
What it is for
An inspector does not ask what you sold. They ask where every gram went. A dispensary can have a perfectly reconciled cash drawer and still fail an audit, because the question is custodial rather than commercial. Every gram that came through the door was dispensed, destroyed, left on the shelf, or quarantined pending a lab result, and those have to add back up to intake with evidence attached to each. Point-of-sale software answers the commercial question. The custodial one gets answered by a spreadsheet maintained after the fact, which is the artefact nobody trusts when it matters — that, and a budtender holding an ID check and a running daily total in their head, with a queue in front of them.
- Platform
- Odoo
- Category
- Regulated records
- Works with
- Odoo 18 · Odoo 19
- Technical name
cannabis_dispensary- Status
- Direct from webbox
- Pricing
- Paid
What is inside it
- 01
The seed-to-sale ledger
Intake is typed once. Dispensed, destroyed, on hand and quarantined are computed from the sales log and the destruction register, so the shelf figure follows from the events rather than from anyone's correction.
- 02
What the till refuses
A ticket can be created, edited and cancelled freely. Completing it is the guarded step: no unchecked ID, no batch without a passing COA, no sale that puts the customer over the day's cap.
- 03
The daily limit
The check sums every completed sale that customer made that day and adds the ticket being rung. Day boundaries resolve in the dispensary's own timezone rather than off raw UTC dates.
- 04
The board
Opening the app lands on a compliance board of twelve tiles: quarantined grams, saleable stock, limit and ID-check rates, tickets held at the till, expiring medical cards, with five charts underneath.
- 05
Chain of custody
Destruction is a two-step record carrying a quantity, a reason, a method and a named witness. A draft entry is not yet a destroyed gram, and entries with no witness get their own tile.
What it looks like in practice
-
A customer splits one purchase across two visits on the same afternoon
Someone buys at 16:00 and comes back at 18:00 local time. At UTC−7 those two timestamps land on different UTC days, so a naive daily total drops the earlier one.
The guard sums every completed sale that customer made inside the dispensary's own day, adds the ticket being rung, and refuses completion with the message that the sale would put the customer at 31.5 g today, over the 28.0 g legal daily limit. The verdict is stored per ticket and coloured in the list, so who went over and when is a filter you can run.
- Default daily limit
- 28.0 g
A default you can change.
The daily limitWhat the till refuses
-
The batch that failed its lab screen is missing from the shelf list
The batch list totals 4,440 g while intake across the estate was 4,920 g. One archived batch of 480 g failed its screen and was destroyed in full.
The dashboard ledger adds the archived batch back in, so dispensed, destroyed, on hand and quarantined sum to intake. A dashboard test asserts that the sum holds, which means a change breaking the balance fails the build instead of shipping quietly.
- Intake
- 4,920 g
- Dispensed
- 150 g
- Destroyed
- 559.5 g
- On hand
- 3,160.5 g
- Quarantined
- 1,050 g
Figures from the module's own demo data, on a fresh install. Install with demo data and open Cannabis then Dashboard.
The seed-to-sale ledgerThe board
-
A destruction entry sits with the witness field still blank
Seven rows in the destruction register add to 563 g in the footer, and the board reports 559.5 g destroyed.
The 3.5 g at the top is still a draft. Mark Destroyed is the only route to the second state, so those grams stay outside the destroyed total until somebody presses it, and rows with no witness named show in red where an audit stops.
- Register footer
- 563 g
- Reported destroyed
- 559.5 g
- Still in draft
- 3.5 g
Figures from the module's own demo data, on a fresh install. Install with demo data and open Inventory then Waste / Destruction.
Chain of custodyThe board
What it deliberately does not do
- No state track-and-trace filing
- There is no Metrc, BioTrack or Leaf API integration. The ledger here is the internal record you report from.
- Not a payment terminal or cash-drawer POS
- It logs the dispense and the compliance decision. Money stays Odoo's job.
- No lab portal feed
- A COA is a flag plus the attached certificate, set by whoever reads the lab report.
- Cultivation is out of scope
- No plant tagging, propagation, room or harvest planning, and no delivery manifests or driver routing. It starts at intake.
- It does not decide your legal limit
- The daily limit is a field on the ticket, defaulting to 28.0 g. Set it to whatever your jurisdiction requires.
Questions
Can I install this on Odoo Online?
Does it file to Metrc or BioTrack?
Where is the legal daily limit set?
Who can see the app once it is installed?
Have something to build?
Tell us the problem. We'll come back with a plan, a price, and who'd actually build it.
- Free scoping call
- Reply within 1 business day
- No lock-in