Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
4b9777f
add empty pricing app
SchrodingersGat Jul 12, 2026
600ab45
Merge commit '9177ebcb9715a8a3585d0da62a6f2d4dd74d0e1e' into pricing-app
SchrodingersGat Jul 31, 2026
a9c0bd1
Add new "pricing" ruleset
SchrodingersGat Aug 1, 2026
5c8aebc
Add placeholder files
SchrodingersGat Aug 1, 2026
caa37da
Add StockItemCost model
SchrodingersGat Aug 1, 2026
dda423e
Add serializer
SchrodingersGat Aug 1, 2026
6130168
Add regression tests for new API endpoints
SchrodingersGat Aug 1, 2026
911f79c
Merge commit '7a935f6055b7dcda546c2486a80afa3cac3878dd' into pricing-app
SchrodingersGat Aug 11, 2026
9910f5c
Merge commit 'e4b23b4665810319c83ecb74e65c4ff694b0b811' into pricing-app
SchrodingersGat Aug 15, 2026
814fec1
Adjust StockItemCost model
SchrodingersGat Aug 15, 2026
da4fd12
Merge commit 'ee4ad7fd1051a033a3536145b94409ea663ef6f8' into pricing-app
SchrodingersGat Aug 15, 2026
0233f09
Remove "part" field from StockItemCost model
SchrodingersGat Aug 15, 2026
3dcfd2a
Remove weighted 'cost' field
SchrodingersGat Aug 15, 2026
7259e0c
Remove custom str representation
SchrodingersGat Aug 15, 2026
8c11cf4
Adjust serializer
SchrodingersGat Aug 15, 2026
c737d15
Add data migration for stock item pricing
SchrodingersGat Aug 16, 2026
63b9980
Merge commit 'af74f1abf62ee735210665dbbc18a850292d4dc3' into pricing-app
SchrodingersGat Aug 16, 2026
569c634
Adjust migration
SchrodingersGat Aug 16, 2026
3ada943
Add pricing user role
SchrodingersGat Aug 16, 2026
f28a630
UI updates
SchrodingersGat Aug 16, 2026
5e65043
Add separate form for editing stock item cost
SchrodingersGat Aug 16, 2026
b82b3fa
Add StockItemCostEntry model
SchrodingersGat Aug 16, 2026
411cc0f
Add cost when receiving items against order
SchrodingersGat Aug 17, 2026
7841d0c
Disassembly
SchrodingersGat Aug 17, 2026
e8f22de
Merge commit '34732f0afa0e4dedc2300957f19e872f75307a7d' into pricing-app
SchrodingersGat Aug 18, 2026
3c94120
Adjust stock merge action
SchrodingersGat Aug 18, 2026
f0881d4
Update API changelog
SchrodingersGat Aug 18, 2026
9b8af8b
Remove purchase_price from raw StockItem serializer
SchrodingersGat Aug 18, 2026
2c036fb
remove old field
SchrodingersGat Aug 18, 2026
5e2e857
Merge commit 'dc059398b5469352a01e94523e514bc2b6d093c8' into pricing-app
SchrodingersGat Aug 21, 2026
0f7989d
Remove purchase_price field
SchrodingersGat Aug 21, 2026
a608c52
Update API filters
SchrodingersGat Aug 21, 2026
370102b
Add basic docs
SchrodingersGat Aug 21, 2026
25c6ee0
Accumulate manufacturing costs
SchrodingersGat Aug 22, 2026
1f692a0
refactor manufacturing costs into material costs
SchrodingersGat Aug 22, 2026
2155bd7
Merge commit '9d19b32b16d7424d349644b4fb8d9c3377d40365' into pricing-app
SchrodingersGat Aug 22, 2026
77d1a09
Add more complex unit test
SchrodingersGat Aug 22, 2026
d0756d4
Merge commit 'f063a6c67f9d3a4ba106c13c8a9aab10bccb22c5' into pricing-app
SchrodingersGat Aug 23, 2026
c37405a
Merge commit '528bb085d7ccde10d76a8c78580d4659cabbe45c' into pricing-app
SchrodingersGat Aug 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ The following Django apps are defined in `src/backend/InvenTree/`:
| `machine/` | Support for external machines and devices |
| `order/` | Purchase orders and sales orders |
| `part/` | Parts catalogue and categories |
| `pricing/` | Pricing calculation and caching |
| `stock/` | Stock items and locations |
| `report/` | Report templates and generation |
| `plugin/` | Plugin system |
Expand Down
11 changes: 11 additions & 0 deletions docs/docs/concepts/pricing.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ Throughout this documentation (and within InvenTree) the concepts of *cost* and
| Price | The theoretical amount of money required to pay for something. |
| Cost | The actual amount of money paid. |

