Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e2d92e5
Add basic structure for NonConformance
SchrodingersGat Aug 18, 2026
a7ceb0f
Implement basic UX
SchrodingersGat Aug 18, 2026
591e03f
Merge commit 'a48ba58ee997ba48fc4a13fa42cd248eb82ff40c' into ncr
SchrodingersGat Aug 20, 2026
bd03111
Fix icon
SchrodingersGat Aug 20, 2026
4345814
Remove duplicate "title" field
SchrodingersGat Aug 20, 2026
922a5f8
Merge commit 'dc059398b5469352a01e94523e514bc2b6d093c8' into ncr
SchrodingersGat Aug 21, 2026
608968a
Restrict stock item to match underlying part
SchrodingersGat Aug 21, 2026
9cd8227
Rename API endpoints
SchrodingersGat Aug 21, 2026
0a18ac2
Move disposition to the individual stock items
SchrodingersGat Aug 21, 2026
96f1c1b
Add unit tests
SchrodingersGat Aug 21, 2026
9a0330b
Fix 500 errors for transitions
SchrodingersGat Aug 21, 2026
222da05
Support report printing
SchrodingersGat Aug 21, 2026
731e809
Merge branch 'master' into ncr
SchrodingersGat Aug 22, 2026
2be5a7d
Merge commit '669c2c0511c7ec07fdd12efefe25f48cc9e923cc' into ncr
SchrodingersGat Aug 22, 2026
78462f8
Add basic docs
SchrodingersGat Aug 22, 2026
fcd349e
Add global setting to control NCR availability
SchrodingersGat Aug 22, 2026
a7f48a1
Align NCR status values with existing operations
SchrodingersGat Aug 22, 2026
6c368f4
Merge commit 'ebd1b6e936392cf1c99fb8f1ae7f025e279c1e53' into ncr
SchrodingersGat Aug 22, 2026
7269a40
Merge branch 'master' into ncr
SchrodingersGat Aug 23, 2026
fe7fe53
Merge branch 'master' into ncr
SchrodingersGat Aug 23, 2026
426791f
Merge commit '528bb085d7ccde10d76a8c78580d4659cabbe45c' into ncr
SchrodingersGat Aug 23, 2026
6e35cb9
Merge branch 'ncr' of github.com:SchrodingersGat/InvenTree into ncr
SchrodingersGat Aug 23, 2026
8d9e9f2
Merge commit 'a205717171894fa0da9e44b2558dc293ad811ccf' into ncr
SchrodingersGat Aug 30, 2026
af33dd6
Merge commit '3a0ade3265b70dc308cc9bfb4b057ee53d74399b' into ncr
SchrodingersGat Sep 17, 2026
b840477
FIx duplicate migration
SchrodingersGat Sep 17, 2026
8a84214
Fix typo
SchrodingersGat Sep 17, 2026
9f98586
use viewset instead
SchrodingersGat Sep 17, 2026
d0ab5ea
Merge branch 'master' into ncr
SchrodingersGat Oct 16, 2026
0ac3664
Merge branch 'master' into ncr
SchrodingersGat Oct 24, 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
6 changes: 6 additions & 0 deletions docs/docs/manufacturing/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ InvenTree allows users to allocate stock items to specific build orders, ensurin

Read more about stock allocation in the [Stock Allocation documentation](./allocate.md).

### Non-Conformance Reports

Quality problems identified against a part - a bad supplier batch, a failed inspection, or a build defect - can be tracked using Non-Conformance Reports (NCRs), from initial detection through investigation, disposition, and closure.

Read more about Non-Conformance Reports in the [NCR documentation](./ncr.md).

### Disassembly

The reverse process is also supported - an assembled stock item can be broken back down into its component parts, based on its BOM. This is useful for reworking or scrapping an assembly, or for splitting a bundled "kit" product purchased from a supplier into its individual components.
Expand Down
183 changes: 183 additions & 0 deletions docs/docs/manufacturing/ncr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
title: Non-Conformance Reports
---

## Non-Conformance Reports

A *Non-Conformance Report* (NCR) records a quality problem identified against a [Part](../part/index.md) - for example a bad supplier batch, a failed inspection, a customer complaint, or a defect found during a build.

An NCR behaves like a lightweight order - it has a reference number, a status workflow, and can be assigned to a responsible user or group - but its purpose is to *track a problem to closure*, not to move stock or money. Raising an NCR does not automatically affect stock levels, pricing, or any linked order.

!!! tip "Also Known As"
A Non-Conformance Report may also be referred to as a *Non-Conformity Report*, or simply an *NCR*.

### Enable Non-Conformance Report Functionality

