Daily Odoo low stock brief that skips what is already on order

Every weekday morning we work out which products will genuinely run out, ignore the ones with deliveries already booked, and post a ranked brief to Slack.

Agentic Task
OdooSlackGoogle SheetsOperationsNotifications & AlertsDaily DigestsAI Reports
PromptCreate

Every weekday at 7am, work out which products in my Odoo inventory are genuinely about to run out, and brief my operations team on them.

Start with current stock. Use Odoo Search & Read Records (search_read) on stock.quant to get on hand quantities per product, restricted to internal stock locations so you are not counting stock sitting in customer, supplier or virtual locations. Then use Search & Read Records on product.product to pull the details needed for the brief: name, internal reference or SKU, list price, and whether the product is still active. Skip anything archived (active is false) or marked discontinued, and ignore service type products that do not hold stock at all.

Next work out how fast each product is selling. Use Read Grouped Aggregates (read_group) on sale.order.line grouped by product, filtered to confirmed orders from the last 30 days, summing both quantity sold and line revenue. Divide the 30 day quantity by 30 to get a daily velocity per product. If a product sold nothing in that window it has no meaningful velocity, so leave it out of the brief rather than reporting infinite days of cover.

Then find out what is already on the way. Use Search & Read Records on purchase.order.line to pull open purchase order lines per product, with quantity ordered, quantity already received, and the expected receipt date. Only count lines belonging to confirmed purchase orders, not drafts or cancelled ones.

Now apply the judgement, which is the whole point of this workflow. For each product compute days of cover as quantity on hand divided by daily velocity, then estimate a stockout date as today plus days of cover. Exclude any product where a confirmed inbound purchase order is expected to arrive before that stockout date, because that gap is already handled and flagging it just creates noise. What remains is the genuine risk list. Odoo's native reordering rules fire on a static minimum quantity with no awareness of sales velocity or of inbound stock already covering the gap, which is exactly what generates alert fatigue, so do not simply reproduce them.

Rank the risk list by days of cover ascending first, then by revenue at risk descending as the tiebreaker, where revenue at risk is roughly daily velocity multiplied by list price across the expected replenishment window. For each product suggest a reorder quantity that covers the supplier lead time plus a safety buffer, using the product's configured lead time in Odoo where one exists and a sensible default where it does not.

Post the brief to Slack using Send a Message to my operations channel. Keep it to the top items, around ten, rather than dumping the whole catalogue. For each product show the name and SKU, days of cover, recent daily velocity, quantity on hand, suggested reorder quantity and revenue at risk, ordered worst first. Close with a single line saying how many further products were low but excluded because stock is already inbound, so the team can see they were considered.

Finally, append one row per at risk product to my Google Sheets tracking sheet using Append Values, so we build a history of stockout near misses over time. Each row should carry the run date, product name, SKU, quantity on hand, daily velocity, days of cover, revenue at risk, suggested reorder quantity, and whether an inbound purchase order exists. If nothing is at risk on a given morning, post a short all clear to Slack and append nothing to the sheet.

Example output

Stock risk brief for Tuesday 11 Aug 5 products at risk, ranked worst first. 1. Aluminium Frame 40mm (AF-040) 3.2 days of cover · 18.5 units/day · 59 on hand Suggested reorder: 560 units · Revenue at risk: £14,200 2. Hex Bolt M8 Zinc (HB-M8Z) 4.8 days of cover · 240 units/day · 1,150 on hand Suggested reorder: 7,200 units · Revenue at risk: £3,900 3. Nylon Spacer 12mm (NS-012) 6.1 days of cover · 42 units/day · 256 on hand Suggested reorder: 1,300 units · Revenue at risk: £2,050 4. Rubber Gasket 60mm (RG-060) 7.4 days of cover · 31 units/day · 229 on hand Suggested reorder: 950 units · Revenue at risk: £1,780 5. Steel Bracket L (SB-L) 9.0 days of cover · 12 units/day · 108 on hand Suggested reorder: 380 units · Revenue at risk: £1,320 6 more products were low but already have a purchase order arriving before they run out. No action needed.

