2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-01 03:00:54 +00:00

[plugin] Auto issue orders (#9565)

* Add builtin plugin for auto-issuing orders

* Add plugin to auto-issue orders

* Add placeholder documentation

* Fix typo

* Adds image macro

- To replace img.html
- includes checking if file exists

* Fix tooltips

* More docs

* Adjust plugin settings filters

* docs

* More docs

* More docs

* Updates

* Less restrictive URL checking

* Refactor build order page

* Fix typo

* Allow 429

* Debug output

* More debug

* Construct assets dir

* Cleanup

* Update docs README

* Refactoring more pages

* Fix image link

* Fix SSO settings

* Add hook to check for missing settings

- Ensure that all settings are documented!

* Add missing user settings

* Update docstring

* Tweak SSO.md

* Image updates

* More updates

* Tweaks

* Exclude orders without a target_date

* Fix for issuing build orders

* Further refactoring

* Fixes

* Image refactoring

* More refactoring

* More refactoring

* Refactor app images

* Fix pathing issues

* Suppress some openapidocs warnings in logs

(much easier to debug docs build issues)

* Fix image reference

* Reduce error messages

* Fix image links

* Fix image links

* Reduce docs log output

* Ensure settings are loaded before displaying them

* Fix for UI test

* Fix unit test

* Test tweaks
This commit is contained in:
Oliver
2025-06-03 17:07:12 +10:00
committed by GitHub
parent 89f8f132e1
commit 11ab0203b1
124 changed files with 1178 additions and 957 deletions

View File

@ -461,12 +461,6 @@ SYSTEM_SETTINGS: dict[str, InvenTreeSettingsKeyType] = {
'default': False,
'validator': bool,
},
'PART_SHOW_IMPORT': {
'name': _('Show Import in Views'),
'description': _('Display the import wizard in some part views'),
'default': False,
'validator': bool,
},
'PART_SHOW_RELATED': {
'name': _('Show related parts'),
'description': _('Display related parts for a part'),

View File

@ -0,0 +1,130 @@
"""Plugin to automatically issue orders on the assigned target date."""
from django.utils.translation import gettext_lazy as _
import structlog
from InvenTree.helpers import current_date
from plugin import InvenTreePlugin
from plugin.mixins import ScheduleMixin, SettingsMixin
logger = structlog.get_logger('inventree')
class AutoIssueOrdersPlugin(ScheduleMixin, SettingsMixin, InvenTreePlugin):
"""Plugin to automatically issue orders on the assigned target date."""
NAME = _('Auto Issue Orders')
SLUG = 'autoiissueorders'
AUTHOR = _('InvenTree contributors')
DESCRIPTION = _('Automatically issue orders on the assigned target date')
VERSION = '1.0.0'
# Set the scheduled tasks for this plugin
SCHEDULED_TASKS = {
'auto_issue_orders': {'func': 'auto_issue_orders', 'schedule': 'D'}
}
SETTINGS = {
'AUTO_ISSUE_BUILD_ORDERS': {
'name': _('Auto Issue Build Orders'),
'description': _(
'Automatically issue build orders on the assigned target date'
),
'validator': bool,
'default': True,
},
'AUTO_ISSUE_PURCHASE_ORDERS': {
'name': _('Auto Issue Purchase Orders'),
'description': _(
'Automatically issue purchase orders on the assigned target date'
),
'validator': bool,
'default': True,
},
'AUTO_ISSUE_SALES_ORDERS': {
'name': _('Auto Issue Sales Orders'),
'description': _(
'Automatically issue sales orders on the assigned target date'
),
'validator': bool,
'default': True,
},
'AUTO_ISSUE_RETURN_ORDERS': {
'name': _('Auto Issue Return Orders'),
'description': _(
'Automatically issue return orders on the assigned target date'
),
'validator': bool,
'default': True,
},
'ISSUE_BACKDATED_ORDERS': {
'name': _('Issue Backdated Orders'),
'description': _('Automatically issue orders that are backdated'),
'validator': bool,
'default': False,
},
}
def auto_issue_orders(self):
"""Automatically issue orders on the assigned target date."""
if self.get_setting('AUTO_ISSUE_BUILD_ORDERS', backup_value=True):
self.auto_issue_build_orders()
if self.get_setting('AUTO_ISSUE_PURCHASE_ORDERS', backup_value=True):
self.auto_issue_purchase_orders()
if self.get_setting('AUTO_ISSUE_SALES_ORDERS', backup_value=True):
self.auto_issue_sales_orders()
if self.get_setting('AUTO_ISSUE_RETURN_ORDERS', backup_value=True):
self.auto_issue_return_orders()
def issue_func(self, model, status: int, func_name: str = 'issue_order'):
"""Helper function to issue orders of a given model and status."""
orders = model.objects.filter(status=status)
orders = orders.filter(target_date__isnull=False)
if self.get_setting('ISSUE_BACKDATED_ORDERS', backup_value=False):
orders = orders.filter(target_date__lte=current_date())
else:
orders = orders.filter(target_date=current_date())
if orders.count() == 0:
return
logger.info('Auto-issuing %d orders for %s', orders.count(), model.__name__)
for order in orders:
try:
getattr(order, func_name)()
except Exception as e:
logger.error('Failed to issue order %s: %s', order.pk, str(e))
def auto_issue_build_orders(self):
"""Automatically issue build orders on the assigned target date."""
from build.models import Build
from build.status_codes import BuildStatus
self.issue_func(Build, BuildStatus.PENDING, func_name='issue_build')
def auto_issue_purchase_orders(self):
"""Automatically issue purchase orders on the assigned target date."""
from order.models import PurchaseOrder
from order.status_codes import PurchaseOrderStatus
self.issue_func(PurchaseOrder, PurchaseOrderStatus.PENDING)
def auto_issue_sales_orders(self):
"""Automatically issue sales orders on the assigned target date."""
from order.models import SalesOrder
from order.status_codes import SalesOrderStatus
self.issue_func(SalesOrder, SalesOrderStatus.PENDING)
def auto_issue_return_orders(self):
"""Automatically issue return orders on the assigned target date."""
from order.models import ReturnOrder
from order.status_codes import ReturnOrderStatus
self.issue_func(ReturnOrder, ReturnOrderStatus.PENDING)

View File

@ -15,7 +15,7 @@ class DigiKeyPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin):
NAME = 'DigiKeyPlugin'
TITLE = _('Supplier Integration - DigiKey')
DESCRIPTION = _('Provides support for scanning DigiKey barcodes')
VERSION = '1.0.0'
VERSION = '1.0.1'
AUTHOR = _('InvenTree contributors')
DEFAULT_SUPPLIER_NAME = 'DigiKey'
@ -25,6 +25,7 @@ class DigiKeyPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin):
'name': _('Supplier'),
'description': _("The Supplier which acts as 'DigiKey'"),
'model': 'company.company',
'model_filters': {'is_supplier': True},
}
}