By default, Non-Conformance Report functionality is disabled - it must be enabled by a *staff* user from the settings page, via the {{ globalsetting("NCR_ENABLED", short=True) }} setting. Once enabled, the "Non-Conformances" tab becomes available on the Manufacturing page.

### View Non-Conformance Reports

To navigate to the Non-Conformance Report display, select *Manufacturing* from the main navigation menu, and *Non-Conformances* from the sidebar. This shows a table of all Non-Conformance Reports, which can be filtered to only show the reports you are interested in.

### NCR Permissions

[Permissions](../settings/permissions.md) for Non-Conformance Reports are managed via the `ncr` permission group. Users are assigned appropriate permissions based on the groups they are part of. Note that this is a distinct permission group from `build` - a user does not require any Build Order permissions to view or raise NCRs.

### NCR Status

Each Non-Conformance Report has a specific status code, indicating where it is in its lifecycle:

| Status | Description |
| --- | --- |
| Pending | The NCR has been raised, but not yet investigated |
| In Progress | Root cause investigation is underway |
| Cancelled | The NCR was raised in error, or withdrawn |
| Complete | The NCR has been closed out |

**Source Code**

Refer to the source code for the NCR status codes:

::: build.status_codes.NonConformanceStatus
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []

NCR Status supports [custom states](../concepts/custom_states.md).

