Odoo for Pharmacies

Pharmacy Management in Odoo 19: Medicines, Batches and Daily Closing

Star Bit Solutions9 min read

A pharmacy needs to know what every product contains, which batch expires next and how the day's takings split by payment type. Here is how to set that up in Odoo 19, with Inventory and the free SBS Pharmacy Management module.

A medicine bottle with lot and expiry tags beside a daily sales report split into cash, card, credit, insurance and branch
Scroll

Key takeaways

  • Odoo 19 Inventory handles lots, expiry dates and FEFO picking; SBS Pharmacy Management adds the medicine details a product form lacks.
  • The Daily Sales Report splits takings into cash, card, credit, insurance and branch by reading the journals that actually paid each invoice.
  • The report is fail-closed: an uncategorized payment journal stops it, so no money is left out of a bucket.
  • Switch to perpetual valuation, labeled Perpetual (at invoicing) in Odoo 19, before trusting the cost, closing stock and gross profit lines.

Pharmacy management in Odoo comes down to three questions a pharmacy owner asks every day. What exactly is this product? Which batch expires next? And how did today's takings split between cash, card, credit and insurance? Standard Odoo 19 answers the second question well. The first and third need more than an ordinary product form and a sales report.

This guide sets out what a pharmacy needs from its system, how Odoo 19 Inventory handles batches and expiry dates, and how our free SBS Pharmacy Management module adds medicine master data and a daily closing report. It ends with the rollout steps our team follows when it sets up a pharmacy.

Running Odoo Enterprise, or planning to? Enterprise adds apps such as Barcode for scanning at receipt and Documents for licenses and supplier certificates, around the same Inventory setup, and our guide to Odoo Documents and approvals shows how the Documents side works. The pharmacy module is built and tested on Odoo 19 Community, so on Enterprise we try it on a staging copy first.

What a Pharmacy Needs from Its System

A pharmacy is a retailer with stricter master data. Before choosing modules, list what the system must do. A typical list looks like this:

  • Medicine master data: active ingredient, strength, pack size, manufacturer, source and dispensing mode, recorded the same way every time.
  • Batch and expiry control: every unit traceable to a lot, with its expiry date captured at receipt.
  • First expired, first out: stock picked by expiry date rather than by arrival date.
  • Daily closing: one figure each for cash, card, credit, insurance and branch, with the customer counts behind them.
  • Reliable margins: cost of goods sold and closing stock that reflect real movements.
  • Clear roles: counter staff who sell, and managers who see the closing figures.

Medicine Master Data on the Odoo Product Form

A standard Odoo product form has no place for an active ingredient or a dispensing mode. SBS Pharmacy Management adds an Is Medicine checkbox to the ordinary product. Tick it and a Medicine Details tab appears with the active ingredient, strength, pack size, manufacturer, import status and prescription requirement.

The values come from four small master lists that you maintain under the Inventory configuration menus:

  • Active Ingredients: what the medicine contains, so you can find every brand of the same ingredient.
  • Companies: the manufacturers, picked from a list rather than typed freely.
  • Sources: local, imported or however you choose to classify supply.
  • Dispensing Modes: over the counter, prescription only or controlled.

Each list can be archived rather than deleted, so an entry you stop using is hidden without being lost. Because staff pick values instead of typing them, the same ingredient is spelled the same way every time, which is what makes a search by ingredient reliable. The dispensing mode is recorded on the product, so keep your prescription checks in your dispensing procedure.

Batches and Expiry Dates with Odoo Inventory

Batch and expiry control is standard Odoo 19 Inventory, not part of the pharmacy module. It works on products tracked by lots, and Odoo's expiration dates documentation covers it in detail. The setup takes five steps:

  1. In Inventory > Configuration > Settings, under Traceability, enable Lots and Serial Numbers, then Expiration Dates.
  2. On each medicine's General Information tab, keep the product type as Goods and set Track Inventory to By Lots.
  3. On the Inventory tab, tick Expiration Date and fill in the four dates, each in days: the Expiration Date after receipt, and the Best Before, Removal and Alert dates before expiry.
  4. Set the removal strategy to First Expiry First Out (FEFO) on the stock location, or through Force Removal Strategy on the product category.
  5. Name a Responsible user on the Inventory tab, so that person is given a to-do activity when a lot still in stock reaches its alert date.

From then on, a receipt cannot be validated until each line has a lot number, and the expiry date fills itself in from the product settings. For example, with an Expiration Date of 730 days and a Removal Date of 60 days, a lot received on 1 June 2026 expires on 31 May 2028 and should leave the shelf by 1 April 2028. When the date printed on the pack differs, overwrite it on the lot at receipt.

To review stock by expiry, open Inventory > Products > Lots/Serial Numbers, group the list by expiration date, and apply the Expiration Alerts filter to see the lots whose alert date has been reached. A weekly look at both is a habit worth building into the dispensary routine.

Have a question about this guide? Ask the engineers who wrote it.

The Daily Closing Report, Split by Payment Type

At the end of the day an owner wants one number for cash, one for card, one for what went out on credit and one for insurance. The module's Daily Sales Report gives exactly that, with Cash, Credit Card, Credit, Insurance and Branch buckets and the customer counts behind each, as a one-page PDF on the company letterhead or as an Excel workbook.

