mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Build order rules (#7842)
* Add new global setting * Check if there are open children before completing a build * Adds management command to export settings definition * Fix settings export * Extract settings data into documentation * Add global settings spec * User settings * Revert strict mode * Tweak unit test * Remove unreachable code * Always export settings first * Remove unused macro * Remove old images * Re-add missing docs strings * Tweak docs * Remove unused import
This commit is contained in:
parent
556a3161e8
commit
42183a3a3f
1
.gitignore
vendored
1
.gitignore
vendored
@ -111,3 +111,4 @@ InvenTree/web/static
|
|||||||
docs/schema.yml
|
docs/schema.yml
|
||||||
docs/docs/api/*.yml
|
docs/docs/api/*.yml
|
||||||
docs/docs/api/schema/*.yml
|
docs/docs/api/schema/*.yml
|
||||||
|
inventree_settings.json
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 56 KiB |
Binary file not shown.
Before Width: | Height: | Size: 84 KiB |
24
docs/docs/build/build.md
vendored
24
docs/docs/build/build.md
vendored
@ -265,18 +265,16 @@ Build orders may (optionally) have a target complete date specified. If this dat
|
|||||||
- Builds can be filtered by overdue status in the build list
|
- Builds can be filtered by overdue status in the build list
|
||||||
- Overdue builds will be displayed on the home page
|
- Overdue builds will be displayed on the home page
|
||||||
|
|
||||||
## Build Order Restrictions
|
## Build Order Settings
|
||||||
|
|
||||||
There are a number of optional restrictions which can be applied to build orders, which may be enabled or disabled in the system settings:
|
The following [global settings](../settings/global.md) are available for adjusting the behavior of build orders:
|
||||||
|
|
||||||
### Require Active Part
|
| Name | Description | Default | Units |
|
||||||
|
| ---- | ----------- | ------- | ----- |
|
||||||
If this option is enabled, build orders can only be created for parts which are marked as [Active](../part/part.md#active-parts).
|
{{ globalsetting("BUILDORDER_REFERENCE_PATTERN") }}
|
||||||
|
{{ globalsetting("BUILDORDER_REQUIRE_RESPONSIBLE") }}
|
||||||
### Require Locked Part
|
{{ globalsetting("BUILDORDER_REQUIRE_ACTIVE_PART") }}
|
||||||
|
{{ globalsetting("BUILDORDER_REQUIRE_LOCKED_PART") }}
|
||||||
If this option is enabled, build orders can only be created for parts which are marked as [Locked](../part/part.md#locked-parts).
|
{{ globalsetting("BUILDORDER_REQUIRE_VALID_BOM") }}
|
||||||
|
{{ globalsetting("BUILDORDER_REQUIRE_CLOSED_CHILDS") }}
|
||||||
### Require Valid BOM
|
{{ globalsetting("PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS") }}
|
||||||
|
|
||||||
If this option is enabled, build orders can only be created for parts which have a valid [Bill of Materials](./bom.md) defined.
|
|
||||||
|
@ -139,3 +139,14 @@ This view can be accessed externally as an ICS calendar using a URL like the fol
|
|||||||
`http://inventree.example.org/api/order/calendar/purchase-order/calendar.ics`
|
`http://inventree.example.org/api/order/calendar/purchase-order/calendar.ics`
|
||||||
|
|
||||||
by default, completed orders are not exported. These can be included by appending `?include_completed=True` to the URL.
|
by default, completed orders are not exported. These can be included by appending `?include_completed=True` to the URL.
|
||||||
|
|
||||||
|
## Purchase Order Settings
|
||||||
|
|
||||||
|
The following [global settings](../settings/global.md) are available for purchase orders:
|
||||||
|
|
||||||
|
| Name | Description | Default | Units |
|
||||||
|
| ---- | ----------- | ------- | ----- |
|
||||||
|
{{ globalsetting("PURCHASEORDER_REFERENCE_PATTERN") }}
|
||||||
|
{{ globalsetting("PURCHASEORDER_REQUIRE_RESPONSIBLE") }}
|
||||||
|
{{ globalsetting("PURCHASEORDER_EDIT_COMPLETED_ORDERS") }}
|
||||||
|
{{ globalsetting("PURCHASEORDER_AUTO_COMPLETE") }}
|
||||||
|
@ -121,3 +121,14 @@ This view can be accessed externally as an ICS calendar using a URL like the fol
|
|||||||
`http://inventree.example.org/api/order/calendar/return-order/calendar.ics`
|
`http://inventree.example.org/api/order/calendar/return-order/calendar.ics`
|
||||||
|
|
||||||
by default, completed orders are not exported. These can be included by appending `?include_completed=True` to the URL.
|
by default, completed orders are not exported. These can be included by appending `?include_completed=True` to the URL.
|
||||||
|
|
||||||
|
## Return Order Settings
|
||||||
|
|
||||||
|
The following [global settings](../settings/global.md) are available for return orders:
|
||||||
|
|
||||||
|
| Name | Description | Default | Units |
|
||||||
|
| ---- | ----------- | ------- | ----- |
|
||||||
|
{{ globalsetting("RETURNORDER_ENABLED") }}
|
||||||
|
{{ globalsetting("RETURNORDER_REFERENCE_PATTERN") }}
|
||||||
|
{{ globalsetting("RETURNORDER_REQUIRE_RESPONSIBLE") }}
|
||||||
|
{{ globalsetting("RETURNORDER_EDIT_COMPLETED_ORDERS") }}
|
||||||
|
@ -183,3 +183,15 @@ All these fields can be edited by the user:
|
|||||||
{% with id="edit-shipment", url="order/edit_shipment.png", description="Edit shipment" %}
|
{% with id="edit-shipment", url="order/edit_shipment.png", description="Edit shipment" %}
|
||||||
{% include "img.html" %}
|
{% include "img.html" %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
|
|
||||||
|
## Sales Order Settings
|
||||||
|
|
||||||
|
The following [global settings](../settings/global.md) are available for sales orders:
|
||||||
|
|
||||||
|
| Name | Description | Default | Units |
|
||||||
|
| ---- | ----------- | ------- | ----- |
|
||||||
|
{{ globalsetting("SALESORDER_REFERENCE_PATTERN") }}
|
||||||
|
{{ globalsetting("SALESORDER_REQUIRE_RESPONSIBLE") }}
|
||||||
|
{{ globalsetting("SALESORDER_DEFAULT_SHIPMENT") }}
|
||||||
|
{{ globalsetting("SALESORDER_EDIT_COMPLETED_ORDERS") }}
|
||||||
|
{{ globalsetting("SALESORDER_SHIP_COMPLETE") }}
|
||||||
|
@ -24,12 +24,7 @@ If a different currency exchange backend is needed, or a custom implementation i
|
|||||||
|
|
||||||
### Currency Settings
|
### Currency Settings
|
||||||
|
|
||||||
In the [settings screen](./global.md), under the *Pricing* section, the following currency settings are available:
|
Refer to the [global settings](./global.md#pricing-and-currency) documentation for more information on available currency settings.
|
||||||
|
|
||||||
| Setting | Description | Default Value |
|
|
||||||
| --- | --- |
|
|
||||||
| Default Currency | The selected *default* currency for the system. | USD |
|
|
||||||
| Supported Currencies | The list of supported currencies for the system. | AUD, CAD, CNY, EUR, GBP, JPY, NZD, USD |
|
|
||||||
|
|
||||||
#### Supported Currencies
|
#### Supported Currencies
|
||||||
|
|
||||||
|
@ -17,120 +17,139 @@ Global settings are arranged in the following categories:
|
|||||||
|
|
||||||
### Server Settings
|
### Server Settings
|
||||||
|
|
||||||
Configuration of basic server settings.
|
Configuration of basic server settings:
|
||||||
|
|
||||||
|
| Name | Description | Default | Units |
|
||||||
|
| ---- | ----------- | ------- | ----- |
|
||||||
|
{{ globalsetting("INVENTREE_BASE_URL") }}
|
||||||
|
{{ globalsetting("INVENTREE_COMPANY_NAME") }}
|
||||||
|
{{ globalsetting("INVENTREE_INSTANCE") }}
|
||||||
|
{{ globalsetting("INVENTREE_INSTANCE_TITLE") }}
|
||||||
|
{{ globalsetting("INVENTREE_RESTRICT_ABOUT") }}
|
||||||
|
{{ globalsetting("DISPLAY_FULL_NAMES") }}
|
||||||
|
{{ globalsetting("INVENTREE_UPDATE_CHECK_INTERVAL") }}
|
||||||
|
{{ globalsetting("INVENTREE_DOWNLOAD_FROM_URL") }}
|
||||||
|
{{ globalsetting("INVENTREE_DOWNLOAD_IMAGE_MAX_SIZE") }}
|
||||||
|
{{ globalsetting("INVENTREE_DOWNLOAD_FROM_URL_USER_AGENT") }}
|
||||||
|
{{ globalsetting("INVENTREE_REQUIRE_CONFIRM") }}
|
||||||
|
{{ globalsetting("INVENTREE_STRICT_URLS") }}
|
||||||
|
{{ globalsetting("INVENTREE_TREE_DEPTH") }}
|
||||||
|
{{ globalsetting("INVENTREE_BACKUP_ENABLE") }}
|
||||||
|
{{ globalsetting("INVENTREE_BACKUP_DAYS") }}
|
||||||
|
{{ globalsetting("INVENTREE_DELETE_TASKS_DAYS") }}
|
||||||
|
{{ globalsetting("INVENTREE_DELETE_ERRORS_DAYS") }}
|
||||||
|
{{ globalsetting("INVENTREE_DELETE_NOTIFICATIONS_DAYS") }}
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| InvenTree Instance Name | String | String descriptor for the InvenTree server instance | InvenTree Server |
|
|
||||||
| Use Instance Name | Boolean | Use instance name in title bars | False |
|
|
||||||
| Restrict showing `about` | Boolean | Show the `about` modal only to superusers | False |
|
|
||||||
| Base URL | String | Base URL for server instance | *blank* |
|
|
||||||
| Company Name | String | Company name | My company name |
|
|
||||||
| Download from URL | Boolean | Allow downloading of images from remote URLs | False |
|
|
||||||
|
|
||||||
### Login Settings
|
### Login Settings
|
||||||
|
|
||||||
Change how logins, password-forgot, signups are handled.
|
Change how logins, password-forgot, signups are handled:
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
| Name | Description | Default | Units |
|
||||||
| --- | --- | --- | --- |
|
| ---- | ----------- | ------- | ----- |
|
||||||
| Enable registration | Boolean | Enable self-registration for users on the login-pages | False |
|
{{ globalsetting("LOGIN_ENABLE_PWD_FORGOT") }}
|
||||||
| Enable SSO | Boolean | Enable SSO on the login-pages | False |
|
{{ globalsetting("LOGIN_MAIL_REQUIRED") }}
|
||||||
| Enable SSO registration | Boolean | Enable self-registration for users via SSO on the login-pages | False |
|
{{ globalsetting("LOGIN_ENFORCE_MFA") }}
|
||||||
| Enable SSO group sync | Boolean | Enable synchronizing InvenTree groups directly from the IdP | False |
|
{{ globalsetting("LOGIN_ENABLE_REG") }}
|
||||||
| SSO group key | String | The name of the groups claim attribute provided by the IdP | |
|
{{ globalsetting("LOGIN_SIGNUP_MAIL_TWICE") }}
|
||||||
| SSO group map | String (JSON) | A mapping from SSO groups to local InvenTree groups | {} |
|
{{ globalsetting("LOGIN_SIGNUP_PWD_TWICE") }}
|
||||||
| Remove groups outside of SSO | Boolean | Whether groups assigned to the user should be removed if they are not backend by the IdP. Disabling this setting might cause security issues | True |
|
{{ globalsetting("SIGNUP_GROUP") }}
|
||||||
| Enable password forgot | Boolean | Enable password forgot function on the login-pages.<br><br>This will let users reset their passwords on their own. For this feature to work you need to configure E-mail | True |
|
{{ globalsetting("LOGIN_SIGNUP_MAIL_RESTRICTION") }}
|
||||||
| E-Mail required | Boolean | Require user to supply e-mail on signup.<br><br>Without a way (e-mail) to contact the user notifications and security features might not work! | False |
|
{{ globalsetting("LOGIN_ENABLE_SSO") }}
|
||||||
| Enforce MFA | Boolean | Users must use multifactor security.<br><br>This forces each user to setup MFA and use it on each authentication | False |
|
{{ globalsetting("LOGIN_ENABLE_SSO_REG") }}
|
||||||
| Mail twice | Boolean | On signup ask users twice for their mail | False |
|
{{ globalsetting("LOGIN_SIGNUP_SSO_AUTO") }}
|
||||||
| Password twice | Boolean | On signup ask users twice for their password | True |
|
{{ globalsetting("LOGIN_ENABLE_SSO_GROUP_SYNC") }}
|
||||||
| Auto-fill SSO users | Boolean | Automatically fill out user-details from SSO account-data.<br><br>If this feature is enabled the user is only asked for their username, first- and surname if those values can not be gathered from their SSO profile. This might lead to unwanted usernames bleeding over. | True |
|
{{ globalsetting("SSO_GROUP_MAP") }}
|
||||||
| Allowed domains | String | Restrict signup to certain domains (comma-separated, starting with @) | |
|
{{ globalsetting("SSO_GROUP_KEY") }}
|
||||||
|
{{ globalsetting("SSO_REMOVE_GROUPS") }}
|
||||||
|
|
||||||
|
#### Require User Email
|
||||||
|
|
||||||
|
If this setting is enabled, users must provide an email address when signing up. Note that some notification and security features require a valid email address.
|
||||||
|
|
||||||
|
#### Forgot Password
|
||||||
|
|
||||||
|
If this setting is enabled, users can reset their password via email. This requires a valid email address to be associated with the user account.
|
||||||
|
|
||||||
|
#### Enforce Multi-Factor Authentication
|
||||||
|
|
||||||
|
If this setting is enabled, users must have multi-factor authentication enabled to log in.
|
||||||
|
|
||||||
|
#### Auto Fil SSO Users
|
||||||
|
|
||||||
|
Automatically fill out user-details from SSO account-data. If this feature is enabled the user is only asked for their username, first- and surname if those values can not be gathered from their SSO profile. This might lead to unwanted usernames bleeding over.
|
||||||
|
|
||||||
### Barcodes
|
### Barcodes
|
||||||
|
|
||||||
Configuration of barcode functionality
|
Configuration of barcode functionality:
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
| Name | Description | Default | Units |
|
||||||
| --- | --- | --- | --- |
|
| ---- | ----------- | ------- | ----- |
|
||||||
| Barcode Support | Boolean | Enable barcode functionality in web interface | True |
|
{{ globalsetting("BARCODE_ENABLE") }}
|
||||||
|
{{ globalsetting("BARCODE_INPUT_DELAY") }}
|
||||||
|
{{ globalsetting("BARCODE_WEBCAM_SUPPORT") }}
|
||||||
|
{{ globalsetting("BARCODE_SHOW_TEXT") }}
|
||||||
|
{{ globalsetting("BARCODE_GENERATION_PLUGIN") }}
|
||||||
|
|
||||||
### Currencies
|
### Pricing and Currency
|
||||||
|
|
||||||
Configuration of currency support
|
Configuration of pricing data and currency support:
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
| Name | Description | Default | Units |
|
||||||
| --- | --- | --- | --- |
|
| ---- | ----------- | ------- | ----- |
|
||||||
| Default Currency | Currency | Default currency | USD |
|
{{ globalsetting("INVENTREE_DEFAULT_CURRENCY") }}
|
||||||
|
{{ globalsetting("CURRENCY_CODES") }}
|
||||||
|
{{ globalsetting("PART_INTERNAL_PRICE") }}
|
||||||
|
{{ globalsetting("PART_BOM_USE_INTERNAL_PRICE") }}
|
||||||
|
{{ globalsetting("PRICING_DECIMAL_PLACES_MIN") }}
|
||||||
|
{{ globalsetting("PRICING_DECIMAL_PLACES") }}
|
||||||
|
{{ globalsetting("PRICING_UPDATE_DAYS") }}
|
||||||
|
{{ globalsetting("PRICING_USE_SUPPLIER_PRICING") }}
|
||||||
|
{{ globalsetting("PRICING_PURCHASE_HISTORY_OVERRIDES_SUPPLIER") }}
|
||||||
|
{{ globalsetting("PRICING_USE_STOCK_PRICING") }}
|
||||||
|
{{ globalsetting("PRICING_STOCK_ITEM_AGE_DAYS") }}
|
||||||
|
{{ globalsetting("PRICING_USE_VARIANT_PRICING") }}
|
||||||
|
{{ globalsetting("PRICING_ACTIVE_VARIANTS") }}
|
||||||
|
|
||||||
### Reporting
|
### Reporting
|
||||||
|
|
||||||
Configuration of report generation
|
Configuration of report generation:
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
| Name | Description | Default | Units |
|
||||||
| --- | --- | --- | --- |
|
| ---- | ----------- | ------- | ----- |
|
||||||
| Enable Reports | Boolean | Enable report generation | False |
|
{{ globalsetting("REPORT_ENABLE") }}
|
||||||
| Page Size | String | Default page size | A4 |
|
{{ globalsetting("REPORT_DEFAULT_PAGE_SIZE") }}
|
||||||
| Debug Mode | Boolean | Generate reports in debug mode (HTML output) | False |
|
{{ globalsetting("REPORT_DEBUG_MODE") }}
|
||||||
| Test Reports | Boolean | Enable generation of test reports | False |
|
{{ globalsetting("REPORT_LOG_ERRORS") }}
|
||||||
|
{{ globalsetting("REPORT_ENABLE_TEST_REPORT") }}
|
||||||
|
{{ globalsetting("REPORT_ATTACH_TEST_REPORT") }}
|
||||||
|
|
||||||
### Parts
|
### Parts
|
||||||
|
|
||||||
#### Main Settings
|
| Name | Description | Default | Units |
|
||||||
|
| ---- | ----------- | ------- | ----- |
|
||||||
| Setting | Type | Description | Default |
|
{{ globalsetting("PART_IPN_REGEX") }}
|
||||||
| --- | --- | --- | --- |
|
{{ globalsetting("PART_ALLOW_DUPLICATE_IPN") }}
|
||||||
| IPN Regex | String | Regular expression pattern for matching Part IPN | *blank* |
|
{{ globalsetting("PART_ALLOW_EDIT_IPN") }}
|
||||||
| Allow Duplicate IPN | Boolean | Allow multiple parts to share the same IPN | True |
|
{{ globalsetting("PART_ALLOW_DELETE_FROM_ASSEMBLY") }}
|
||||||
| Allow Editing IPN | Boolean | Allow changing the IPN value while editing a part | True |
|
{{ globalsetting("PART_ENABLE_REVISION") }}
|
||||||
| Part Name Display Format | String | Format to display the part name | {% raw %}`{{ part.id if part.id }}{{ ' | ' if part.id }}{{ part.name }}{{ ' | ' if part.revision }}{{ part.revision if part.revision }}`{% endraw %} |
|
{{ globalsetting("PART_REVISION_ASSEMBLY_ONLY") }}
|
||||||
| Show Price History | Boolean | Display historical pricing for Part | False |
|
{{ globalsetting("PART_NAME_FORMAT") }}
|
||||||
| Show Price in Forms | Boolean | Display part price in some forms | True |
|
{{ globalsetting("PART_SHOW_RELATED") }}
|
||||||
| Show Price in BOM | Boolean | Include pricing information in BOM tables | True |
|
{{ globalsetting("PART_CREATE_INITIAL") }}
|
||||||
| Show related parts | Boolean | Display related parts for a part | True |
|
{{ globalsetting("PART_CREATE_SUPPLIER") }}
|
||||||
| Create initial stock | Boolean | Create initial stock on part creation | True |
|
{{ globalsetting("PART_TEMPLATE") }}
|
||||||
|
{{ globalsetting("PART_ASSEMBLY") }}
|
||||||
#### Creation Settings
|
{{ globalsetting("PART_COMPONENT") }}
|
||||||
|
{{ globalsetting("PART_TRACKABLE") }}
|
||||||
| Setting | Type | Description | Default |
|
{{ globalsetting("PART_PURCHASEABLE") }}
|
||||||
| --- | --- | --- | --- |
|
{{ globalsetting("PART_SALABLE") }}
|
||||||
| Template | Boolean | Parts are templates by default | False |
|
{{ globalsetting("PART_VIRTUAL") }}
|
||||||
| Assembly | Boolean | Parts can be assembled from other components by default | False |
|
{{ globalsetting("PART_COPY_BOM") }}
|
||||||
| Component | Boolean | Parts can be used as sub-components by default | True |
|
{{ globalsetting("PART_COPY_PARAMETERS") }}
|
||||||
| Trackable | Boolean | Parts are trackable by default | False |
|
{{ globalsetting("PART_COPY_TESTS") }}
|
||||||
| Purchaseable | Boolean | Parts are purchaseable by default | True |
|
{{ globalsetting("PART_CATEGORY_PARAMETERS") }}
|
||||||
| Salable | Boolean | Parts are salable by default | False |
|
{{ globalsetting("PART_CATEGORY_DEFAULT_ICON") }}
|
||||||
| Virtual | Boolean | Parts are virtual by default | False |
|
|
||||||
|
|
||||||
#### Copy Settings
|
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Copy Part BOM Data | Boolean | Copy BOM data by default when duplicating a part | True |
|
|
||||||
| Copy Part Parameter Data | Boolean | Copy parameter data by default when duplicating a part | True |
|
|
||||||
| Copy Part Test Data | Boolean | Copy test data by default when duplicating a part | True |
|
|
||||||
| Copy Category Parameter Templates | Boolean | Copy category parameter templates when creating a part | True |
|
|
||||||
|
|
||||||
#### Internal Price Settings
|
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Internal Prices | Boolean | Enable internal prices for parts | False |
|
|
||||||
| Internal Price as BOM-Price | Boolean | Use the internal price (if set) in BOM-price calculations | False |
|
|
||||||
|
|
||||||
#### Part Import Setting
|
|
||||||
|
|
||||||
This section of the part settings allows staff users to:
|
|
||||||
|
|
||||||
- import parts to InvenTree clicking the <span class="badge inventree add"><span class='fas fa-plus-circle'></span> Import Part</span> button
|
|
||||||
- enable the ["Import Parts" tab in the part category view](../part/part.md#part-import).
|
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Show Import in Views | Boolean | Display the import wizard in some part views | True |
|
|
||||||
|
|
||||||
#### Part Parameter Templates
|
#### Part Parameter Templates
|
||||||
|
|
||||||
@ -153,45 +172,48 @@ After a list of parameters is added to a part category and upon creation of a ne
|
|||||||
|
|
||||||
Configuration of stock item options
|
Configuration of stock item options
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
| Name | Description | Default | Units |
|
||||||
| --- | --- | --- | --- |
|
| ---- | ----------- | ------- | ----- |
|
||||||
| Stock Expiry | Boolean | Enable stock expiry functionality | False |
|
{{ globalsetting("SERIAL_NUMBER_GLOBALLY_UNIQUE") }}
|
||||||
| Stock Stale Time | Days | Number of days stock items are considered stale before expiring | 90 |
|
{{ globalsetting("SERIAL_NUMBER_AUTOFILL") }}
|
||||||
| Sell Expired Stock | Boolean | Allow sale of expired stock | False |
|
{{ globalsetting("STOCK_DELETE_DEPLETED_DEFAULT") }}
|
||||||
| Build Expired Stock | Boolean | Allow building with expired stock | False |
|
{{ globalsetting("STOCK_BATCH_CODE_TEMPLATE") }}
|
||||||
| Stock Ownership Control | Boolean | Enable ownership control functionality | False |
|
{{ globalsetting("STOCK_ENABLE_EXPIRY") }}
|
||||||
|
{{ globalsetting("STOCK_STALE_DAYS") }}
|
||||||
|
{{ globalsetting("STOCK_ALLOW_EXPIRED_SALE") }}
|
||||||
|
{{ globalsetting("STOCK_ALLOW_EXPIRED_BUILD") }}
|
||||||
|
{{ globalsetting("STOCK_OWNERSHIP_CONTROL") }}
|
||||||
|
{{ globalsetting("STOCK_LOCATION_DEFAULT_ICON") }}
|
||||||
|
{{ globalsetting("STOCK_SHOW_INSTALLED_ITEMS") }}
|
||||||
|
{{ globalsetting("STOCK_ENFORCE_BOM_INSTALLATION") }}
|
||||||
|
{{ globalsetting("STOCK_ALLOW_OUT_OF_STOCK_TRANSFER") }}
|
||||||
|
{{ globalsetting("TEST_STATION_DATA") }}
|
||||||
|
|
||||||
### Build Orders
|
### Build Orders
|
||||||
|
|
||||||
Options for build orders
|
Refer to the [build order settings](../build/build.md#build-order-settings).
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Reference Pattern | String | Pattern for defining Build Order reference values | {% raw %}BO-{ref:04d}{% endraw %} |
|
|
||||||
|
|
||||||
### Purchase Orders
|
### Purchase Orders
|
||||||
|
|
||||||
Options for purchase orders
|
Refer to the [purchase order settings](../order/purchase_order.md#purchase-order-settings).
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
### Sales Orders
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Reference Pattern | String | Pattern for defining Purchase Order reference values | {% raw %}PO-{ref:04d}{% endraw %} |
|
|
||||||
|
|
||||||
### Sales orders
|
Refer to the [sales order settings](../order/sales_order.md#sales-order-settings).
|
||||||
|
|
||||||
Options for sales orders
|
### Return Orders
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
Refer to the [return order settings](../order/return_order.md#return-order-settings).
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Reference Pattern | String | Pattern for defining Sales Order reference values | {% raw %}SO-{ref:04d}{% endraw %} |
|
|
||||||
|
|
||||||
### Plugin Settings
|
### Plugin Settings
|
||||||
|
|
||||||
Change into what parts plugins can integrate into.
|
|
||||||
|
|
||||||
| Setting | Type | Description | Default |
|
| Name | Description | Default | Units |
|
||||||
| --- | --- | --- | --- |
|
| ---- | ----------- | ------- | ----- |
|
||||||
| Enable URL integration | Boolean | Enable plugins to add URL routes | False |
|
{{ globalsetting("PLUGIN_ON_STARTUP") }}
|
||||||
| Enable navigation integration | Boolean | Enable plugins to integrate into navigation | False |
|
{{ globalsetting("PLUGIN_UPDATE_CHECK") }}
|
||||||
| Enable setting integration | Boolean | Enable plugins to integrate into inventree settings | False |
|
{{ globalsetting("ENABLE_PLUGINS_URL") }}
|
||||||
| Enable app integration | Boolean | Enable plugins to add apps | False |
|
{{ globalsetting("ENABLE_PLUGINS_NAVIGATION") }}
|
||||||
|
{{ globalsetting("ENABLE_PLUGINS_APP") }}
|
||||||
|
{{ globalsetting("ENABLE_PLUGINS_SCHEDULE") }}
|
||||||
|
{{ globalsetting("ENABLE_PLUGINS_EVENTS") }}
|
||||||
|
@ -32,24 +32,44 @@ This screen allows the user to customize display of items on the InvenTree home
|
|||||||
|
|
||||||
### Search Settings
|
### Search Settings
|
||||||
|
|
||||||
Customize settings for search results
|
Customize settings for search results:
|
||||||
|
|
||||||
{% with id="user-search", url="settings/user_search.png", description="User Search Settings" %}
|
| Name | Description | Default | Units |
|
||||||
{% include 'img.html' %}
|
| ---- | ----------- | ------- | ----- |
|
||||||
{% endwith %}
|
{{ usersetting("SEARCH_WHOLE") }}
|
||||||
|
{{ usersetting("SEARCH_REGEX") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_RESULTS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_PARTS") }}
|
||||||
|
{{ usersetting("SEARCH_HIDE_INACTIVE_PARTS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_SUPPLIER_PARTS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_MANUFACTURER_PARTS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_CATEGORIES") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_STOCK") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_HIDE_UNAVAILABLE_STOCK") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_LOCATIONS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_COMPANIES") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_BUILD_ORDERS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_PURCHASE_ORDERS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_EXCLUDE_INACTIVE_PURCHASE_ORDERS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_SALES_ORDERS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_EXCLUDE_INACTIVE_SALES_ORDERS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_SHOW_RETURN_ORDERS") }}
|
||||||
|
{{ usersetting("SEARCH_PREVIEW_EXCLUDE_INACTIVE_RETURN_ORDERS") }}
|
||||||
|
|
||||||
### Notifications
|
### Notifications
|
||||||
|
|
||||||
Settings related to notification messages
|
Settings related to notification messages:
|
||||||
|
|
||||||
{% with id="user-notification", url="settings/user_notifications.png", description="User Notification Settings" %}
|
| Name | Description | Default | Units |
|
||||||
{% include 'img.html' %}
|
| ---- | ----------- | ------- | ----- |
|
||||||
{% endwith %}
|
{{ usersetting("NOTIFICATION_ERROR_REPORT") }}
|
||||||
|
|
||||||
### Reporting
|
### Reporting
|
||||||
|
|
||||||
Settings for label printing and report generation
|
Settings for label printing and report generation:
|
||||||
|
|
||||||
{% with id="user-reporting", url="settings/user_reporting.png", description="User Reporting Settings" %}
|
| Name | Description | Default | Units |
|
||||||
{% include 'img.html' %}
|
| ---- | ----------- | ------- | ----- |
|
||||||
{% endwith %}
|
{{ usersetting("REPORT_INLINE") }}
|
||||||
|
{{ usersetting("LABEL_INLINE") }}
|
||||||
|
{{ usersetting("LABEL_DEFAULT_PRINTER") }}
|
||||||
|
49
docs/main.py
49
docs/main.py
@ -1,5 +1,6 @@
|
|||||||
"""Main entry point for the documentation build process."""
|
"""Main entry point for the documentation build process."""
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import textwrap
|
import textwrap
|
||||||
@ -7,6 +8,20 @@ import textwrap
|
|||||||
import requests
|
import requests
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
# Cached settings dict values
|
||||||
|
global GLOBAL_SETTINGS
|
||||||
|
global USER_SETTINGS
|
||||||
|
|
||||||
|
# Read in the InvenTree settings file
|
||||||
|
here = os.path.dirname(__file__)
|
||||||
|
settings_file = os.path.join(here, 'inventree_settings.json')
|
||||||
|
|
||||||
|
with open(settings_file, 'r') as sf:
|
||||||
|
settings = json.load(sf)
|
||||||
|
|
||||||
|
GLOBAL_SETTINGS = settings['global']
|
||||||
|
USER_SETTINGS = settings['user']
|
||||||
|
|
||||||
|
|
||||||
def get_repo_url(raw=False):
|
def get_repo_url(raw=False):
|
||||||
"""Return the repository URL for the current project."""
|
"""Return the repository URL for the current project."""
|
||||||
@ -219,3 +234,37 @@ def define_env(env):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return includefile(fn, f'Template: {base}', format='html')
|
return includefile(fn, f'Template: {base}', format='html')
|
||||||
|
|
||||||
|
@env.macro
|
||||||
|
def rendersetting(setting: dict):
|
||||||
|
"""Render a provided setting object into a table row."""
|
||||||
|
name = setting['name']
|
||||||
|
description = setting['description']
|
||||||
|
default = setting.get('default', None)
|
||||||
|
units = setting.get('units', None)
|
||||||
|
|
||||||
|
return f'| {name} | {description} | {default if default is not None else ""} | {units if units is not None else ""} |'
|
||||||
|
|
||||||
|
@env.macro
|
||||||
|
def globalsetting(key: str):
|
||||||
|
"""Extract information on a particular global setting.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- key: The name of the global setting to extract information for.
|
||||||
|
"""
|
||||||
|
global GLOBAL_SETTINGS
|
||||||
|
setting = GLOBAL_SETTINGS[key]
|
||||||
|
|
||||||
|
return rendersetting(setting)
|
||||||
|
|
||||||
|
@env.macro
|
||||||
|
def usersetting(key: str):
|
||||||
|
"""Extract information on a particular user setting.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
- key: The name of the user setting to extract information for.
|
||||||
|
"""
|
||||||
|
global USER_SETTINGS
|
||||||
|
setting = USER_SETTINGS[key]
|
||||||
|
|
||||||
|
return rendersetting(setting)
|
||||||
|
@ -17,5 +17,6 @@ build:
|
|||||||
- echo "Generating API schema file"
|
- echo "Generating API schema file"
|
||||||
- pip install -U invoke
|
- pip install -U invoke
|
||||||
- invoke migrate
|
- invoke migrate
|
||||||
|
- invoke export-settings-definitions --filename docs/inventree_settings.json --overwrite
|
||||||
- invoke schema --filename docs/schema.yml --ignore-warnings
|
- invoke schema --filename docs/schema.yml --ignore-warnings
|
||||||
- python docs/extract_schema.py docs/schema.yml
|
- python docs/extract_schema.py docs/schema.yml
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
"""Custom management command to export settings definitions.
|
||||||
|
|
||||||
|
This is used to generate a JSON file which contains all of the settings,
|
||||||
|
so that they can be introspected by the InvenTree documentation system.
|
||||||
|
|
||||||
|
This in turn allows settings to be documented in the InvenTree documentation,
|
||||||
|
without having to manually duplicate the information in multiple places.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
"""Extract settings 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 settings definitions'
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
"""Export settings information to a JSON file."""
|
||||||
|
from common.models import InvenTreeSetting, InvenTreeUserSetting
|
||||||
|
|
||||||
|
settings = {'global': {}, 'user': {}}
|
||||||
|
|
||||||
|
# Global settings
|
||||||
|
for key, setting in InvenTreeSetting.SETTINGS.items():
|
||||||
|
settings['global'][key] = {
|
||||||
|
'name': str(setting['name']),
|
||||||
|
'description': str(setting['description']),
|
||||||
|
'default': str(InvenTreeSetting.get_setting_default(key)),
|
||||||
|
'units': str(setting.get('units', '')),
|
||||||
|
}
|
||||||
|
|
||||||
|
# User settings
|
||||||
|
for key, setting in InvenTreeUserSetting.SETTINGS.items():
|
||||||
|
settings['user'][key] = {
|
||||||
|
'name': str(setting['name']),
|
||||||
|
'description': str(setting['description']),
|
||||||
|
'default': str(InvenTreeUserSetting.get_setting_default(key)),
|
||||||
|
'units': str(setting.get('units', '')),
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = kwargs.get('filename', 'inventree_settings.json')
|
||||||
|
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
json.dump(settings, f, indent=4)
|
||||||
|
|
||||||
|
print(f"Exported InvenTree settings definitions to '{filename}'")
|
@ -395,9 +395,9 @@ class Build(
|
|||||||
def sub_builds(self, cascade=True):
|
def sub_builds(self, cascade=True):
|
||||||
"""Return all Build Order objects under this one."""
|
"""Return all Build Order objects under this one."""
|
||||||
if cascade:
|
if cascade:
|
||||||
return Build.objects.filter(parent=self.pk)
|
return self.get_descendants(include_self=False)
|
||||||
descendants = self.get_descendants(include_self=True)
|
else:
|
||||||
Build.objects.filter(parent__pk__in=[d.pk for d in descendants])
|
return self.get_children()
|
||||||
|
|
||||||
def sub_build_count(self, cascade=True):
|
def sub_build_count(self, cascade=True):
|
||||||
"""Return the number of sub builds under this one.
|
"""Return the number of sub builds under this one.
|
||||||
@ -407,6 +407,11 @@ class Build(
|
|||||||
"""
|
"""
|
||||||
return self.sub_builds(cascade=cascade).count()
|
return self.sub_builds(cascade=cascade).count()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_open_child_builds(self):
|
||||||
|
"""Return True if this build order has any open child builds."""
|
||||||
|
return self.sub_builds().filter(status__in=BuildStatusGroups.ACTIVE_CODES).exists()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_overdue(self):
|
def is_overdue(self):
|
||||||
"""Returns true if this build is "overdue".
|
"""Returns true if this build is "overdue".
|
||||||
@ -576,6 +581,9 @@ class Build(
|
|||||||
- Untracked parts must be allocated
|
- Untracked parts must be allocated
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if get_global_setting('BUILDORDER_REQUIRE_CLOSED_CHILDS') and self.has_open_child_builds:
|
||||||
|
return False
|
||||||
|
|
||||||
if self.status != BuildStatus.PRODUCTION.value:
|
if self.status != BuildStatus.PRODUCTION.value:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -619,6 +627,10 @@ class Build(
|
|||||||
trim_allocated_stock = kwargs.pop('trim_allocated_stock', False)
|
trim_allocated_stock = kwargs.pop('trim_allocated_stock', False)
|
||||||
user = kwargs.pop('user', None)
|
user = kwargs.pop('user', None)
|
||||||
|
|
||||||
|
# Prevent completion if there are open child builds
|
||||||
|
if get_global_setting('BUILDORDER_REQUIRE_CLOSED_CHILDS') and self.has_open_child_builds:
|
||||||
|
return
|
||||||
|
|
||||||
if self.incomplete_count > 0:
|
if self.incomplete_count > 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -974,7 +986,10 @@ class Build(
|
|||||||
items_to_save = []
|
items_to_save = []
|
||||||
items_to_delete = []
|
items_to_delete = []
|
||||||
|
|
||||||
for build_line in self.untracked_line_items:
|
lines = self.untracked_line_items
|
||||||
|
lines = lines.prefetch_related('allocations')
|
||||||
|
|
||||||
|
for build_line in lines:
|
||||||
|
|
||||||
reduce_by = build_line.allocated_quantity() - build_line.quantity
|
reduce_by = build_line.allocated_quantity() - build_line.quantity
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ from stock.serializers import StockItemSerializerBrief, LocationBriefSerializer
|
|||||||
|
|
||||||
import common.models
|
import common.models
|
||||||
from common.serializers import ProjectCodeSerializer
|
from common.serializers import ProjectCodeSerializer
|
||||||
|
from common.settings import get_global_setting
|
||||||
from importer.mixins import DataImportExportSerializerMixin
|
from importer.mixins import DataImportExportSerializerMixin
|
||||||
import company.serializers
|
import company.serializers
|
||||||
import part.filters
|
import part.filters
|
||||||
@ -765,6 +766,9 @@ class BuildCompleteSerializer(serializers.Serializer):
|
|||||||
"""Perform validation of this serializer prior to saving"""
|
"""Perform validation of this serializer prior to saving"""
|
||||||
build = self.context['build']
|
build = self.context['build']
|
||||||
|
|
||||||
|
if get_global_setting('BUILDORDER_REQUIRE_CLOSED_CHILDS') and build.has_open_child_builds:
|
||||||
|
raise ValidationError(_("Build order has open child build orders"))
|
||||||
|
|
||||||
if build.status != BuildStatus.PRODUCTION.value:
|
if build.status != BuildStatus.PRODUCTION.value:
|
||||||
raise ValidationError(_("Build order must be in production state"))
|
raise ValidationError(_("Build order must be in production state"))
|
||||||
|
|
||||||
|
@ -1015,7 +1015,7 @@ class BuildOverallocationTest(BuildAPITest):
|
|||||||
'accept_overallocated': 'trim',
|
'accept_overallocated': 'trim',
|
||||||
},
|
},
|
||||||
expected_code=201,
|
expected_code=201,
|
||||||
max_query_count=555, # TODO: Come back and refactor this
|
max_query_count=600, # TODO: Come back and refactor this
|
||||||
)
|
)
|
||||||
|
|
||||||
self.build.refresh_from_db()
|
self.build.refresh_from_db()
|
||||||
|
@ -1838,6 +1838,14 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
|||||||
'default': False,
|
'default': False,
|
||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
'BUILDORDER_REQUIRE_CLOSED_CHILDS': {
|
||||||
|
'name': _('Require Closed Child Orders'),
|
||||||
|
'description': _(
|
||||||
|
'Prevent build order completion until all child orders are closed'
|
||||||
|
),
|
||||||
|
'default': False,
|
||||||
|
'validator': bool,
|
||||||
|
},
|
||||||
'PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS': {
|
'PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS': {
|
||||||
'name': _('Block Until Tests Pass'),
|
'name': _('Block Until Tests Pass'),
|
||||||
'description': _(
|
'description': _(
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_ACTIVE_PART" %}
|
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_ACTIVE_PART" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_LOCKED_PART" %}
|
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_LOCKED_PART" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_VALID_BOM" %}
|
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_VALID_BOM" %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REQUIRE_CLOSED_CHILDS" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS" %}
|
{% include "InvenTree/settings/setting.html" with key="PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS" %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -244,6 +244,7 @@ export default function SystemSettings() {
|
|||||||
'BUILDORDER_REQUIRE_ACTIVE_PART',
|
'BUILDORDER_REQUIRE_ACTIVE_PART',
|
||||||
'BUILDORDER_REQUIRE_LOCKED_PART',
|
'BUILDORDER_REQUIRE_LOCKED_PART',
|
||||||
'BUILDORDER_REQUIRE_VALID_BOM',
|
'BUILDORDER_REQUIRE_VALID_BOM',
|
||||||
|
'BUILDORDER_REQUIRE_CLOSED_CHILDS',
|
||||||
'PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS'
|
'PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS'
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
15
tasks.py
15
tasks.py
@ -1074,6 +1074,16 @@ def schema(
|
|||||||
print('Schema export completed:', filename)
|
print('Schema export completed:', filename)
|
||||||
|
|
||||||
|
|
||||||
|
@task
|
||||||
|
def export_settings_definitions(c, filename='inventree_settings.json', overwrite=False):
|
||||||
|
"""Export settings definition to a JSON file."""
|
||||||
|
filename = Path(filename).resolve()
|
||||||
|
check_file_existance(filename, overwrite)
|
||||||
|
|
||||||
|
print(f"Exporting settings definition to '{filename}'...")
|
||||||
|
manage(c, f'export_settings_definitions {filename}', pty=True)
|
||||||
|
|
||||||
|
|
||||||
@task(default=True)
|
@task(default=True)
|
||||||
def version(c):
|
def version(c):
|
||||||
"""Show the current version of InvenTree."""
|
"""Show the current version of InvenTree."""
|
||||||
@ -1406,6 +1416,11 @@ via your signed in browser, or consider using a point release download via invok
|
|||||||
)
|
)
|
||||||
def docs_server(c, address='localhost:8080', compile_schema=False):
|
def docs_server(c, address='localhost:8080', compile_schema=False):
|
||||||
"""Start a local mkdocs server to view the documentation."""
|
"""Start a local mkdocs server to view the documentation."""
|
||||||
|
# Extract settings definitions
|
||||||
|
export_settings_definitions(
|
||||||
|
c, filename='docs/inventree_settings.json', overwrite=True
|
||||||
|
)
|
||||||
|
|
||||||
if compile_schema:
|
if compile_schema:
|
||||||
# Build the schema docs first
|
# Build the schema docs first
|
||||||
schema(c, ignore_warnings=True, overwrite=True, filename='docs/schema.yml')
|
schema(c, ignore_warnings=True, overwrite=True, filename='docs/schema.yml')
|
||||||
|
Loading…
Reference in New Issue
Block a user