diff --git a/docs/docs/concepts/data_import.md b/docs/docs/concepts/data_import.md
index eac5712c86..10cafe2fd0 100644
--- a/docs/docs/concepts/data_import.md
+++ b/docs/docs/concepts/data_import.md
@@ -39,6 +39,12 @@ Some models allow for mapping based on other "natural key" fields (e.g. the `ref
Importing data is a multi-step process, which is managed via an *import session*. An import session is created when the user initiates a data import, and is used to track the progress of the data import process.
+### Import Session Status
+
+Each import session has a specific status code, indicating where it is in the import process:
+
+{{ statuscodes("DataImportStatusCode") }}
+
### Import Session List
The import session is managed by the InvenTree server, and all import session data is stored on the server. As the import process can be time-consuming, the user can navigate away from the import page and return later to check on the progress of the import.
diff --git a/docs/docs/hooks.py b/docs/docs/hooks.py
index fc1f98e4a0..4d3d0a5a72 100644
--- a/docs/docs/hooks.py
+++ b/docs/docs/hooks.py
@@ -260,14 +260,75 @@ def on_config(config, *args, **kwargs):
return config
+def check_status_codes_documented(gen_base):
+ """Check that every 'StatusCode' class is documented somewhere in the docs.
+
+ A class counts as documented if the `statuscodes()` macro has been called
+ for it from at least one markdown page (recorded in 'observed_status_codes.json').
+ """
+ expected_status_codes_file = gen_base.joinpath('inventree_status_codes.json')
+ observed_status_codes_file = gen_base.joinpath('observed_status_codes.json')
+
+ with open(observed_status_codes_file, encoding='utf-8') as f:
+ observed_status_codes = json.loads(f.read())
+
+ with open(expected_status_codes_file, encoding='utf-8') as f:
+ expected_status_codes = json.loads(f.read())
+
+ missing = [
+ name for name in expected_status_codes if name not in observed_status_codes
+ ]
+
+ if missing:
+ raise NotImplementedError(
+ 'Missing Status Codes:\n'
+ + f'There are {len(missing)} status code classes not documented via the `statuscodes()` macro:\n- '
+ + '\n- '.join(missing)
+ )
+
+
+def check_status_code_values_documented(gen_base):
+ """Check that every value of every 'StatusCode' class has a description.
+
+ Descriptions are sourced from the class docstring's `Attributes:` block (see
+ `export_status_codes.py` / e.g. `build.status_codes.BuildStatus`) - a status
+ value with no matching `Attributes:` entry exports with an empty description,
+ which this check catches.
+ """
+ expected_status_codes_file = gen_base.joinpath('inventree_status_codes.json')
+
+ with open(expected_status_codes_file, encoding='utf-8') as f:
+ expected_status_codes = json.loads(f.read())
+
+ missing = [
+ f'{class_name}.{value["name"]}'
+ for class_name, info in expected_status_codes.items()
+ for value in info['values']
+ if not value['description']
+ ]
+
+ if missing:
+ raise NotImplementedError(
+ 'Missing Status Code Descriptions:\n'
+ + f'There are {len(missing)} status code values with no description in their '
+ + "class docstring's `Attributes:` block:\n- "
+ + '\n- '.join(missing)
+ )
+
+
def on_post_build(*args, **kwargs):
"""Run after the build is complete.
- Here we check that all global settings and user settings are documented.
+ Here we check that all global settings and user settings are documented,
+ that every status code class is documented (via the `statuscodes` macro),
+ and that every individual status code value has a description.
"""
here = Path(__file__).parent
gen_base = here.parent.joinpath('generated')
+ check_status_codes_documented(gen_base)
+ check_status_code_values_documented(gen_base)
+
expected_settings_file = gen_base.joinpath('inventree_settings.json')
observed_settings_file = gen_base.joinpath('observed_settings.json')
diff --git a/docs/docs/manufacturing/build.md b/docs/docs/manufacturing/build.md
index 496e2c1dde..9e07f65580 100644
--- a/docs/docs/manufacturing/build.md
+++ b/docs/docs/manufacturing/build.md
@@ -71,25 +71,7 @@ Read more about build outputs [here](./output.md).
Each *Build Order* has an associated *Status* flag, which indicates the state of the build:
-| Status | Description |
-| ----------- | ----------- |
-| `Pending` | Build order has been created, but is not yet in production |
-| `Production` | Build order is currently in production |
-| `On Hold` | Build order has been placed on hold, but is still active |
-| `Cancelled` | Build order has been cancelled |
-| `Completed` | Build order has been completed |
-
-**Source Code**
-
-Refer to the source code for the Build Order status codes:
-
-::: build.status_codes.BuildStatus
- options:
- show_bases: False
- show_root_heading: False
- show_root_toc_entry: False
- show_source: True
- members: []
+{{ statuscodes("BuildStatus") }}
### Stock Allocations
diff --git a/docs/docs/plugins/machines/label_printer.md b/docs/docs/plugins/machines/label_printer.md
index fa35b95ef6..264000a4f9 100644
--- a/docs/docs/plugins/machines/label_printer.md
+++ b/docs/docs/plugins/machines/label_printer.md
@@ -10,17 +10,13 @@ Label printer machines can directly print labels for various items in InvenTree.
To implement a custom label printer driver, you need to write a plugin which implements the [MachineDriverMixin](../mixins/machine.md) and returns a list of label printer drivers in the `get_machine_drivers` method.
-Take a look at the most basic required code for a driver in this [example](./overview.md#example-driver). Next either implement the [`print_label`](#machine.machine_types.LabelPrinterBaseDriver.print_label) or [`print_labels`](#machine.machine_types.LabelPrinterBaseDriver.print_labels) function.
+Take a look at the most basic required code for a driver in this [example](./overview.md#example-driver). Next either implement the [`print_label`](#labelprintingdriver-api) or [`print_labels`](#labelprintingdriver-api) function.
### Label Printer Status
There are a couple of predefined status codes for label printers. By default the `UNKNOWN` status code is set for each machine, but they can be changed at any time by the driver. For more info about status code see [Machine status codes](./overview.md#machine-status).
-::: machine.machine_types.label_printer.LabelPrinterStatus
- options:
- heading_level: 4
- show_bases: false
- show_docstring_description: false
+{{ statuscodes("LabelPrinterStatus") }}
### LabelPrintingDriver API
diff --git a/docs/docs/purchasing/purchase_order.md b/docs/docs/purchasing/purchase_order.md
index e7654e7159..09ecf1070f 100644
--- a/docs/docs/purchasing/purchase_order.md
+++ b/docs/docs/purchasing/purchase_order.md
@@ -30,27 +30,7 @@ The following view modes are available:
Each Purchase Order has a specific status code which indicates the current state of the order:
-| Status | Description |
-| --- | --- |
-| Pending | The purchase order has been created, but has not been submitted to the supplier |
-| In Progress | The purchase order has been issued to the supplier, and is in progress |
-| On Hold | The purchase order has been placed on hold, but is still active |
-| Complete | The purchase order has been completed, and is now closed |
-| Cancelled | The purchase order was cancelled, and is now closed |
-| Lost | The purchase order was lost, and is now closed |
-| Returned | The purchase order was returned, and is now closed |
-
-**Source Code**
-
-Refer to the source code for the Purchase Order status codes:
-
-::: order.status_codes.PurchaseOrderStatus
- options:
- show_bases: False
- show_root_heading: False
- show_root_toc_entry: False
- show_source: True
- members: []
+{{ statuscodes("PurchaseOrderStatus") }}
Purchase Order Status supports [custom states](../concepts/custom_states.md).
diff --git a/docs/docs/sales/return_order.md b/docs/docs/sales/return_order.md
index b78b3fe3e4..79db9c1420 100644
--- a/docs/docs/sales/return_order.md
+++ b/docs/docs/sales/return_order.md
@@ -55,25 +55,7 @@ Various filters are available to configure which orders are displayed, and how t
Each Return Order has a specific status code, as follows:
-| Status | Description |
-| --- | --- |
-| Pending | The return order has been created, but not sent to the customer |
-| In Progress | The return order has been issued to the customer |
-| On Hold | The return order has been placed on hold, but is still active |
-| Complete | The return order was marked as complete, and is now closed |
-| Cancelled | The return order was cancelled, and is now closed |
-
-**Source Code**
-
-Refer to the source code for the Return Order status codes:
-
-::: order.status_codes.ReturnOrderStatus
- options:
- show_bases: False
- show_root_heading: False
- show_root_toc_entry: False
- show_source: True
- members: []
+{{ statuscodes("ReturnOrderStatus") }}
Return Order Status supports [custom states](../concepts/custom_states.md).
@@ -126,14 +108,7 @@ Each line item tracks a *Cost* (the cost associated with the return, repair, or
Each line item has an *Outcome*, which records the disposition decided for the returned item:
-| Outcome | Description |
-| --- | --- |
-| Pending | No outcome has been decided yet (default value for a new line item) |
-| Return | The item is to be returned to the customer, with no further action |
-| Repair | The item is to be repaired, and returned to the customer |
-| Replace | The item is to be replaced with a new item |
-| Refund | The item cannot be repaired, and a refund is to be issued |
-| Reject | The return is rejected |
+{{ statuscodes("ReturnOrderLineStatus") }}
The *Outcome* is not available when a line item is first created - it can only be set afterwards, by editing the line item. Selecting an outcome is a manual, record-keeping step only: InvenTree does not automatically create a replacement order, issue a refund, or link to a [repair](../manufacturing/index.md) process based on the selected outcome. Any follow-up action (raising a new [Sales Order](./sales_order.md) for a replacement, processing a refund, or tracking a repair) must currently be actioned separately.
diff --git a/docs/docs/sales/sales_order.md b/docs/docs/sales/sales_order.md
index bfb3a7b9db..1e1a65de70 100644
--- a/docs/docs/sales/sales_order.md
+++ b/docs/docs/sales/sales_order.md
@@ -31,28 +31,7 @@ The following view modes are available:
Each Sales Order has a specific status code, which represents the state of the order:
-| Status | Description |
-| --- | --- |
-| Pending | The sales order has been created, but has not been finalized or submitted |
-| In Progress | The sales order has been issued, and is in progress |
-| On Hold | The sales order has been placed on hold, but is still active |
-| Shipped | The sales order has been shipped, but is not yet complete |
-| Complete | The sales order is fully completed, and is now closed |
-| Cancelled | The sales order was cancelled, and is now closed |
-| Lost | The sales order was lost, and is now closed |
-| Returned | The sales order was returned, and is now closed |
-
-**Source Code**
-
-Refer to the source code for the Sales Order status codes:
-
-::: order.status_codes.SalesOrderStatus
- options:
- show_bases: False
- show_root_heading: False
- show_root_toc_entry: False
- show_source: True
- members: []
+{{ statuscodes("SalesOrderStatus") }}
Sales Order Status supports [custom states](../concepts/custom_states.md).
diff --git a/docs/docs/settings/permissions.md b/docs/docs/settings/permissions.md
index e40b206672..6c1eae7068 100644
--- a/docs/docs/settings/permissions.md
+++ b/docs/docs/settings/permissions.md
@@ -25,18 +25,7 @@ A *role* is a set of distinct permissions linked to a given subset of InvenTree
InvenTree functionality is split into a number of distinct roles. A group will have a set of permissions assigned to each of the following roles:
-| Role | Description |
-| ---- | ----------- |
-| **Admin** | The *admin* role is related to assigning user permissions. |
-| **BOM** | The *bom* role is related to accessing Bill of Materials data |
-| **Build** | The *build* role is related to accessing manufacturing / Build Order |
-| **Part** | The *part* role is related to accessing Part data |
-| **Part Category** | The *part category* role is related to accessing Part Category data |
-| **Purchase Order** | The *purchase* role is related to accessing Purchase Order data |
-| **Return Order** | The *return* role is related to accessing Return Order data |
-| **Sales Order** | The *sales* role is related to accessing Sales Order data |
-| **Stock Item** | The *stock item* role is related to accessing Stock Item data |
-| **Stock Location** | The *stock location* role is related to accessing Stock Location data |
+{{ roles() }}
{{ image("admin/roles.png", "Roles") }}
diff --git a/docs/docs/stock/status.md b/docs/docs/stock/status.md
index d153047941..d432c98620 100644
--- a/docs/docs/stock/status.md
+++ b/docs/docs/stock/status.md
@@ -10,32 +10,14 @@ Certain stock item status codes will restrict the availability of the stock item
Below is the list of available stock status codes and their meaning:
-| Status | Description | Available |
-| ----------- | ----------- | --- |
-| OK | Stock item is healthy, nothing wrong to report | Yes |
-| Attention needed | Stock item hasn't been checked or tested yet | Yes |
-| Damaged | Stock item is not functional in its present state | Yes |
-| Destroyed | Stock item has been destroyed | No |
-| Lost | Stock item has been lost | No |
-| Rejected | Stock item did not pass the quality control standards | No |
-| Quarantined | Stock item has been intentionally isolated and it unavailable | No |
+{{ statuscodes("StockStatus") }}
+
+Of these, only *OK*, *Attention needed*, *Damaged* and *Returned* count as "available" stock - the remainder are excluded from availability calculations.
The *status* of a given stock item is displayed on the stock item detail page:
{{ image("stock/stock_status_label.png", title="Stock status label") }}
-**Source Code**
-
-Refer to the source code for the Stock status codes:
-
-::: stock.status_codes.StockStatus
- options:
- show_bases: False
- show_root_heading: False
- show_root_toc_entry: False
- show_source: True
- members: []
-
### Custom Status Codes
Stock Status supports [custom states](../concepts/custom_states.md).
diff --git a/docs/docs/stock/tracking.md b/docs/docs/stock/tracking.md
index 6ece3f08aa..12ac65c48f 100644
--- a/docs/docs/stock/tracking.md
+++ b/docs/docs/stock/tracking.md
@@ -17,6 +17,12 @@ Some examples of events that may trigger stock tracking entries include:
- Allocation of stock items to orders (e.g. shipping items against sales orders)
- Consumption of stock items during build processes (e.g. using items to complete a build order)
+### Tracking Entry Types
+
+Each stock tracking entry records a specific *type*, indicating which event triggered it:
+
+{{ statuscodes("StockHistoryCode") }}
+
## Viewing Stock Tracking History
There are multiple ways to view the stock tracking history for a particular stock item or part via the user interface.
diff --git a/docs/docs/stock/transfer_order.md b/docs/docs/stock/transfer_order.md
index b5648f4505..72b985bfee 100644
--- a/docs/docs/stock/transfer_order.md
+++ b/docs/docs/stock/transfer_order.md
@@ -31,25 +31,7 @@ The following view modes are available:
Each Transfer Order has a specific status code, which represents the state of the order:
-| Status | Description |
-| --- | --- |
-| Pending | The transfer order has been created, but has not been finalized or submitted |
-| Issued | The transfer order has been issued, and is in progress |
-| On Hold | The transfer order has been placed on hold, but is still active |
-| Complete | The transfer order is fully completed, and is now closed |
-| Cancelled | The transfer order was cancelled, and is now closed |
-
-**Source Code**
-
-Refer to the source code for the Transfer Order status codes:
-
-::: order.status_codes.TransferOrderStatus
- options:
- show_bases: False
- show_root_heading: False
- show_root_toc_entry: False
- show_source: True
- members: []
+{{ statuscodes("TransferOrderStatus") }}
Transfer Order Status supports [custom states](../concepts/custom_states.md).
diff --git a/docs/main.py b/docs/main.py
index 9e44c5e8b1..b7aed84775 100644
--- a/docs/main.py
+++ b/docs/main.py
@@ -40,6 +40,8 @@ global USER_SETTINGS
global TAGS
global FILTERS
global REPORT_CONTEXT
+global STATUS_CODES
+global ROLES
# Read in the InvenTree settings file
here = Path(__file__).parent
@@ -60,6 +62,13 @@ with open(observed_settings_file, 'w', encoding='utf-8') as f:
# This is used to track which settings we have observed during the build process
f.write(json.dumps(data, indent=4))
+# File where we will *store* information on the status code classes we have observed
+observed_status_codes_file = gen_base.joinpath('observed_status_codes.json')
+
+# Overwrite the observed status codes file
+with open(observed_status_codes_file, 'w', encoding='utf-8') as f:
+ f.write(json.dumps({}, indent=4))
+
with open(settings_file, encoding='utf-8') as sf:
settings = json.load(sf)
@@ -73,9 +82,15 @@ with open(gen_base.joinpath('inventree_tags.yml'), encoding='utf-8') as f:
# Filters
with open(gen_base.joinpath('inventree_filters.yml'), encoding='utf-8') as f:
FILTERS = yaml.load(f, yaml.BaseLoader)
+# Status codes
+with open(gen_base.joinpath('inventree_status_codes.json'), encoding='utf-8') as f:
+ STATUS_CODES = json.load(f)
# Report context
with open(gen_base.joinpath('inventree_report_context.json'), encoding='utf-8') as f:
REPORT_CONTEXT = json.load(f)
+# User permission roles
+with open(gen_base.joinpath('inventree_roles.json'), encoding='utf-8') as f:
+ ROLES = json.load(f)
def get_repo_url(raw=False):
@@ -297,6 +312,38 @@ def define_env(env):
return includefile(fn, f'Template: {base}', fmt='html')
+ @env.macro
+ def statuscodes(class_name: str):
+ """Render a markdown table of status codes for the given StatusCode class.
+
+ Arguments:
+ class_name: The name of the `StatusCode` subclass to render (e.g. 'BuildStatus')
+
+ The table is built directly from `docs/generated/inventree_status_codes.json`
+ (produced by the `export_status_codes` management command), so it can never
+ drift out of sync with the status codes actually defined in the source code.
+ """
+ global STATUS_CODES
+
+ status_class = STATUS_CODES[class_name]
+
+ # Record that this status code class has been rendered somewhere in the docs
+ with open(observed_status_codes_file, encoding='utf-8') as f:
+ data = json.load(f)
+
+ data[class_name] = True
+
+ with open(observed_status_codes_file, 'w', encoding='utf-8') as f:
+ json.dump(data, f, indent=4)
+
+ ret_data = '| Status | Value | Description |\n| --- | --- | --- |\n'
+
+ for item in status_class['values']:
+ description = item['description'] or item['label']
+ ret_data += f'| {item["label"]} | {item["key"]} | {description} |\n'
+
+ return ret_data
+
def observe_setting(key: str, group: str):
"""Record that a particular setting has been observed.
@@ -429,6 +476,25 @@ def define_env(env):
return ret_data
+ @env.macro
+ def roles():
+ """Render a markdown table of the available user permission roles.
+
+ The table is built directly from `docs/generated/inventree_roles.json`
+ (produced by the `export_roles` management command, sourced from
+ `users.ruleset.RULESET_CHOICES`), so it can never drift out of sync with
+ the roles actually defined in the source code.
+ """
+ global ROLES
+
+ ret_data = '| Role | Description |\n| --- | --- |\n'
+
+ for role in ROLES:
+ description = role['description'] or role['label']
+ ret_data += f'| **{role["label"]}** | {description} |\n'
+
+ return ret_data
+
@env.macro
def report_context(type_: Literal['models', 'base'], model: str):
"""Extract information on a particular report context."""
diff --git a/src/backend/InvenTree/InvenTree/management/commands/export_roles.py b/src/backend/InvenTree/InvenTree/management/commands/export_roles.py
new file mode 100644
index 0000000000..3ca50b5477
--- /dev/null
+++ b/src/backend/InvenTree/InvenTree/management/commands/export_roles.py
@@ -0,0 +1,58 @@
+"""Custom management command to export all user permission roles.
+
+This is used to generate a JSON file which contains all of the roles (rulesets)
+available in InvenTree, so that they can be introspected by the InvenTree
+documentation system. This allows the roles table to be documented without
+having to manually duplicate the information (which otherwise silently drifts
+out of sync with the source code - e.g. a newly added ruleset going undocumented).
+"""
+
+import json
+
+from django.core.management.base import BaseCommand
+
+from users.ruleset import RULESET_CHOICES, RuleSetEnum
+
+from .export_report_context import parse_docstring
+
+
+class Command(BaseCommand):
+ """Extract user permission role information, and export to a JSON file."""
+
+ def add_arguments(self, parser):
+ """Add custom arguments for this command."""
+ parser.add_argument(
+ 'filename', type=str, help='Output filename for role definitions'
+ )
+
+ def handle(self, *args, **kwargs):
+ """Export role information to a JSON file."""
+ roles = discover_roles()
+
+ filename = kwargs.get('filename', 'inventree_roles.json')
+
+ with open(filename, 'w', encoding='utf-8') as f:
+ json.dump(roles, f, indent=4)
+
+ print(f"Exported InvenTree role definitions to '{filename}'")
+
+
+def discover_roles():
+ """Discover all available user permission roles (rulesets).
+
+ Returns a list of roles, in the order they are declared in `RULESET_CHOICES`.
+ Each role's description is sourced from `RuleSetEnum`'s docstring `Attributes:`
+ block, rather than being manually curated here - so a role's description can
+ never drift out of sync with its source.
+ """
+ attributes = parse_docstring(RuleSetEnum.__doc__ or '').get('Attributes', {})
+
+ return [
+ {
+ 'name': key.name,
+ 'key': str(key.value),
+ 'label': str(label),
+ 'description': attributes.get(key.name, ''),
+ }
+ for key, label in RULESET_CHOICES
+ ]
diff --git a/src/backend/InvenTree/InvenTree/management/commands/export_status_codes.py b/src/backend/InvenTree/InvenTree/management/commands/export_status_codes.py
new file mode 100644
index 0000000000..2faf4c9c3c
--- /dev/null
+++ b/src/backend/InvenTree/InvenTree/management/commands/export_status_codes.py
@@ -0,0 +1,84 @@
+"""Custom management command to export all status codes.
+
+This is used to generate a JSON file which contains all of the 'StatusCode'
+classes available in InvenTree, so that they can be introspected by the
+InvenTree documentation system. This allows status code tables to be
+documented without having to manually duplicate the information (which
+otherwise silently drifts out of sync with the source code).
+"""
+
+import json
+
+from django.core.management.base import BaseCommand
+
+from generic.states import StatusCode
+from InvenTree.helpers import inheritors
+
+from .export_report_context import parse_docstring
+
+
+class Command(BaseCommand):
+ """Extract status code information, and export to a JSON file."""
+
+ def add_arguments(self, parser):
+ """Add custom arguments for this command."""
+ parser.add_argument(
+ 'filename', type=str, help='Output filename for status code definitions'
+ )
+
+ def handle(self, *args, **kwargs):
+ """Export status code information to a JSON file."""
+ status_codes = discover_status_codes()
+
+ filename = kwargs.get('filename', 'inventree_status_codes.json')
+
+ with open(filename, 'w', encoding='utf-8') as f:
+ json.dump(status_codes, f, indent=4)
+
+ print(f"Exported InvenTree status code definitions to '{filename}'")
+
+
+def discover_status_codes():
+ """Discover all available status code classes.
+
+ Returns a dict, keyed by class name, of every concrete `StatusCode`
+ subclass (i.e. one which defines at least one status value - this
+ excludes abstract base classes such as `MachineStatus`, which is
+ subclassed per machine driver/plugin rather than used directly).
+
+ Each entry contains the class' module path and 'tag', plus a list of its
+ status values. The description of each value is sourced from the
+ class docstring's Google-style `Attributes:` block (see e.g.
+ `build.status_codes.BuildStatus`), rather than being manually curated
+ here - so a status code's description can never drift out of sync with
+ its source.
+ """
+ data = {}
+
+ for cls in inheritors(StatusCode):
+ # custom=False: this is a definition of the *built-in* status codes as
+ # they exist in source - user/plugin-defined custom states are runtime data
+ values = cls.dict(custom=False)
+
+ if not values:
+ # Abstract base class with no concrete status values (e.g. MachineStatus)
+ continue
+
+ attributes = parse_docstring(cls.__doc__ or '').get('Attributes', {})
+
+ data[cls.__name__] = {
+ 'module': cls.__module__,
+ 'tag': cls.tag(),
+ 'values': [
+ {
+ 'name': item['name'],
+ 'key': item['key'],
+ 'label': str(item['label']),
+ 'color': item['color'],
+ 'description': attributes.get(item['name'], ''),
+ }
+ for item in values.values()
+ ],
+ }
+
+ return dict(sorted(data.items()))
diff --git a/src/backend/InvenTree/build/status_codes.py b/src/backend/InvenTree/build/status_codes.py
index 75bf3945cc..4308b4ddbe 100644
--- a/src/backend/InvenTree/build/status_codes.py
+++ b/src/backend/InvenTree/build/status_codes.py
@@ -6,13 +6,21 @@ from generic.states import ColorEnum, StatusCode
class BuildStatus(StatusCode):
- """Build status codes."""
+ """Build status codes.
- PENDING = 10, _('Pending'), ColorEnum.secondary # Build is pending / active
- PRODUCTION = 20, _('Production'), ColorEnum.primary # Build is in production
- ON_HOLD = 25, _('On Hold'), ColorEnum.warning # Build is on hold
- CANCELLED = 30, _('Cancelled'), ColorEnum.danger # Build was cancelled
- COMPLETE = 40, _('Complete'), ColorEnum.success # Build is complete
+ Attributes:
+ PENDING: Build is pending / active
+ PRODUCTION: Build is in production
+ ON_HOLD: Build is on hold
+ CANCELLED: Build was cancelled
+ COMPLETE: Build is complete
+ """
+
+ PENDING = 10, _('Pending'), ColorEnum.secondary
+ PRODUCTION = 20, _('Production'), ColorEnum.primary
+ ON_HOLD = 25, _('On Hold'), ColorEnum.warning
+ CANCELLED = 30, _('Cancelled'), ColorEnum.danger
+ COMPLETE = 40, _('Complete'), ColorEnum.success
class BuildStatusGroups:
diff --git a/src/backend/InvenTree/importer/status_codes.py b/src/backend/InvenTree/importer/status_codes.py
index 2a884cec17..fc10cdd334 100644
--- a/src/backend/InvenTree/importer/status_codes.py
+++ b/src/backend/InvenTree/importer/status_codes.py
@@ -6,22 +6,18 @@ from generic.states import ColorEnum, StatusCode
class DataImportStatusCode(StatusCode):
- """Defines a set of status codes for a DataImportSession."""
+ """Defines a set of status codes for a DataImportSession.
- INITIAL = (
- 0,
- _('Initializing'),
- ColorEnum.secondary,
- ) # Import session has been created
- MAPPING = (
- 10,
- _('Mapping Columns'),
- ColorEnum.primary,
- ) # Import fields are being mapped
- IMPORTING = 20, _('Importing Data'), ColorEnum.primary # Data is being imported
- PROCESSING = (
- 30,
- _('Processing Data'),
- ColorEnum.primary,
- ) # Data is being processed by the user
- COMPLETE = 40, _('Complete'), ColorEnum.success # Import has been completed
+ Attributes:
+ INITIAL: Import session has been created
+ MAPPING: Import fields are being mapped
+ IMPORTING: Data is being imported
+ PROCESSING: Data is being processed by the user
+ COMPLETE: Import has been completed
+ """
+
+ INITIAL = 0, _('Initializing'), ColorEnum.secondary
+ MAPPING = 10, _('Mapping Columns'), ColorEnum.primary
+ IMPORTING = 20, _('Importing Data'), ColorEnum.primary
+ PROCESSING = 30, _('Processing Data'), ColorEnum.primary
+ COMPLETE = 40, _('Complete'), ColorEnum.success
diff --git a/src/backend/InvenTree/order/status_codes.py b/src/backend/InvenTree/order/status_codes.py
index 170a4a2a44..4d3235ea33 100644
--- a/src/backend/InvenTree/order/status_codes.py
+++ b/src/backend/InvenTree/order/status_codes.py
@@ -6,16 +6,25 @@ from generic.states import ColorEnum, StatusCode
class PurchaseOrderStatus(StatusCode):
- """Defines a set of status codes for a PurchaseOrder."""
+ """Defines a set of status codes for a PurchaseOrder.
- # Order status codes
- PENDING = 10, _('Pending'), ColorEnum.secondary # Order is pending (not yet placed)
- PLACED = 20, _('Placed'), ColorEnum.primary # Order has been placed with supplier
- ON_HOLD = 25, _('On Hold'), ColorEnum.warning # Order is on hold
- COMPLETE = 30, _('Complete'), ColorEnum.success # Order has been completed
- CANCELLED = 40, _('Cancelled'), ColorEnum.danger # Order was cancelled
- LOST = 50, _('Lost'), ColorEnum.warning # Order was lost
- RETURNED = 60, _('Returned'), ColorEnum.warning # Order was returned
+ Attributes:
+ PENDING: Order is pending (not yet placed)
+ PLACED: Order has been placed with supplier
+ ON_HOLD: Order is on hold
+ COMPLETE: Order has been completed
+ CANCELLED: Order was cancelled
+ LOST: Order was lost
+ RETURNED: Order was returned
+ """
+
+ PENDING = 10, _('Pending'), ColorEnum.secondary
+ PLACED = 20, _('Placed'), ColorEnum.primary
+ ON_HOLD = 25, _('On Hold'), ColorEnum.warning
+ COMPLETE = 30, _('Complete'), ColorEnum.success
+ CANCELLED = 40, _('Cancelled'), ColorEnum.danger
+ LOST = 50, _('Lost'), ColorEnum.warning
+ RETURNED = 60, _('Returned'), ColorEnum.warning
class PurchaseOrderStatusGroups:
@@ -39,20 +48,27 @@ class PurchaseOrderStatusGroups:
class SalesOrderStatus(StatusCode):
- """Defines a set of status codes for a SalesOrder."""
+ """Defines a set of status codes for a SalesOrder.
- PENDING = 10, _('Pending'), ColorEnum.secondary # Order is pending
- IN_PROGRESS = (
- 15,
- _('In Progress'),
- ColorEnum.primary,
- ) # Order has been issued, and is in progress
- SHIPPED = 20, _('Shipped'), ColorEnum.primary # Order has been shipped to customer
- ON_HOLD = 25, _('On Hold'), ColorEnum.warning # Order is on hold
- COMPLETE = 30, _('Complete'), ColorEnum.success # Order is complete
- CANCELLED = 40, _('Cancelled'), ColorEnum.danger # Order has been cancelled
- LOST = 50, _('Lost'), ColorEnum.warning # Order was lost
- RETURNED = 60, _('Returned'), ColorEnum.warning # Order was returned
+ Attributes:
+ PENDING: Order is pending
+ IN_PROGRESS: Order has been issued, and is in progress
+ SHIPPED: Order has been shipped to customer
+ ON_HOLD: Order is on hold
+ COMPLETE: Order is complete
+ CANCELLED: Order has been cancelled
+ LOST: Order was lost
+ RETURNED: Order was returned
+ """
+
+ PENDING = 10, _('Pending'), ColorEnum.secondary
+ IN_PROGRESS = 15, _('In Progress'), ColorEnum.primary
+ SHIPPED = 20, _('Shipped'), ColorEnum.primary
+ ON_HOLD = 25, _('On Hold'), ColorEnum.warning
+ COMPLETE = 30, _('Complete'), ColorEnum.success
+ CANCELLED = 40, _('Cancelled'), ColorEnum.danger
+ LOST = 50, _('Lost'), ColorEnum.warning
+ RETURNED = 60, _('Returned'), ColorEnum.warning
class SalesOrderStatusGroups:
@@ -71,16 +87,19 @@ class SalesOrderStatusGroups:
class ReturnOrderStatus(StatusCode):
- """Defines a set of status codes for a ReturnOrder."""
+ """Defines a set of status codes for a ReturnOrder.
+
+ Attributes:
+ PENDING: Order is pending, waiting for receipt of items
+ IN_PROGRESS: Items have been received, and are being inspected
+ ON_HOLD: Order is on hold
+ COMPLETE: Order is complete
+ CANCELLED: Order has been cancelled
+ """
- # Order is pending, waiting for receipt of items
PENDING = 10, _('Pending'), ColorEnum.secondary
-
- # Items have been received, and are being inspected
IN_PROGRESS = 20, _('In Progress'), ColorEnum.primary
-
ON_HOLD = 25, _('On Hold'), ColorEnum.warning
-
COMPLETE = 30, _('Complete'), ColorEnum.success
CANCELLED = 40, _('Cancelled'), ColorEnum.danger
@@ -98,35 +117,41 @@ class ReturnOrderStatusGroups:
class ReturnOrderLineStatus(StatusCode):
- """Defines a set of status codes for a ReturnOrderLineItem."""
+ """Defines a set of status codes for a ReturnOrderLineItem.
+
+ Attributes:
+ PENDING: No outcome has been decided yet (default value for a new line item)
+ RETURN: The item is to be returned to the customer, with no further action
+ REPAIR: The item is to be repaired, and returned to the customer
+ REPLACE: The item is to be replaced with a new item
+ REFUND: The item cannot be repaired, and a refund is to be issued
+ REJECT: The return is rejected
+ """
PENDING = 10, _('Pending'), ColorEnum.secondary
-
- # Item is to be returned to customer, no other action
RETURN = 20, _('Return'), ColorEnum.success
-
- # Item is to be repaired, and returned to customer
REPAIR = 30, _('Repair'), ColorEnum.primary
-
- # Item is to be replaced (new item shipped)
REPLACE = 40, _('Replace'), ColorEnum.warning
-
- # Item is to be refunded (cannot be repaired)
REFUND = 50, _('Refund'), ColorEnum.info
-
- # Item is rejected
REJECT = 60, _('Reject'), ColorEnum.danger
class TransferOrderStatus(StatusCode):
- """Defines a set of status codes for a TransferOrder."""
+ """Defines a set of status codes for a TransferOrder.
- # Order status codes
- PENDING = 10, _('Pending'), ColorEnum.secondary # Order is pending (not yet issued)
- ISSUED = 20, _('Issued'), ColorEnum.primary # Order has been issued
- ON_HOLD = 25, _('On Hold'), ColorEnum.warning # Order is on hold
- COMPLETE = 30, _('Complete'), ColorEnum.success # Order has been completed
- CANCELLED = 40, _('Cancelled'), ColorEnum.danger # Order was cancelled
+ Attributes:
+ PENDING: Order is pending (not yet issued)
+ ISSUED: Order has been issued
+ ON_HOLD: Order is on hold
+ COMPLETE: Order has been completed
+ CANCELLED: Order was cancelled
+ """
+
+ PENDING = 10, _('Pending'), ColorEnum.secondary
+ ISSUED = 20, _('Issued'), ColorEnum.primary
+ ON_HOLD = 25, _('On Hold'), ColorEnum.warning
+ COMPLETE = 30, _('Complete'), ColorEnum.success
+ CANCELLED = 40, _('Cancelled'), ColorEnum.danger
class TransferOrderStatusGroups:
diff --git a/src/backend/InvenTree/stock/status_codes.py b/src/backend/InvenTree/stock/status_codes.py
index 8f92a630b8..7f16af376f 100644
--- a/src/backend/InvenTree/stock/status_codes.py
+++ b/src/backend/InvenTree/stock/status_codes.py
@@ -6,24 +6,27 @@ from generic.states import ColorEnum, StatusCode
class StockStatus(StatusCode):
- """Status codes for Stock."""
+ """Status codes for Stock.
- OK = 10, _('OK'), ColorEnum.success # Item is OK
- ATTENTION = 50, _('Attention needed'), ColorEnum.warning # Item requires attention
- DAMAGED = 55, _('Damaged'), ColorEnum.warning # Item is damaged
- DESTROYED = 60, _('Destroyed'), ColorEnum.danger # Item is destroyed
- REJECTED = 65, _('Rejected'), ColorEnum.danger # Item is rejected
- LOST = 70, _('Lost'), ColorEnum.dark # Item has been lost
- QUARANTINED = (
- 75,
- _('Quarantined'),
- ColorEnum.info,
- ) # Item has been quarantined and is unavailable
- RETURNED = (
- 85,
- _('Returned'),
- ColorEnum.warning,
- ) # Item has been returned from a customer
+ Attributes:
+ OK: Stock item is healthy, nothing wrong to report
+ ATTENTION: Stock item hasn't been checked or tested yet
+ DAMAGED: Stock item is not functional in its present state
+ DESTROYED: Stock item has been destroyed
+ REJECTED: Stock item did not pass the quality control standards
+ LOST: Stock item has been lost
+ QUARANTINED: Stock item has been intentionally isolated and is unavailable
+ RETURNED: Stock item has been returned from a customer
+ """
+
+ OK = 10, _('OK'), ColorEnum.success
+ ATTENTION = 50, _('Attention needed'), ColorEnum.warning
+ DAMAGED = 55, _('Damaged'), ColorEnum.warning
+ DESTROYED = 60, _('Destroyed'), ColorEnum.danger
+ REJECTED = 65, _('Rejected'), ColorEnum.danger
+ LOST = 70, _('Lost'), ColorEnum.dark
+ QUARANTINED = 75, _('Quarantined'), ColorEnum.info
+ RETURNED = 85, _('Returned'), ColorEnum.warning
class StockStatusGroups:
@@ -39,7 +42,55 @@ class StockStatusGroups:
class StockHistoryCode(StatusCode):
- """Status codes for StockHistory."""
+ """Status codes for StockHistory.
+
+ Attributes:
+ LEGACY: Legacy stock tracking entry, created before tracking entry types existed
+ CREATED: Stock item created
+
+ EDITED: Stock item was manually edited
+ ASSIGNED_SERIAL: A serial number was assigned to the stock item
+
+ STOCK_COUNT: Stock was manually counted
+ STOCK_ADD: Stock was manually added
+ STOCK_REMOVE: Stock was manually removed
+ STOCK_SERIALIZED: Stock items were serialized
+
+ RETURNED_TO_STOCK: Stock item was returned to stock
+
+ STOCK_MOVE: The location of the stock item was changed
+ STOCK_UPDATE: Stock item was updated
+
+ INSTALLED_INTO_ASSEMBLY: Stock item was installed into an assembly
+ REMOVED_FROM_ASSEMBLY: Stock item was removed from an assembly
+
+ INSTALLED_CHILD_ITEM: A component item was installed into this stock item
+ REMOVED_CHILD_ITEM: A component item was removed from this stock item
+
+ SPLIT_FROM_PARENT: Stock item was split from a parent stock item
+ SPLIT_CHILD_ITEM: A child stock item was split from this stock item
+
+ MERGED_STOCK_ITEMS: Multiple stock items were merged into this one
+
+ DISASSEMBLED: Stock item was disassembled into its component items
+ CREATED_FROM_DISASSEMBLY: Stock item was created as a result of disassembly
+
+ CONVERTED_TO_VARIANT: Stock item was converted to a variant of its part
+
+ BUILD_OUTPUT_CREATED: Stock item was created as a build order output
+ BUILD_OUTPUT_COMPLETED: Stock item (a build order output) was completed
+ BUILD_OUTPUT_REJECTED: Stock item (a build order output) was rejected
+ BUILD_CONSUMED: Stock item was consumed by a build order
+
+ SHIPPED_AGAINST_SALES_ORDER: Stock item was shipped against a Sales Order
+
+ RECEIVED_AGAINST_PURCHASE_ORDER: Stock item was received against a Purchase Order
+
+ RETURNED_AGAINST_RETURN_ORDER: Stock item was returned against a Return Order
+
+ SENT_TO_CUSTOMER: Stock item was sent to a customer
+ RETURNED_FROM_CUSTOMER: Stock item was returned from a customer
+ """
LEGACY = 0, _('Legacy stock tracking entry')
@@ -55,7 +106,7 @@ class StockHistoryCode(StatusCode):
STOCK_REMOVE = 12, _('Stock manually removed')
STOCK_SERIALIZED = 13, _('Serialized stock items')
- RETURNED_TO_STOCK = 15, _('Returned to stock') # Stock item returned to stock
+ RETURNED_TO_STOCK = 15, _('Returned to stock')
# Location operations
STOCK_MOVE = 20, _('Location changed')
diff --git a/src/backend/InvenTree/users/ruleset.py b/src/backend/InvenTree/users/ruleset.py
index 3787eb89b9..0ed2ddf3fc 100644
--- a/src/backend/InvenTree/users/ruleset.py
+++ b/src/backend/InvenTree/users/ruleset.py
@@ -7,7 +7,21 @@ from generic.enums import StringEnum
class RuleSetEnum(StringEnum):
- """Enumeration of ruleset names."""
+ """Enumeration of ruleset names.
+
+ Attributes:
+ ADMIN: Assigning user permissions, and other administrative tasks
+ PART_CATEGORY: Accessing Part Category data
+ PART: Accessing Part data
+ BOM: Accessing Bill of Materials data
+ STOCK_LOCATION: Accessing Stock Location data
+ STOCK: Accessing Stock Item data
+ BUILD: Accessing manufacturing / Build Order data
+ PURCHASE_ORDER: Accessing Purchase Order data
+ SALES_ORDER: Accessing Sales Order data
+ RETURN_ORDER: Accessing Return Order data
+ TRANSFER_ORDER: Accessing Transfer Order data
+ """
ADMIN = 'admin'
PART_CATEGORY = 'part_category'
diff --git a/tasks.py b/tasks.py
index 519342c457..7156191e90 100644
--- a/tasks.py
+++ b/tasks.py
@@ -2037,6 +2037,8 @@ def export_definitions(c, basedir: str = ''):
base_path.joinpath('inventree_tags.yml'),
base_path.joinpath('inventree_filters.yml'),
base_path.joinpath('inventree_report_context.json'),
+ base_path.joinpath('inventree_status_codes.json'),
+ base_path.joinpath('inventree_roles.json'),
]
info('Exporting definitions...')
@@ -2051,6 +2053,12 @@ def export_definitions(c, basedir: str = ''):
check_file_existence(filenames[3], overwrite=True)
manage(c, f'export_report_context {filenames[3]}', pty=True)
+ check_file_existence(filenames[4], overwrite=True)
+ manage(c, f'export_status_codes {filenames[4]}', pty=True)
+
+ check_file_existence(filenames[5], overwrite=True)
+ manage(c, f'export_roles {filenames[5]}', pty=True)
+
info('Exporting definitions complete')