It does not guess. Each payment journal carries a Pharmacy Payment Category, and the report reads the journals that actually paid each invoice:

SituationHow the report treats it
Invoice paid through a categorized journalCounted in that journal's bucket
Invoice still outstandingReported as credit
Part-paid invoiceShared proportionally across the categories that paid; the rest is credit
Payment made after the report's To DateStays credit, so re-running an earlier day gives the same answer
Credit noteFiltered on its accounting date, with the original invoice's proportions
Invoice with no sales orderLeft out of the report

Sales are dated by the sales order's order date, not the invoice date. The part-payment and credit note rules are how the report is designed to work; the rollout tips below list what we have not yet tested with real data. If any payment journal has no category, both the PDF and the Excel export refuse to run and name the journal, for example "Set a Pharmacy Payment Category on these payment journals before generating the report: Bank". The report will not quietly leave money out of a bucket.

In our test on a live Odoo 19 Community database, three sales on one day, one in cash, one by card and one left outstanding, split into 48.00 cash, 85.00 card and 63.00 credit: 196.00 of net sales from three customers, with 29.40 of tax at that database's 15% rate, in both the PDF and the workbook. Because the report reads sales orders and their invoices, run every sale you want in the closing figures through a sales order and an invoice.

Check your valuation first. Cost of Goods Sold, Closing Stock and Gross Profit are read from Odoo's stock valuation, which only produces real numbers when your product categories use Automated (perpetual) valuation, the option Odoo 19 labels Perpetual (at invoicing). On the default periodic valuation, Cost of Goods Sold comes out as zero, Gross Profit Margin reads 100% and Closing Stock can be a large negative number, and the report does not warn you. We have seen these three lines only on a periodic-valuation database so far, so check them on a staging copy after switching. Sales, tax and customer counts come from invoices and are right either way.

What the Module Changes across the Database

SBS Pharmacy Management is built for a pharmacy, and a few of its changes reach beyond pharmacy records. Know them before you install:

  • Pharmacy Payment Category becomes required on every bank, cash and credit journal in the database, for every user.
  • The Taxes column is hidden on sale order lines on every sales order; anyone who needs it can switch it back on through the column chooser.
  • Sales reporting menus are re-scoped, so an SBS Pharma Manager sees the Daily Sales Report rather than the full set of sales reports.
  • Configuration lives under Inventory, so maintaining the master lists needs Inventory administrator rights as well as the pharmacy role.

The module depends on account, stock, stock_account, product, sale and sale_stock, and the Excel export needs the xlsxwriter Python package. It is listed for Odoo.sh and on-premise installations, not Odoo Online. Our tour of free Odoo 19 Community modules explains how to install it on either.

Rollout Tips for Pharmacy Management in Odoo 19

  1. Agree the switch to perpetual valuation, labeled Perpetual (at invoicing) in Odoo 19, with your accountant before you load opening stock, so the report's margins are real from the first day.
  2. Fill the four master lists before creating medicines, then load products with Is Medicine ticked and their details completed.
  3. Enable lots and expiry dates, set tracking by lots and FEFO, then load opening stock through an inventory adjustment with real lot numbers, and correct each lot's expiry date to the date printed on the pack.
  4. Set a Pharmacy Payment Category on every payment journal, including the bank journals used for card settlements.
  5. Give counter staff the SBS Pharma User role and the owner or branch manager SBS Pharma Manager.
  6. Run a test day on a staging copy and agree the report's buckets with the till count and the card terminal totals.
  7. Test the cases we have not yet tested with real data: insurance and branch categories, partial payments, credit notes, multi-company use and the optional link to SBS Account Community's restricted journals.
  8. Train staff to sell through sales orders and invoices, go live, and run the report every evening.

If you keep medicines that must stay cold, StarSense, our AI and IoT platform, logs the temperature of medicine fridges and cold rooms continuously, with a time-stamped record of every excursion and an audit trail ready for inspections.

How Star Bit Solutions Can Help

We wrote SBS Pharmacy Management, and our OdooStar team sets up pharmacies on both editions. On Odoo Enterprise we add apps such as Barcode and Documents around the same Inventory setup. On Community we install and configure the free module, load your medicines and lots, and test the daily report against your till. Our healthcare industry page shows how this fits with the rest of our work for pharmacies and clinics.

To plan a rollout, contact us, call +971 55 973 4524 or message us on WhatsApp with your number of branches, products and payment types, and an engineer will suggest a setup and an order of work.

Star Bit Solutions logo
Written by the Star Bit Solutions team

Star Bit Solutions is a software company in Ajman, UAE, founded in 2014. We implement and customize Odoo Enterprise and Odoo Community, and build StarBiz (AI-driven ERP), StarHub (life super app), StarBot (conversational AI), StarLearn (adaptive learning) and StarSense (AI and IoT platform). About us

OdooStar by Star Bit Solutions

Close the Pharmacy Day with One Report, Not a Calculator.

We set up medicines, lots, expiry dates and the daily closing report on Odoo 19, then test them against your till before go-live.

Not Sure Which Solution Fits?

Tell us about your business and we will recommend the right starting point, free of charge.