diff --git a/.gitignore b/.gitignore index 4bc362f653..8541ce79a3 100644 --- a/.gitignore +++ b/.gitignore @@ -111,3 +111,4 @@ InvenTree/web/static docs/schema.yml docs/docs/api/*.yml docs/docs/api/schema/*.yml +inventree_settings.json diff --git a/docs/docs/assets/images/settings/user_notifications.png b/docs/docs/assets/images/settings/user_notifications.png deleted file mode 100644 index ef1b8294f0..0000000000 Binary files a/docs/docs/assets/images/settings/user_notifications.png and /dev/null differ diff --git a/docs/docs/assets/images/settings/user_reporting.png b/docs/docs/assets/images/settings/user_reporting.png deleted file mode 100644 index 0b08c7914b..0000000000 Binary files a/docs/docs/assets/images/settings/user_reporting.png and /dev/null differ diff --git a/docs/docs/build/build.md b/docs/docs/build/build.md index 6c2f4c31df..09c0add44f 100644 --- a/docs/docs/build/build.md +++ b/docs/docs/build/build.md @@ -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 - 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 - -If this option is enabled, build orders can only be created for parts which are marked as [Active](../part/part.md#active-parts). - -### 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). - -### Require Valid BOM - -If this option is enabled, build orders can only be created for parts which have a valid [Bill of Materials](./bom.md) defined. +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ globalsetting("BUILDORDER_REFERENCE_PATTERN") }} +{{ globalsetting("BUILDORDER_REQUIRE_RESPONSIBLE") }} +{{ globalsetting("BUILDORDER_REQUIRE_ACTIVE_PART") }} +{{ globalsetting("BUILDORDER_REQUIRE_LOCKED_PART") }} +{{ globalsetting("BUILDORDER_REQUIRE_VALID_BOM") }} +{{ globalsetting("BUILDORDER_REQUIRE_CLOSED_CHILDS") }} +{{ globalsetting("PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS") }} diff --git a/docs/docs/order/purchase_order.md b/docs/docs/order/purchase_order.md index fe39c2ab8f..19169c2298 100644 --- a/docs/docs/order/purchase_order.md +++ b/docs/docs/order/purchase_order.md @@ -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` 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") }} diff --git a/docs/docs/order/return_order.md b/docs/docs/order/return_order.md index ad219c099b..cdbfba88b1 100644 --- a/docs/docs/order/return_order.md +++ b/docs/docs/order/return_order.md @@ -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` 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") }} diff --git a/docs/docs/order/sales_order.md b/docs/docs/order/sales_order.md index 3d6f77dec0..e44666fb02 100644 --- a/docs/docs/order/sales_order.md +++ b/docs/docs/order/sales_order.md @@ -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" %} {% include "img.html" %} {% 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") }} diff --git a/docs/docs/settings/currency.md b/docs/docs/settings/currency.md index 4a2e7834f5..7368213afa 100644 --- a/docs/docs/settings/currency.md +++ b/docs/docs/settings/currency.md @@ -24,12 +24,7 @@ If a different currency exchange backend is needed, or a custom implementation i ### Currency Settings -In the [settings screen](./global.md), under the *Pricing* section, the following currency settings are available: - -| 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 | +Refer to the [global settings](./global.md#pricing-and-currency) documentation for more information on available currency settings. #### Supported Currencies diff --git a/docs/docs/settings/global.md b/docs/docs/settings/global.md index 967651e46d..7de1186167 100644 --- a/docs/docs/settings/global.md +++ b/docs/docs/settings/global.md @@ -17,120 +17,139 @@ Global settings are arranged in the following categories: ### 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 -Change how logins, password-forgot, signups are handled. +Change how logins, password-forgot, signups are handled: -| Setting | Type | Description | Default | -| --- | --- | --- | --- | -| Enable registration | Boolean | Enable self-registration for users on the login-pages | False | -| Enable SSO | Boolean | Enable SSO on the login-pages | False | -| Enable SSO registration | Boolean | Enable self-registration for users via SSO on the login-pages | False | -| Enable SSO group sync | Boolean | Enable synchronizing InvenTree groups directly from the IdP | False | -| SSO group key | String | The name of the groups claim attribute provided by the IdP | | -| SSO group map | String (JSON) | A mapping from SSO groups to local InvenTree groups | {} | -| 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 | -| Enable password forgot | Boolean | Enable password forgot function on the login-pages.

This will let users reset their passwords on their own. For this feature to work you need to configure E-mail | True | -| E-Mail required | Boolean | Require user to supply e-mail on signup.

Without a way (e-mail) to contact the user notifications and security features might not work! | False | -| Enforce MFA | Boolean | Users must use multifactor security.

This forces each user to setup MFA and use it on each authentication | False | -| Mail twice | Boolean | On signup ask users twice for their mail | False | -| Password twice | Boolean | On signup ask users twice for their password | True | -| Auto-fill SSO users | Boolean | 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. | True | -| Allowed domains | String | Restrict signup to certain domains (comma-separated, starting with @) | | +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ globalsetting("LOGIN_ENABLE_PWD_FORGOT") }} +{{ globalsetting("LOGIN_MAIL_REQUIRED") }} +{{ globalsetting("LOGIN_ENFORCE_MFA") }} +{{ globalsetting("LOGIN_ENABLE_REG") }} +{{ globalsetting("LOGIN_SIGNUP_MAIL_TWICE") }} +{{ globalsetting("LOGIN_SIGNUP_PWD_TWICE") }} +{{ globalsetting("SIGNUP_GROUP") }} +{{ globalsetting("LOGIN_SIGNUP_MAIL_RESTRICTION") }} +{{ globalsetting("LOGIN_ENABLE_SSO") }} +{{ globalsetting("LOGIN_ENABLE_SSO_REG") }} +{{ globalsetting("LOGIN_SIGNUP_SSO_AUTO") }} +{{ globalsetting("LOGIN_ENABLE_SSO_GROUP_SYNC") }} +{{ globalsetting("SSO_GROUP_MAP") }} +{{ 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 -Configuration of barcode functionality +Configuration of barcode functionality: -| Setting | Type | Description | Default | -| --- | --- | --- | --- | -| Barcode Support | Boolean | Enable barcode functionality in web interface | True | +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ 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 | -| --- | --- | --- | --- | -| Default Currency | Currency | Default currency | USD | +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ 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 -Configuration of report generation +Configuration of report generation: -| Setting | Type | Description | Default | -| --- | --- | --- | --- | -| Enable Reports | Boolean | Enable report generation | False | -| Page Size | String | Default page size | A4 | -| Debug Mode | Boolean | Generate reports in debug mode (HTML output) | False | -| Test Reports | Boolean | Enable generation of test reports | False | +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ globalsetting("REPORT_ENABLE") }} +{{ globalsetting("REPORT_DEFAULT_PAGE_SIZE") }} +{{ globalsetting("REPORT_DEBUG_MODE") }} +{{ globalsetting("REPORT_LOG_ERRORS") }} +{{ globalsetting("REPORT_ENABLE_TEST_REPORT") }} +{{ globalsetting("REPORT_ATTACH_TEST_REPORT") }} ### Parts -#### Main Settings - -| Setting | Type | Description | Default | -| --- | --- | --- | --- | -| IPN Regex | String | Regular expression pattern for matching Part IPN | *blank* | -| Allow Duplicate IPN | Boolean | Allow multiple parts to share the same IPN | True | -| Allow Editing IPN | Boolean | Allow changing the IPN value while editing a part | True | -| 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 %} | -| Show Price History | Boolean | Display historical pricing for Part | False | -| Show Price in Forms | Boolean | Display part price in some forms | True | -| Show Price in BOM | Boolean | Include pricing information in BOM tables | True | -| Show related parts | Boolean | Display related parts for a part | True | -| Create initial stock | Boolean | Create initial stock on part creation | True | - -#### Creation Settings - -| Setting | Type | Description | Default | -| --- | --- | --- | --- | -| Template | Boolean | Parts are templates by default | False | -| Assembly | Boolean | Parts can be assembled from other components by default | False | -| Component | Boolean | Parts can be used as sub-components by default | True | -| Trackable | Boolean | Parts are trackable by default | False | -| Purchaseable | Boolean | Parts are purchaseable by default | True | -| Salable | Boolean | Parts are salable by default | False | -| 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 Import Part 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 | +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ globalsetting("PART_IPN_REGEX") }} +{{ globalsetting("PART_ALLOW_DUPLICATE_IPN") }} +{{ globalsetting("PART_ALLOW_EDIT_IPN") }} +{{ globalsetting("PART_ALLOW_DELETE_FROM_ASSEMBLY") }} +{{ globalsetting("PART_ENABLE_REVISION") }} +{{ globalsetting("PART_REVISION_ASSEMBLY_ONLY") }} +{{ globalsetting("PART_NAME_FORMAT") }} +{{ globalsetting("PART_SHOW_RELATED") }} +{{ globalsetting("PART_CREATE_INITIAL") }} +{{ globalsetting("PART_CREATE_SUPPLIER") }} +{{ globalsetting("PART_TEMPLATE") }} +{{ globalsetting("PART_ASSEMBLY") }} +{{ globalsetting("PART_COMPONENT") }} +{{ globalsetting("PART_TRACKABLE") }} +{{ globalsetting("PART_PURCHASEABLE") }} +{{ globalsetting("PART_SALABLE") }} +{{ globalsetting("PART_VIRTUAL") }} +{{ globalsetting("PART_COPY_BOM") }} +{{ globalsetting("PART_COPY_PARAMETERS") }} +{{ globalsetting("PART_COPY_TESTS") }} +{{ globalsetting("PART_CATEGORY_PARAMETERS") }} +{{ globalsetting("PART_CATEGORY_DEFAULT_ICON") }} #### 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 -| Setting | Type | Description | Default | -| --- | --- | --- | --- | -| Stock Expiry | Boolean | Enable stock expiry functionality | False | -| Stock Stale Time | Days | Number of days stock items are considered stale before expiring | 90 | -| Sell Expired Stock | Boolean | Allow sale of expired stock | False | -| Build Expired Stock | Boolean | Allow building with expired stock | False | -| Stock Ownership Control | Boolean | Enable ownership control functionality | False | +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ globalsetting("SERIAL_NUMBER_GLOBALLY_UNIQUE") }} +{{ globalsetting("SERIAL_NUMBER_AUTOFILL") }} +{{ globalsetting("STOCK_DELETE_DEPLETED_DEFAULT") }} +{{ globalsetting("STOCK_BATCH_CODE_TEMPLATE") }} +{{ 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 -Options for build orders - -| Setting | Type | Description | Default | -| --- | --- | --- | --- | -| Reference Pattern | String | Pattern for defining Build Order reference values | {% raw %}BO-{ref:04d}{% endraw %} | +Refer to the [build order settings](../build/build.md#build-order-settings). ### Purchase Orders -Options for purchase orders +Refer to the [purchase order settings](../order/purchase_order.md#purchase-order-settings). -| Setting | Type | Description | Default | -| --- | --- | --- | --- | -| Reference Pattern | String | Pattern for defining Purchase Order reference values | {% raw %}PO-{ref:04d}{% endraw %} | +### Sales Orders -### 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 | -| --- | --- | --- | --- | -| Reference Pattern | String | Pattern for defining Sales Order reference values | {% raw %}SO-{ref:04d}{% endraw %} | +Refer to the [return order settings](../order/return_order.md#return-order-settings). ### Plugin Settings -Change into what parts plugins can integrate into. -| Setting | Type | Description | Default | -| --- | --- | --- | --- | -| Enable URL integration | Boolean | Enable plugins to add URL routes | False | -| Enable navigation integration | Boolean | Enable plugins to integrate into navigation | False | -| Enable setting integration | Boolean | Enable plugins to integrate into inventree settings | False | -| Enable app integration | Boolean | Enable plugins to add apps | False | +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ globalsetting("PLUGIN_ON_STARTUP") }} +{{ globalsetting("PLUGIN_UPDATE_CHECK") }} +{{ globalsetting("ENABLE_PLUGINS_URL") }} +{{ globalsetting("ENABLE_PLUGINS_NAVIGATION") }} +{{ globalsetting("ENABLE_PLUGINS_APP") }} +{{ globalsetting("ENABLE_PLUGINS_SCHEDULE") }} +{{ globalsetting("ENABLE_PLUGINS_EVENTS") }} diff --git a/docs/docs/settings/user.md b/docs/docs/settings/user.md index c9f74b97ed..fdb6cb0aca 100644 --- a/docs/docs/settings/user.md +++ b/docs/docs/settings/user.md @@ -32,24 +32,44 @@ This screen allows the user to customize display of items on the InvenTree home ### 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" %} -{% include 'img.html' %} -{% endwith %} +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ 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 -Settings related to notification messages +Settings related to notification messages: -{% with id="user-notification", url="settings/user_notifications.png", description="User Notification Settings" %} -{% include 'img.html' %} -{% endwith %} +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ usersetting("NOTIFICATION_ERROR_REPORT") }} ### 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" %} -{% include 'img.html' %} -{% endwith %} +| Name | Description | Default | Units | +| ---- | ----------- | ------- | ----- | +{{ usersetting("REPORT_INLINE") }} +{{ usersetting("LABEL_INLINE") }} +{{ usersetting("LABEL_DEFAULT_PRINTER") }} diff --git a/docs/main.py b/docs/main.py index 11066c4057..b09b8b0da2 100644 --- a/docs/main.py +++ b/docs/main.py @@ -1,5 +1,6 @@ """Main entry point for the documentation build process.""" +import json import os import subprocess import textwrap @@ -7,6 +8,20 @@ import textwrap import requests 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): """Return the repository URL for the current project.""" @@ -219,3 +234,37 @@ def define_env(env): ) 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) diff --git a/readthedocs.yml b/readthedocs.yml index 003ca95426..f9a08ce2a9 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -17,5 +17,6 @@ build: - echo "Generating API schema file" - pip install -U invoke - invoke migrate + - invoke export-settings-definitions --filename docs/inventree_settings.json --overwrite - invoke schema --filename docs/schema.yml --ignore-warnings - python docs/extract_schema.py docs/schema.yml diff --git a/src/backend/InvenTree/InvenTree/management/commands/export_settings_definitions.py b/src/backend/InvenTree/InvenTree/management/commands/export_settings_definitions.py new file mode 100644 index 0000000000..8587e936d0 --- /dev/null +++ b/src/backend/InvenTree/InvenTree/management/commands/export_settings_definitions.py @@ -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}'") diff --git a/src/backend/InvenTree/build/models.py b/src/backend/InvenTree/build/models.py index eb0449ea94..adde7080da 100644 --- a/src/backend/InvenTree/build/models.py +++ b/src/backend/InvenTree/build/models.py @@ -395,9 +395,9 @@ class Build( def sub_builds(self, cascade=True): """Return all Build Order objects under this one.""" if cascade: - return Build.objects.filter(parent=self.pk) - descendants = self.get_descendants(include_self=True) - Build.objects.filter(parent__pk__in=[d.pk for d in descendants]) + return self.get_descendants(include_self=False) + else: + return self.get_children() def sub_build_count(self, cascade=True): """Return the number of sub builds under this one. @@ -407,6 +407,11 @@ class Build( """ 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 def is_overdue(self): """Returns true if this build is "overdue". @@ -576,6 +581,9 @@ class Build( - 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: return False @@ -619,6 +627,10 @@ class Build( trim_allocated_stock = kwargs.pop('trim_allocated_stock', False) 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: return @@ -974,7 +986,10 @@ class Build( items_to_save = [] 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 diff --git a/src/backend/InvenTree/build/serializers.py b/src/backend/InvenTree/build/serializers.py index 38f6b43adf..ef73686a9b 100644 --- a/src/backend/InvenTree/build/serializers.py +++ b/src/backend/InvenTree/build/serializers.py @@ -27,6 +27,7 @@ from stock.serializers import StockItemSerializerBrief, LocationBriefSerializer import common.models from common.serializers import ProjectCodeSerializer +from common.settings import get_global_setting from importer.mixins import DataImportExportSerializerMixin import company.serializers import part.filters @@ -765,6 +766,9 @@ class BuildCompleteSerializer(serializers.Serializer): """Perform validation of this serializer prior to saving""" 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: raise ValidationError(_("Build order must be in production state")) diff --git a/src/backend/InvenTree/build/test_api.py b/src/backend/InvenTree/build/test_api.py index acb75c25f3..518d4c4098 100644 --- a/src/backend/InvenTree/build/test_api.py +++ b/src/backend/InvenTree/build/test_api.py @@ -1015,7 +1015,7 @@ class BuildOverallocationTest(BuildAPITest): 'accept_overallocated': 'trim', }, 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() diff --git a/src/backend/InvenTree/common/models.py b/src/backend/InvenTree/common/models.py index 46e38b03d8..9b34a4c37b 100644 --- a/src/backend/InvenTree/common/models.py +++ b/src/backend/InvenTree/common/models.py @@ -1838,6 +1838,14 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'default': False, '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': { 'name': _('Block Until Tests Pass'), 'description': _( diff --git a/src/backend/InvenTree/templates/InvenTree/settings/build.html b/src/backend/InvenTree/templates/InvenTree/settings/build.html index 9eb1ce47bb..cce783b372 100644 --- a/src/backend/InvenTree/templates/InvenTree/settings/build.html +++ b/src/backend/InvenTree/templates/InvenTree/settings/build.html @@ -17,6 +17,7 @@ {% 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_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" %} diff --git a/src/frontend/src/pages/Index/Settings/SystemSettings.tsx b/src/frontend/src/pages/Index/Settings/SystemSettings.tsx index 0db6114592..fe4d7a49e4 100644 --- a/src/frontend/src/pages/Index/Settings/SystemSettings.tsx +++ b/src/frontend/src/pages/Index/Settings/SystemSettings.tsx @@ -244,6 +244,7 @@ export default function SystemSettings() { 'BUILDORDER_REQUIRE_ACTIVE_PART', 'BUILDORDER_REQUIRE_LOCKED_PART', 'BUILDORDER_REQUIRE_VALID_BOM', + 'BUILDORDER_REQUIRE_CLOSED_CHILDS', 'PREVENT_BUILD_COMPLETION_HAVING_INCOMPLETED_TESTS' ]} /> diff --git a/tasks.py b/tasks.py index 57c2ceed30..b665daec7a 100644 --- a/tasks.py +++ b/tasks.py @@ -1074,6 +1074,16 @@ def schema( 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) def version(c): """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): """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: # Build the schema docs first schema(c, ignore_warnings=True, overwrite=True, filename='docs/schema.yml')