!!! info "Status vs. Disposition"
*Status* tracks where the NCR is in its own lifecycle. *Disposition* - what has been decided about the affected material - is a separate concept, recorded against each individual [linked stock item](#linked-stock-items) rather than the NCR as a whole, and validated as part of the [Complete](#complete) action rather than being its own status. See [Item Disposition](#item-disposition) below.

## Create a Non-Conformance Report

From the Non-Conformance Report table, click on <span class='badge inventree add'>{{ icon("plus") }} Report Non-Conformance</span> to open the "Report Non-Conformance" form.

### NCR Reference

Each NCR is uniquely identified by its *Reference* field, automatically generated according to the configured [reference pattern](../settings/reference.md).

### NCR Parameters

The following parameters are available for each NCR, and can be edited by the user:

| Parameter | Description |
| --- | --- |
| Reference | NCR reference e.g. 'NCR-0001' |
| Part | The [part](../part/index.md) against which the non-conformance was raised (required) |
| Description | Description of the non-conformance (required) |
| Severity | Optional severity classification - *Minor*, *Major*, or *Critical* |
| Build Order | Optional link to the [build order](./build.md) which surfaced the problem |
| Sales Order | Optional link to the related [sales order](../sales/sales_order.md) |
| Purchase Order | Optional link to the related [purchase order](../purchasing/purchase_order.md) |
| Return Order | Optional link to the related [return order](../sales/return_order.md) |
| Quantity | Optional affected quantity, as a fact about the world - this is purely informational, and is independent of the quantity recorded against any [linked stock items](#linked-stock-items) |
| Root Cause | Root cause of the problem, typically filled in during investigation |
| Corrective Action | Corrective action taken to resolve the problem |
| Responsible | User (or group of users) responsible for resolving the NCR |
| Target Date | Target date for resolution of the NCR |
| External Link | Link to external webpage |
| Notes | NCR notes, supports markdown |

The part is the only mandatory link - an NCR can be raised with no order context at all (for example, one found during a stocktake or a random audit), or optionally linked to whichever order surfaced the problem.

### Responsible Owner

The NCR can be assigned to a responsible *owner*, which is either a user or a group.

## Non-Conformance Report Detail

Selecting an individual NCR from the table navigates to the NCR detail page, which provides an overview of the report and the available actions.

### Edit NCR

The NCR details can be edited by selecting the {{ icon("edit", color="blue", title="Edit") }} icon under the {{ icon("tools") }} actions menu.

### Linked Stock Items

The *Stock Items* tab lists the [stock items](../stock/index.md) affected by this non-conformance. Stock items can be linked (and unlinked) from this tab.

!!! info "Matching Part Required"
Only stock items of the same [part](../part/index.md) as the NCR can be linked - the part is the anchor for the whole report, so a mismatched stock item is rejected.

Each linked stock item optionally records an affected *Quantity* (a portion of the stock item, if not all of it is affected) and free-text *Notes*.

#### Item Disposition

Each linked stock item has its own *Disposition*, recording what has been decided for that specific item:

| Disposition | Description |
| --- | --- |
| Pending | No disposition has been decided yet (default value for a newly-linked item) |
| Use As Is | The item is acceptable to use without further action |
| Rework | The item is to be reworked to meet requirements |
| Repair | The item is to be repaired |
| Scrap | The item is to be scrapped |
| Return to Supplier | The item is to be returned to the supplier |

**Source Code**

Refer to the source code for the NCR disposition codes:

::: build.status_codes.NonConformanceDisposition
options:
show_bases: False
show_root_heading: False
show_root_toc_entry: False
show_source: True
members: []

NCR Disposition supports [custom states](../concepts/custom_states.md).

!!! info "Why Per-Item, Not Per-NCR?"
A single NCR can cover a batch of material where different units end up with different outcomes - for example, some units might be usable as-is while others need to be scrapped. Recording disposition against each linked stock item (rather than a single value on the NCR itself) allows for this.

Disposition is set by editing a linked stock item directly - it is not a status transition of its own.

### Attachments

File attachments can be uploaded against the NCR, and are displayed in the *Attachments* tab - for example, photos of the defect or supporting inspection documents.

### Notes

NCR notes (which support markdown formatting) are displayed in the *Notes* tab.

## Investigate

To move an NCR into investigation, click the {{ icon("issue", color="blue", title="Investigate") }} *Investigate* button on the NCR detail page. This is available while the NCR is *Pending*, and moves it into the *In Progress* status.

!!! info "Optional Step"
Investigating first is optional - an NCR can also be completed directly from *Pending*.

## Complete

Click the {{ icon("complete", color="green", title="Complete") }} *Complete* button to close out the NCR. This is available while the NCR is *Pending* or *In Progress*.

!!! warning "All Items Must Be Dispositioned"
Completing an NCR validates that every [linked stock item](#linked-stock-items) has been assigned a [disposition](#item-disposition) other than *Pending* - if any linked item is still *Pending*, the action is rejected. An NCR with no linked stock items has nothing to check, and completes freely.

## Cancel

If an NCR was raised in error, or should otherwise be withdrawn, it can be cancelled instead of completed. Click the {{ icon("cancel", color="red", title="Cancel") }} *Cancel* option under the {{ icon("tools") }} actions menu to cancel the NCR. This is available while the NCR is *Pending* or *In Progress*.

!!! info "No Reopening"
Once an NCR is *Complete* or *Cancelled*, it is final - the same as a [Build Order](./build.md), it cannot be reopened.

## NCR Scheduling

An NCR can optionally be assigned a *Target Date* for resolution. If the target date passes while the NCR is still *Pending* or *In Progress*, the NCR is considered *overdue*. This can be useful for tracking NCRs which are behind schedule.

## Non-Conformance Report Reports

Custom [reports](../report/index.md) can be generated against each Non-Conformance Report.

## Non-Conformance Report Settings

The following [global settings](../settings/global.md) are available for adjusting the behavior of Non-Conformance Reports:

| Name | Description | Default | Units |
| ---- | ----------- | ------- | ----- |
{{ globalsetting("NCR_ENABLED") }}
{{ globalsetting("NCR_REFERENCE_PATTERN") }}
1 change: 1 addition & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ nav:
- Build Outputs: manufacturing/output.md
- Required Quantity: manufacturing/required.md
- Allocating Stock: manufacturing/allocate.md
- Non-Conformance Reports: manufacturing/ncr.md
- External Manufacturing: manufacturing/external.md
- Example Build Order: manufacturing/example.md
- Purchasing:
Expand Down
38 changes: 37 additions & 1 deletion src/backend/InvenTree/build/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

from django.contrib import admin

from build.models import Build, BuildItem, BuildLine
from build.models import (
Build,
BuildItem,
BuildLine,
NonConformance,
NonConformanceStockItem,
)


@admin.register(Build)
Expand Down Expand Up @@ -52,3 +58,33 @@ class BuildLineAdmin(admin.ModelAdmin):
search_fields = ['build__title', 'build__reference', 'bom_item__sub_part__name']

autocomplete_fields = ['bom_item', 'build']


@admin.register(NonConformance)
class NonConformanceAdmin(admin.ModelAdmin):
"""Class for managing the NonConformance model via the admin interface."""

exclude = ['reference_int']

list_display = ('reference', 'description', 'part', 'status')

search_fields = ['reference', 'description', 'part__name', 'part__description']

autocomplete_fields = [
'part',
'build_order',
'sales_order',
'purchase_order',
'return_order',
'responsible',
'raised_by',
]


@admin.register(NonConformanceStockItem)
class NonConformanceStockItemAdmin(admin.ModelAdmin):
"""Class for managing the NonConformanceStockItem model via the admin interface."""

list_display = ('ncr', 'stock_item', 'quantity', 'disposition')

autocomplete_fields = ['ncr', 'stock_item']
Loading
Loading