## Cost Tracking

While *price* (as defined [above](#terminology)) is primarily tracked at the [Part](../part/pricing.md) level, *cost* - the actual amount paid - is tracked at the [Stock Item](../stock/costs.md) level, via one or more *cost entries* recorded against each stock item. These entries are automatically combined into a cached cost summary for the item, which in turn feeds into part-level purchase cost calculations.

Refer to the following pages for details specific to each level:

| Level | Documentation | Description |
| --- | --- | --- |
| Part | [Part Pricing](../part/pricing.md) | Cached price *ranges*, aggregated from multiple sources (BOM, supplier, internal, purchase history, variants, sale history) |
| Stock Item | [Stock Item Costs](../stock/costs.md) | Individual *cost entries* recorded against a specific stock item, and the calculated cost summary derived from them |

## Line Items

Orders (Purchase Orders, Sales Orders, and Return Orders) are made up of *line items*, each linking a *Quantity* to a *Unit Price*. A line item's *Line Total* is calculated as follows:
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/part/pricing.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Pricing information can be determined from multiple sources:
| --- | --- | ---|
| Internal Price | How much a part costs to make | [Part](../part/index.md) |
| Supplier Price | The price to theoretically purchase a part from a given supplier (with price-breaks) | [Supplier](../purchasing/supplier.md) |
| Purchase Cost | Historical cost information for parts purchased | [Purchase Order](../purchasing/purchase_order.md) |
| Purchase Cost | Historical cost information for parts purchased | [Purchase Order](../purchasing/purchase_order.md) / [Stock Item Costs](../stock/costs.md) |
| BOM Price | Total price for an assembly (total price of all component items) | [Part](../part/index.md) |

### Override Pricing
Expand Down Expand Up @@ -71,7 +71,7 @@ If the **Internal Price Override** setting is enabled, then internal pricing dat

### Purchase History

If the Part is designated as *purchaseable*, then historical purchase cost information is displayed (and used to calculate overall pricing). Purchase history data is collected from *completed* [purchase orders](../purchasing/purchase_order.md).
If the Part is designated as *purchaseable*, then historical purchase cost information is displayed (and used to calculate overall pricing). Purchase history data is collected from *completed* [purchase orders](../purchasing/purchase_order.md), and reflects the calculated unit cost of each associated [stock item](../stock/costs.md).

{{ image("part/pricing_purchase_history.png", "Purchase History") }}

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/part/stocktake.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ In particular, an individual *Stocktake* record tracks the following information

### Value Range of Stock on Hand

The total value range of stock on hand is calculated based on the provided pricing data. For stock items which have a recorded *cost* (e.g. *purchase price*), this value is used. If no direct pricing information is available for a particular stock item, the price range of the part itself is used.
The total value range of stock on hand is calculated based on the provided pricing data. For stock items which have a [recorded cost](../stock/costs.md), this value is used. If no direct cost information is available for a particular stock item, the price range of the part itself is used.

!!! info "Value Range"
Value data is provided as a *range* of values, accounting for any variability in available pricing data.
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/purchasing/purchase_order.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Serial numbers are *not* required to receive a trackable part - if left blank, a

### Item Value Currency

The unit cost of the purchase order line item is transferred across to the created stock item. By default, the same currency is used for the stock item as was used for the purchase order line item.
The unit cost of the purchase order line item is transferred across to the created stock item, recorded as a [purchase cost entry](../stock/costs.md#cost-types). By default, the same currency is used for the stock item as was used for the purchase order line item.

However, if the [Convert Currency](#purchase-order-settings) setting is enabled, the currency of the stock item will be converted to the [default currency](../concepts/pricing.md#default-currency) of the system. This may be useful when ordering stock in a different currency, to ensure that the unit cost of the stock item is converted to the base currency at the time of receipt.

Expand All @@ -140,9 +140,9 @@ Rather than receiving the bundle as a single opaque stock quantity, InvenTree al
1. Create a part to represent the bundle itself, and mark it as an [assembly](../part/index.md#assembly)
2. Link a [supplier part](./supplier.md#supplier-parts) to the bundle part, representing how it is purchased from the supplier
3. Define a [Bill of Materials](../manufacturing/bom.md) for the bundle part, listing each of the individual components and the quantity contained within a single bundle
4. Create and receive a purchase order against the bundle's supplier part, as normal - a single stock item is created for the bundle, retaining the purchase price and source purchase order of the order as a whole
4. Create and receive a purchase order against the bundle's supplier part, as normal - a single stock item is created for the bundle, retaining the [unit cost](../stock/costs.md) and source purchase order of the order as a whole

Once the individual components are actually required, the received bundle stock item can be [disassembled](../stock/disassemble.md) into its component parts. The purchase price and traceability data (batch code, source purchase order) of the original bundle are automatically apportioned across the newly generated component stock items.
Once the individual components are actually required, the received bundle stock item can be [disassembled](../stock/disassemble.md) into its component parts. The unit cost and traceability data (batch code, source purchase order) of the original bundle are automatically apportioned across the newly generated component stock items.

!!! tip "Pack Size vs Bundled Items"
A supplier part with a [pack size](./supplier.md#supplier-part-pack-size) greater than one still represents multiple units of the *same* part - the pack size simply determines how many physical units are added to stock per unit ordered. A *bundled* item is different: a single supplier part represents an assortment of *different* components, which must be disassembled before the individual components can be used or sold separately.
Expand Down
3 changes: 3 additions & 0 deletions docs/docs/stock/adjust.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ then the merge would not be possible.

If the conditions are met, the process of merging will add up the stock quantity for all items involved in the merge and create a new stock item with the final calculated quantity.

!!! info "Cost Merging"
If any of the merged items have a [recorded unit cost](./costs.md), the resulting stock item is assigned a new *purchase* [cost entry](./costs.md#cost-types), calculated as a quantity-weighted average of the cost of the merged items. If none of the merged items have recorded cost data, no cost entry is created.

To merge stock items, check two or more items in a stock table and click on the {{ icon("packages", title="Stock Actions") }} icon above the table, then click on {{ icon("arrow-merge", title="Merge") }} menu option.

In the Merge Stock Items form, user can decide to allow mismatched suppliers or status to be merged together (disabled by default).
Expand Down
98 changes: 98 additions & 0 deletions docs/docs/stock/costs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
title: Stock Item Costs
---

## Stock Item Costs

!!! info "Pricing Support"
Refer to the [Pricing Support](../concepts/pricing.md) documentation for a general introduction to cost and pricing concepts in InvenTree.

Each [stock item](./index.md) can have one or more *cost entries* recorded against it, representing the various contributions to its overall unit cost. These entries are automatically combined into a single cached *cost summary*, which is displayed throughout the InvenTree interface (for example in stock tables, and on the stock item detail page).

### Cost Entries

A *cost entry* records a single contribution to a stock item's unit cost, tagged with a [cost type](#cost-types), along with a *minimum* and *maximum* cost value (and their associated currency).

!!! info "Unit Cost, not Total Cost"
Cost entries always represent a **per-unit** cost, not the total value of the stock item. To determine the total value of a stock item, multiply its unit cost by its quantity - see [Stock Value](#stock-value) below.

Only one cost entry may exist per *(stock item, cost type)* pair - adding a new entry of the same type as an existing one updates that entry in place, rather than creating a duplicate.

#### Cost Types

| Cost Type | Description |
| --- | --- |
| Purchase | Cost taken directly from a purchase (e.g. a received purchase order line item) |
| Landed | Purchase cost plus additional landed costs (freight, duty, handling, etc) |
| Material | Cost of BOM components consumed by a build order, from allocated stock which itself has a recorded cost |
| Material (Estimated) | Cost of BOM components consumed by a build order, from allocated stock with no recorded cost - estimated from the component part's price range instead |
| Manufacturing | Reserved for manufacturing *process* cost (e.g. labor, overhead) added during a build - distinct from Material, which is the cost of the components consumed |
| Manual | Cost manually entered (or overridden) by a user |
| System | Cost calculated automatically by the pricing system (e.g. a pricing plugin) |

!!! warning "Manufacturing Process Cost"
*Manufacturing* process cost (labor, overhead) is not yet calculated anywhere - the cost type exists, but nothing populates it yet. Only *Material* cost (see [How Cost Entries are Created](#how-cost-entries-are-created) below) is currently recorded automatically from build orders - see [Known Limitations](#known-limitations) below.

### Cost Summary

The cost summary for a stock item is automatically (re)calculated as the sum of all of its cost entries, and cached for fast retrieval. It is not itself directly editable - it always reflects the current state of the underlying cost entries, and is recalculated automatically whenever an entry is added, updated, or removed.

If a stock item has no cost entries recorded against it, no cost summary is available for that item (rather than a summary reporting a zero cost).

!!! tip "Currency Conversion"
While individual cost entries retain their own original currency, the cost summary is always calculated in the [default currency](../concepts/pricing.md#default-currency). If a currency conversion rate is not available for one of the entries, that entry is excluded from the summary rather than being included unconverted - the summary will never mix currencies.

### Viewing and Editing Cost Entries

Cost entries for a stock item can be viewed - and added, edited, or deleted - from the *Stock Item Cost* tab on the stock item detail page.

| Column | Description |
| --- | --- |
| Cost Type | The [cost type](#cost-types) of the entry |
| Minimum Cost | The minimum unit cost |
| Maximum Cost | The maximum unit cost |
| Date | The date the entry was last updated |
| Notes | Optional notes describing the entry |

!!! info "Permissions"
Viewing, adding, editing and deleting cost entries requires the appropriate [Pricing permission role](../settings/permissions.md#roles), assigned via user groups.

### Displayed Cost Information

Cost summary information is displayed in a number of places throughout the InvenTree interface:

- The stock item detail page displays the *Unit Price* (unit cost) and *Stock Value* for the item, if cost data is available
- Stock tables can optionally display *Unit Price* and *Stock Value* columns - these are hidden by default, and only visible to users with the *Pricing* view permission

#### Stock Value

The *Stock Value* of a stock item is calculated as:

```
Stock Value = Unit Cost * Quantity
```

This value is not itself stored - it is calculated on the fly, from the cached cost summary and the item's current quantity.

### How Cost Entries are Created

Cost entries can be created (or updated) in a number of ways:

- **Manually**: a user with the appropriate permission can add, edit, or delete cost entries directly, via the *Stock Item Cost* tab described [above](#viewing-and-editing-cost-entries)
- **Purchase order receipt**: [receiving a line item](../purchasing/purchase_order.md#receive-line-items) against a purchase order automatically records a *Purchase* cost entry against each created stock item, based on the line item's unit price - see [Item Value Currency](../purchasing/purchase_order.md#item-value-currency)
- **Stock disassembly**: [disassembling](./disassemble.md#automatic-cost-allocation) a stock item automatically apportions its unit cost across the generated component stock items, recorded as a *Purchase* cost entry against each
- **Stock merge**: [merging](./adjust.md#merge-stock) two or more stock items automatically calculates a new *Purchase* cost entry for the merged item, as a quantity-weighted average of the cost of the merged items
- **Direct stock item creation / update**: the [Stock API](../api/index.md) accepts a `purchase_price` (and `purchase_price_currency`) value when creating or updating a stock item, which is recorded as a *Purchase* cost entry - this is a write-only convenience field, rather than a stored property of the stock item itself
- **Build order completion**: completing a [build order](../manufacturing/build.md) automatically records *Material* (or *Material (Estimated)*, if the allocated stock has no recorded cost) cost entries against each completed build output, based on the cost of the BOM components allocated to it - both stock directly allocated to a specific output, and stock allocated to the build order as a whole (apportioned evenly, per unit, across every completed output)

### Known Limitations

- **No cost history**: only the most recent value for each *(stock item, cost type)* pair is retained - there is no historical ledger of cost changes over time for a given stock item
- **Manufacturing process cost**: only the *cost of components* consumed by a build order is recorded automatically (as *Material* / *Material (Estimated)*) - manufacturing *process* cost (labor, overhead) is not yet calculated anywhere, even though the *Manufacturing* cost type exists for this purpose. This is planned for a future release.
- **Consumable and virtual BOM lines**: build order material cost does not yet account for consumable or virtual BOM lines - see the "Manufacturing Costs" section of `dev/todo/pricing.md` for the follow-up plan
- **CSV import**: bulk cost data cannot currently be imported via the stock item CSV import process

### Related Documentation

- [Pricing Support](../concepts/pricing.md) - general pricing and currency concepts
- [Part Pricing](../part/pricing.md) - part-level pricing, which incorporates stock item cost data into purchase history calculations
Loading
Loading