See it in action
From a blank analysis to a full aging matrix and a red-flagged dead-stock list — the whole workflow, end to end.
Naive aging lies. FIFO tells the truth.
A naive report dates stock by the last receipt, so one fresh delivery makes a pile of old stock look new. This app walks the move history — oldest-in, first-out — and reports the age of the oldest unit still on hand. That is the number that tells you whether stock is going stale. From there, configurable provision rules turn that age into a finance-ready obsolescence figure, and a disposition board turns dead stock into a tracked decision instead of just a red flag.
Everything you need to free up cash
FIFO aging buckets
Each product is aged by its oldest remaining unit and placed in a configurable day band — not a misleading last-receipt date.
Aging × movement matrix
A pivot of value by age bucket and movement class shows exactly how much value is old and not moving.
Dead-stock detection
Products with no delivery beyond your threshold are flagged dead, with the capital they tie up surfaced as a single number.
Movement classes
Fast, slow, dead or never sold — from each product's last delivery, so you know what to clear and what to keep.
Capital tied-up view
Total on-hand value and dead value per analysis, so you can put a euro figure on your aging problem.
Write-back to products
Days in stock, aging bucket and the dead-stock flag stored on each product, ready to filter and group across Inventory.
Configurable thresholds
Set the five bucket boundaries and the dead-stock window to match your business; re-run and results update instantly.
Snapshots & cron
Every analysis is saved, and an optional weekly job keeps the latest one fresh so you can track aging over time.
Multi-company
Per-company analyses and record rules keep results separated across companies.
Obsolescence provision ladder
Configurable rules map each age band — optionally per product category — to a provision %. Applied to the value the aging engine already computed, it gives finance a ready obsolescence figure. Opt-in: no rules configured, no change to the report.
Draft-only journal proposal
A wizard drafts a two-line provision entry (debit expense / credit allowance) and leaves it in draft. It never calls action_post and is never triggered automatically — posting is always a human decision.
Dead-stock disposition board
Dead and provisioned products become persistent action items — to review, discount, liquidate, write off or keep — with an assignee, notes and reminder activities that survive every recompute.
Up and running in four steps
Create an analysis
Set the buckets and dead-stock window.
Compute
Every on-hand product is aged and classified.
Read the matrix
See where value is old and not moving.
Act
Clear dead stock and free up cash.
Real screens, real data
Every screenshot below is the actual app running on Odoo 17 — no mockups.
Configure & compute
Set the aging buckets and dead-stock window, then Compute. The total on-hand value and the dead value fill in, with a full audit trail.
The aging × movement matrix
Age buckets down, movement across, value in every cell — instantly see how much value is old and dead versus old but still moving.
Value by age bucket
Switch to the graph to compare the capital sitting in each age band at a glance.
Spot dead stock instantly
The product list flags dead stock in red and slow movers in orange, sorted by age — your clearance shortlist, ready-made.
Aging on the product
Days in stock, bucket and the dead-stock flag are written onto each product, so you can filter and group your catalogue anywhere in Inventory.
Snapshots over time
Keep a saved analysis per period and watch your dead value trend down as you act on it.
Find the cash hiding in your warehouse
Install in seconds. No Enterprise, no external libraries, no lock-in. Works on Odoo 17 Community and Enterprise.
Full manual included. The app ships with a complete in-app documentation page (Apps > this module > Documentation) covering setup, FIFO aging, dead-stock detection, bucket tuning and FAQs. Questions? bambooforge.labs@gmail.com
BambooForge Stock Aging & Dead Stock
See exactly how old your on-hand inventory is and how much capital is tied up in slow-moving and dead stock. Aging is computed FIFO from real stock moves — the age of the oldest unit still on hand — not a naive last-receipt date. Products are bucketed by age, classified by movement (fast / slow / dead / never sold), and the classes are written back onto the products for filtering across Inventory.
This page is the complete manual. Follow it top to bottom and you can install, run your first analysis, read the aging matrix, tune the buckets and fix the common issues without contacting support.
Overview
Inventory that sits too long ties up cash and risks obsolescence. This app makes that visible:
- Aging buckets — every on-hand product is placed in an age band (0-30, 31-60, … , 365+ days by default, fully configurable) based on the age of its oldest remaining unit, computed FIFO from receipts and deliveries.
- Dead-stock detection — products with no outgoing movement for longer than a threshold you set are flagged as dead stock, with the capital they tie up.
- Movement classes — fast, slow, dead or never sold, from each product's last delivery.
- Capital view — total on-hand value and dead value, plus a matrix of value by aging bucket and movement class.
- Write-back to products — days in stock, aging bucket and the dead-stock flag stored on each product, ready to filter and act on.
- Snapshots and an optional weekly cron to track aging over time.
Why FIFO matters
A naive aging report dates stock by the last receipt, so one fresh delivery makes a pile of old stock look new. This app instead walks the move history: it takes incoming quantities oldest-first, removes everything that has since been delivered, and reports the age of the oldest unit still on hand. That is the number that actually tells you whether stock is going stale.
Requirements
- Odoo 17.0.
- The Inventory app (stock). Installing this app pulls it in automatically.
No Enterprise modules and no external Python libraries are required.
Installation
- Copy bambooforge_stock_aging into your addons path.
- Update the apps list (Apps > Update Apps List).
- Search for Stock Aging and click Install.
A new top-level Stock Aging app appears, and a Stock Aging entry is added under Inventory > Reporting.
Quick start
- Open Stock Aging > Analyses and click New.
- Optionally adjust the Aging Buckets (the five day thresholds) and the Dead Stock After (days) value.
- Click Compute.
The analysis switches to Computed, the Products stat fills in, and the Result section shows the total on-hand value and the dead value. Open the Results tab, or Stock Aging > Aging, to explore.
Reading the results
Go to Stock Aging > Aging for the analytical views:
- Pivot — aging buckets down the side, movement classes across the top, value in each cell. This is your "how much value is old, and is it moving?" matrix.
- Graph — value per aging bucket at a glance.
- List — every product with on-hand quantity and value, oldest age, aging bucket, last delivery, movement class and the dead-stock flag. Dead rows are highlighted in red and slow ones in orange.
How classification works
Aging. For each product the app collects done stock moves: receipts into stock and deliveries out of it. Incoming quantities are taken oldest-first and reduced by everything delivered since; the date of the oldest remaining layer gives the oldest age (days), which places the product in a bucket. When a product has stock but no usable move history, its last receipt date is used.
Dead stock & movement. From the last delivery date the app derives the days since the last sale and a movement class: fast (sold recently), slow (no sale for over a third of the dead-stock window), dead (no sale beyond the dead-stock window), or never sold. A product is flagged dead stock when it is dead, or has never sold yet has aged past the dead-stock window.
All values use the product cost in the company currency.
Tuning the buckets
On the analysis form set the five Aging Buckets day thresholds (they must be positive and strictly increasing) and the Dead Stock After (days) window. A sixth bucket automatically holds everything older than the fifth threshold. Re-run the analysis after any change; results update immediately.
Acting on the results
With Write Back to Products on, every product gets a Stock Aging tab showing its days in stock, bucket and dead-stock flag. In the product list (Inventory > Products) you can filter to Dead Stock or group by Aging Bucket, then act: run a clearance promotion, stop replenishing, review suppliers, or write the stock down.
Automating refreshes
A scheduled action Stock Aging: Recompute Latest Analysis ships disabled. Enable it under Settings > Technical > Scheduled Actions to recompute the most recent analysis per company on a schedule (weekly by default), moving the reference date to today each run.
Frequently asked questions
- A product shows age 0 but I know it is old.
- The FIFO age needs receipt moves. Products whose stock came from an inventory adjustment (no receipt move) fall back to their last receipt date, or 0 if there is none. Receive stock through normal operations for full accuracy.
- Value looks wrong.
- Value is on-hand quantity × product cost (standard price). Make sure your cost prices are set.
- Everything is "never sold".
- Movement classes need delivery moves. A database with no customer deliveries yet will show every product as never sold — that is expected.
- Does it respect multiple companies?
- Yes. Each analysis is scoped to one company and results are kept separate per company.
Support
Questions or ideas: bambooforge.labs@gmail.com.
Usage
Everything starts from an analysis record: configure the buckets and thresholds, compute it, then read the results. After installation a top-level Stock Aging app appears, and the analyses are also surfaced under Inventory > Reporting > Stock Aging for inventory managers.
Running an analysis
Go to Stock Aging > Analyses, click New, set the Reference Date (ages are measured up to this date), optionally adjust the five Aging Buckets thresholds and the Dead Stock After (days) window, then click Compute. The record moves to Computed and the summary shows Total Value, Dead Value and, if provision rules exist, the Obsolescence Provision figure. Re-run Compute after any change, or Reset to Draft to clear results. Leave Write Back to Products and Maintain Dead-Stock Actions on unless you only want a throw-away report.
Aging buckets
Each product is placed in one age band based on the age of its oldest unit still on hand, computed FIFO from stock moves. With the default thresholds (30 / 60 / 90 / 180 / 365) the buckets are 1. 0-30d, 2. 31-60d, 3. 61-90d, 4. 91-180d, 5. 181-365d and 6. 365+d — a sixth bucket that automatically holds everything older than the fifth threshold. Thresholds must be positive and strictly increasing; labels are sequence-prefixed so they sort in age order in pivots and group-by views.
Reading the report
Open Stock Aging > Aging for the analytical views:
- Pivot — Aging Bucket rows, Movement columns, with Value and Provision measures: the "how much value is old, and is it still moving?" matrix.
- Graph — a bar chart of on-hand value per aging bucket.
- List — one row per product with quantity, value, oldest age, bucket, last delivery, movement class, dead-stock flag and provision; dead rows show in red and slow-moving rows in orange.
The Movement class comes from the last delivery: Fast Moving, Slow Moving (no sale for over a third of the dead-stock window), Dead (no sale beyond the whole window) or Never Sold. A product is flagged Dead Stock when it is dead, or has never sold yet has aged past the window.
The search view offers the filters Dead Stock, Slow Moving and With Provision, plus Group By Aging Bucket, Movement or Product Category — combine, for example, With Provision grouped by category to see where obsolescence risk concentrates.
Provisioning and dead-stock actions
Provisioning is opt-in. Under Stock Aging > Configuration > Provision Rules map an age band (From / To Age (days), where To = 0 means no upper bound), optionally scoped to a Product Category and Company, to a Provision %. The percentage is applied to the value already computed (qty × cost); the first matching rule in sequence order wins. On the analysis, Propose Provision Entry drafts a two-line journal entry (debit obsolescence expense, credit inventory allowance) and leaves it in draft — never posted automatically.
With Maintain Dead-Stock Actions on, every dead or provisioned product becomes a persistent item under Stock Aging > Dead Stock carrying a Disposition (To Review / Discount / Liquidate / Write Off / Keep), an Assignee and Notes. These items survive recomputes: each compute refreshes the snapshot figures but never overwrites your workflow fields. Use Schedule Review to raise a reminder activity.
Worked example
You receive 100 units in January and 100 more in June, then deliver 150 by December. With a December reference date the FIFO engine consumes the 100 January units plus 50 of June's, so the oldest remaining unit dates from June and the part lands in bucket 4. 91-180d rather than looking new. With no delivery for over 180 days it is also flagged Dead Stock, and a "50% over 180 days" provision rule would put half of its remaining on-hand value into the Obsolescence Provision total.
A scheduled action, Stock Aging: Recompute Latest Analysis, ships disabled; enable it under Settings > Technical > Scheduled Actions to recompute the latest analysis per company (weekly by default), advancing the reference date to today each run.
Upgrading & version compatibility
This build targets Odoo 17.0. Each Odoo major series (17.0, 18.0, 19.0) has its own dedicated build of this module — always install the build that matches your Odoo version. Mixing a build with a different Odoo series is not supported.
Patch upgrades (same series, e.g. 17.0.1.0.0 → later)
Back up your database and filestore first.
Replace the module folder with the newer build.
Restart Odoo with the module updated:
./odoo-bin -c your.conf -u bambooforge_stock_aging -d your_db
Odoo applies any schema/data changes automatically. Your existing records and configuration are preserved.
Cross-version migration (e.g. Odoo 17 → 18)
Upgrading Odoo itself is a database migration handled by Odoo's standard upgrade tooling. When you migrate the database to the next Odoo series, install the matching build of this module for that series. Data created by this module carries over with the database migration.
After any upgrade the module's scheduled actions resume on their normal cadence — no manual re-activation is required.
Uninstallation
You can remove this module at any time from Apps → (this module) → Uninstall, or from the command line. Uninstalling is clean and reversible by reinstalling — but note what is and is not deleted.
What is removed
- The fields, views and analysis definitions this module added.
- The menus, actions, views and reports this module installed.
- Its scheduled actions (cron jobs) — they stop immediately on uninstall.
What is preserved
- Your standard Odoo data (partners, products, sales, invoices, inventory moves) is not deleted — this module only reads and annotates it; the underlying records stay.
- Attachments and chatter messages on standard records are kept.
As always, take a database backup before uninstalling in production.
Changelog
17.0.1.0.0
Current release for Odoo 17.0. This build includes:
- FIFO-accurate stock aging with configurable buckets, an obsolescence provision finance can book, and a dead-stock disposition workflow.
Feature additions and fixes ship as new builds on the Odoo Apps store; this page and the module's version reflect the current published release. Always keep the build matched to your Odoo series (see Upgrading & version compatibility).
Odoo Proprietary License v1.0 This software and associated files (the "Software") may only be used (executed, modified, executed after modifications) if you have purchased a valid license from the authors, typically via Odoo Apps, or if you have received a written agreement from the authors of the Software (see the COPYRIGHT file). You may develop Odoo modules that use the Software as a library (typically by depending on it, importing it and using its resources), but without copying any source code or material from the Software. You may distribute those modules under the license of your choice, provided that this license is compatible with the terms of the Odoo Proprietary License (For example: LGPL, MIT, or proprietary licenses similar to this one). It is forbidden to publish, distribute, sublicense, or sell copies of the Software or modified copies of the Software. The above copyright notice and this permission notice must be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Please log in to comment on this module