# 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.

- Workflow type: agent
- Services: Odoo, Slack, Google Sheets
- Categories: Operations
- Published: 2026-08-07

## What it does

- 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 you'll need

- 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.

## Prompt

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.

## How to customize

- 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.

## 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.

## FAQ

### 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.

Use this prompt in General Input: https://www.generalinput.com/prompts/daily-odoo-low-stock-brief-that-skips-what-is-already-on-order