What does this prompt do?

  • Checks your Odoo inventory every weekday morning and works out how many days of cover each product has left, based on how fast it has actually been selling over the last 30 days.
  • Ignores products that already have a delivery booked to arrive before they would run out, so you only hear about the shortages nobody is handling yet.
  • Posts a ranked brief to your operations Slack channel showing the product, days of cover, recent sales rate and a suggested reorder quantity.
  • Logs every at risk product to a Google Sheet so you build a history of stockout near misses and can spot the lines that keep catching you out.

What do I need to use this?

  • An Odoo account with access to your inventory, sales and purchasing records.
  • A Slack workspace and the channel where your operations team wants the morning brief.
  • A Google Sheets spreadsheet to use as the tracking log, with a tab ready to receive rows.
  • If you are on Odoo Online (odoo.com), outside access to your data requires a Custom plan. Self hosted and Odoo.sh accounts have no such restriction.

How can I customize it?

  • Change the timing. Weekday mornings at 7am suits most teams, but you can run it daily including weekends, or twice a week if your stock moves slowly.
  • Adjust how many products the Slack brief lists and how tight the risk threshold is, so the message stays short enough that people actually read it.
  • Change the sales window from 30 days to something shorter for fast moving lines, or longer for seasonal products where a month is not representative.

FAQs

How is this different from Odoo's built in reordering rules?
Reordering rules fire when stock drops below a fixed minimum quantity. They do not know how fast a product is selling, and they do not know whether you already have a delivery on the way. That combination is what produces a long list of alerts people stop reading. This brief divides your stock on hand by your actual recent sales rate to get days of cover, then drops anything with a purchase order arriving before it would run out.
Will it nag me about products that already have stock on the way?
No. It checks your open purchase orders and their expected arrival dates. If a confirmed delivery lands before the product would run out, that product is treated as handled and left off the brief. The message closes with a count of how many were excluded for that reason, so you can still see the workflow considered them.
Does this work with Odoo Online?
Yes, with one caveat. On Odoo Online (odoo.com), letting outside tools read your data requires a Custom pricing plan. If you are self hosted or on Odoo.sh there is no such restriction and it works on any plan.
What happens to products that have not sold recently?
They are left out. Without recent sales there is no meaningful rate to divide by, so reporting days of cover for them would be misleading. The brief focuses on products that are actively moving and will genuinely hit zero.
Can I send the brief somewhere other than my ops channel?
Yes. You can point it at any channel in your Slack workspace, or have it arrive as a direct message to whoever owns purchasing. The Google Sheet log is separate and keeps recording regardless of where the message goes.

Related templates

Auto-fix your calendar when a flight slips, and flag what's at risk

When your flight moves, your calendar times get corrected automatically and you get a Slack note naming the meetings you're about to miss.

Google Calendar
AviationStack
Slack
Agentic Task
Trace phishing emails to the sending IP and report abuse

Every 15 minutes, forwarded phishing reports get traced back to the server that really sent them, with a verdict in Slack and the worst senders reported.

AbuseIPDB
Gmail
Slack
Agentic Task
Weekly Amazon S3 bucket security audit posted to Slack

Every Monday, check every S3 bucket for public exposure, missing encryption and weak backup settings, then get the risks ranked in Slack.

Amazon S3
Slack Bot
Google Sheets
Agentic Task
Turn procurement portal tenders into CRM deals each morning

Every weekday at 7am, sign in to the tender portals you track, filter new notices against your bid criteria, and open a deal for the ones worth chasing.

Anchor Browser
Google Sheets
HubSpot
+1
Agentic Task
Draft polite follow-ups for emails that never got a reply

Every weekday at 4pm, spot the threads that went quiet, stage a ready-to-send nudge in your mailbox, and get a ranked Slack recap.

Aurinko
Google Sheets
Slack Bot
Agentic Task
Turn each week's football fixtures into a venue staffing plan

Every Monday, rank the week's matches by expected demand, put the big ones on your venue calendar, and post a rota-ready summary to Slack.

API-Sports
Google Calendar
Slack
Agentic Task

Stop hearing about stockouts from your customers.

Get a short, ranked stock risk brief in Slack every weekday morning, with the already handled shortages filtered out.