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

Overdue order notification (#3114)

* Adds a background task to notify users when a PurchaseOrder becomes overdue

* Schedule the overdue purchaseorder check to occur daily

* Allow notifications to be sent to "Owner" instances

- Extract user information from the Owner instance

* add unit test to ensure notifications are sent for overdue purchase orders

* Adds notification for overdue sales orders

* Clean up notification display panel

- Simplify rendering
- Order "newest at top"
- Element alignment tweaks

* style fixes

* More style fixes

* Tweak notification padding

* Fix import order

* Adds task to notify user of overdue build orders

* Adds unit tests for build order notifications

* Refactor subject line for emails:

- Use the configured instance title as a prefix for the subject line

* Add email template for overdue build orders

* Fix unit tests to accommodate new default value

* Logic error fix
This commit is contained in:
Oliver
2022-06-06 19:12:29 +10:00
committed by GitHub
parent 7b4d0605b8
commit 1e6bdfbcab
17 changed files with 439 additions and 22 deletions

View File

@ -274,6 +274,7 @@ class NotificationList(generics.ListAPIView):
'category',
'name',
'read',
'creation',
]
search_fields = [

View File

@ -710,7 +710,7 @@ class InvenTreeSetting(BaseInvenTreeSetting):
'INVENTREE_INSTANCE': {
'name': _('Server Instance Name'),
'default': 'InvenTree server',
'default': 'InvenTree',
'description': _('String descriptor for the server instance'),
},

View File

@ -3,11 +3,15 @@
import logging
from datetime import timedelta
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from common.models import NotificationEntry, NotificationMessage
from InvenTree.helpers import inheritors
from InvenTree.ready import isImportingData
from plugin import registry
from plugin.models import NotificationUserSetting
from users.models import Owner
logger = logging.getLogger('inventree')
@ -266,7 +270,7 @@ def trigger_notification(obj, category=None, obj_ref='pk', **kwargs):
if isImportingData():
return
# Resolve objekt reference
# Resolve object reference
obj_ref_value = getattr(obj, obj_ref)
# Try with some defaults
@ -285,11 +289,33 @@ def trigger_notification(obj, category=None, obj_ref='pk', **kwargs):
return
logger.info(f"Gathering users for notification '{category}'")
# Collect possible targets
if not targets:
targets = target_fnc(*target_args, **target_kwargs)
# Convert list of targets to a list of users
# (targets may include 'owner' or 'group' classes)
target_users = set()
if targets:
for target in targets:
# User instance is provided
if isinstance(target, get_user_model()):
target_users.add(target)
# Group instance is provided
elif isinstance(target, Group):
for user in get_user_model().objects.filter(groups__name=target.name):
target_users.add(user)
# Owner instance (either 'user' or 'group' is provided)
elif isinstance(target, Owner):
for owner in target.get_related_owners(include_group=False):
target_users.add(owner.owner)
# Unhandled type
else:
logger.error(f"Unknown target passed to trigger_notification method: {target}")
if target_users:
logger.info(f"Sending notification '{category}' for '{str(obj)}'")
# Collect possible methods
@ -301,7 +327,7 @@ def trigger_notification(obj, category=None, obj_ref='pk', **kwargs):
for method in delivery_methods:
logger.info(f"Triggering notification method '{method.METHOD_NAME}'")
try:
deliver_notification(method, obj, category, targets, context)
deliver_notification(method, obj, category, target_users, context)
except NotImplementedError as error:
# Allow any single notification method to fail, without failing the others
logger.error(error)

View File

@ -78,7 +78,7 @@ class SettingsTest(InvenTreeTestCase):
# check as_int
self.assertEqual(stale_days.as_int(), 0)
self.assertEqual(instance_obj.as_int(), 'InvenTree server') # not an int -> return default
self.assertEqual(instance_obj.as_int(), 'InvenTree') # not an int -> return default
# check as_bool
self.assertEqual(report_test_obj.as_bool(), True)
@ -258,7 +258,7 @@ class GlobalSettingsApiTest(InvenTreeAPITestCase):
# Access via the API, and the default value should be received
response = self.get(url, expected_code=200)
self.assertEqual(response.data['value'], 'InvenTree server')
self.assertEqual(response.data['value'], 'InvenTree')
# Now, the object should have been created in the DB
self.patch(