View File

@ -17,7 +17,7 @@ class LCSCPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin):
NAME = 'LCSCPlugin'
TITLE = _('Supplier Integration - LCSC')
DESCRIPTION = _('Provides support for scanning LCSC barcodes')
VERSION = '1.0.0'
VERSION = '1.0.1'
AUTHOR = _('InvenTree contributors')
DEFAULT_SUPPLIER_NAME = 'LCSC'
@ -26,6 +26,7 @@ class LCSCPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin):
'name': _('Supplier'),
'description': _("The Supplier which acts as 'LCSC'"),
'model': 'company.company',
'model_filters': {'is_supplier': True},
}
}

View File

@ -15,7 +15,7 @@ class MouserPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin):
NAME = 'MouserPlugin'
TITLE = _('Supplier Integration - Mouser')
DESCRIPTION = _('Provides support for scanning Mouser barcodes')
VERSION = '1.0.0'
VERSION = '1.0.1'
AUTHOR = _('InvenTree contributors')
DEFAULT_SUPPLIER_NAME = 'Mouser'
@ -24,6 +24,7 @@ class MouserPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin):
'name': _('Supplier'),
'description': _("The Supplier which acts as 'Mouser'"),
'model': 'company.company',
'model_filters': {'is_supplier': True},
}
}

View File

@ -17,7 +17,7 @@ class TMEPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin):
NAME = 'TMEPlugin'
TITLE = _('Supplier Integration - TME')
DESCRIPTION = _('Provides support for scanning TME barcodes')
VERSION = '1.0.0'
VERSION = '1.0.1'
AUTHOR = _('InvenTree contributors')
DEFAULT_SUPPLIER_NAME = 'TME'
@ -26,6 +26,7 @@ class TMEPlugin(SupplierBarcodeMixin, SettingsMixin, InvenTreePlugin):
'name': _('Supplier'),
'description': _("The Supplier which acts as 'TME'"),
'model': 'company.company',
'model_filters': {'is_supplier': True},
}
}