From bc98e4bab6deb543b64960be2e52f88b4242d8e6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 23 Aug 2026 18:48:05 +1000 Subject: [PATCH] Auto-extract StatusCode values for docs (#12686) * Auto-extract StatusCode values for docs * Extract user roles from code * Fix links * Remove extraneous source code in docs --- docs/docs/concepts/data_import.md | 6 + docs/docs/hooks.py | 63 +++++++++- docs/docs/manufacturing/build.md | 20 +-- docs/docs/plugins/machines/label_printer.md | 8 +- docs/docs/purchasing/purchase_order.md | 22 +--- docs/docs/sales/return_order.md | 29 +---- docs/docs/sales/sales_order.md | 23 +--- docs/docs/settings/permissions.md | 13 +- docs/docs/stock/status.md | 24 +--- docs/docs/stock/tracking.md | 6 + docs/docs/stock/transfer_order.md | 20 +-- docs/main.py | 66 ++++++++++ .../management/commands/export_roles.py | 58 +++++++++ .../commands/export_status_codes.py | 84 +++++++++++++ src/backend/InvenTree/build/status_codes.py | 20 ++- .../InvenTree/importer/status_codes.py | 32 +++-- src/backend/InvenTree/order/status_codes.py | 117 +++++++++++------- src/backend/InvenTree/stock/status_codes.py | 89 ++++++++++--- src/backend/InvenTree/users/ruleset.py | 16 ++- tasks.py | 8 ++ 20 files changed, 486 insertions(+), 238 deletions(-) create mode 100644 src/backend/InvenTree/InvenTree/management/commands/export_roles.py create mode 100644 src/backend/InvenTree/InvenTree/management/commands/export_status_codes.py 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')