mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge pull request #2229 from SchrodingersGat/low-stock-email-template
Low stock email updates
This commit is contained in:
commit
c31a62cc02
@ -69,6 +69,35 @@ def getStaticUrl(filename):
|
|||||||
return os.path.join(STATIC_URL, str(filename))
|
return os.path.join(STATIC_URL, str(filename))
|
||||||
|
|
||||||
|
|
||||||
|
def construct_absolute_url(*arg):
|
||||||
|
"""
|
||||||
|
Construct (or attempt to construct) an absolute URL from a relative URL.
|
||||||
|
|
||||||
|
This is useful when (for example) sending an email to a user with a link
|
||||||
|
to something in the InvenTree web framework.
|
||||||
|
|
||||||
|
This requires the BASE_URL configuration option to be set!
|
||||||
|
"""
|
||||||
|
|
||||||
|
base = str(InvenTreeSetting.get_setting('INVENTREE_BASE_URL'))
|
||||||
|
|
||||||
|
url = '/'.join(arg)
|
||||||
|
|
||||||
|
if not base:
|
||||||
|
return url
|
||||||
|
|
||||||
|
# Strip trailing slash from base url
|
||||||
|
if base.endswith('/'):
|
||||||
|
base = base[:-1]
|
||||||
|
|
||||||
|
if url.startswith('/'):
|
||||||
|
url = url[1:]
|
||||||
|
|
||||||
|
url = f"{base}/{url}"
|
||||||
|
|
||||||
|
return url
|
||||||
|
|
||||||
|
|
||||||
def getBlankImage():
|
def getBlankImage():
|
||||||
"""
|
"""
|
||||||
Return the qualified path for the 'blank image' placeholder.
|
Return the qualified path for the 'blank image' placeholder.
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
# Author: Roche Christopher
|
# -*- coding: utf-8 -*-
|
||||||
# Created at 10:26 AM on 31/10/21
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
|
||||||
from InvenTree import tasks as inventree_tasks
|
from allauth.account.models import EmailAddress
|
||||||
|
|
||||||
|
from common.models import InvenTree
|
||||||
|
|
||||||
|
import InvenTree.helpers
|
||||||
|
import InvenTree.tasks
|
||||||
|
|
||||||
from part.models import Part
|
from part.models import Part
|
||||||
|
|
||||||
logger = logging.getLogger("inventree")
|
logger = logging.getLogger("inventree")
|
||||||
@ -17,36 +23,36 @@ def notify_low_stock(part: Part):
|
|||||||
Notify users who have starred a part when its stock quantity falls below the minimum threshold
|
Notify users who have starred a part when its stock quantity falls below the minimum threshold
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from allauth.account.models import EmailAddress
|
logger.info(f"Sending low stock notification email for {part.full_name}")
|
||||||
|
|
||||||
starred_users_email = EmailAddress.objects.filter(user__starred_parts__part=part)
|
starred_users_email = EmailAddress.objects.filter(user__starred_parts__part=part)
|
||||||
|
|
||||||
|
# TODO: In the future, include the part image in the email template
|
||||||
|
|
||||||
if len(starred_users_email) > 0:
|
if len(starred_users_email) > 0:
|
||||||
logger.info(f"Notify users regarding low stock of {part.name}")
|
logger.info(f"Notify users regarding low stock of {part.name}")
|
||||||
context = {
|
context = {
|
||||||
'part_name': part.name,
|
# Pass the "Part" object through to the template context
|
||||||
# Part url can be used to open the page of part in application from the email.
|
'part': part,
|
||||||
# It can be facilitated when the application base url is accessible programmatically.
|
'link': InvenTree.helpers.construct_absolute_url(part.get_absolute_url()),
|
||||||
# 'part_url': f'{application_base_url}/part/{stock_item.part.id}',
|
|
||||||
|
|
||||||
# quantity is in decimal field datatype. Since the same datatype is used in models,
|
|
||||||
# it is not converted to number/integer,
|
|
||||||
'part_quantity': part.total_stock,
|
|
||||||
'minimum_quantity': part.minimum_stock
|
|
||||||
}
|
}
|
||||||
subject = _(f'Attention! {part.name} is low on stock')
|
|
||||||
html_message = render_to_string('stock/low_stock_notification.html', context)
|
subject = _(f'[InvenTree] {part.name} is low on stock')
|
||||||
|
html_message = render_to_string('email/low_stock_notification.html', context)
|
||||||
recipients = starred_users_email.values_list('email', flat=True)
|
recipients = starred_users_email.values_list('email', flat=True)
|
||||||
inventree_tasks.send_email(subject, '', recipients, html_message=html_message)
|
|
||||||
|
InvenTree.tasks.send_email(subject, '', recipients, html_message=html_message)
|
||||||
|
|
||||||
|
|
||||||
def notify_low_stock_if_required(part: Part):
|
def notify_low_stock_if_required(part: Part):
|
||||||
"""
|
"""
|
||||||
Check if the stock quantity has fallen below the minimum threshold of part. If yes, notify the users who have
|
Check if the stock quantity has fallen below the minimum threshold of part.
|
||||||
starred the part
|
|
||||||
|
If true, notify the users who have subscribed to the part
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if part.is_part_low_on_stock():
|
if part.is_part_low_on_stock():
|
||||||
inventree_tasks.offload_task(
|
InvenTree.tasks.offload_task(
|
||||||
'part.tasks.notify_low_stock',
|
'part.tasks.notify_low_stock',
|
||||||
part
|
part
|
||||||
)
|
)
|
||||||
|
@ -122,6 +122,12 @@ def inventree_title(*args, **kwargs):
|
|||||||
return version.inventreeInstanceTitle()
|
return version.inventreeInstanceTitle()
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag()
|
||||||
|
def inventree_base_url(*args, **kwargs):
|
||||||
|
""" Return the INVENTREE_BASE_URL setting """
|
||||||
|
return InvenTreeSetting.get_setting('INVENTREE_BASE_URL')
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def python_version(*args, **kwargs):
|
def python_version(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -14,6 +14,8 @@ from stock.models import StockItem
|
|||||||
|
|
||||||
from common.models import InvenTreeSetting
|
from common.models import InvenTreeSetting
|
||||||
|
|
||||||
|
import InvenTree.helpers
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
@ -119,18 +121,10 @@ def internal_link(link, text):
|
|||||||
|
|
||||||
text = str(text)
|
text = str(text)
|
||||||
|
|
||||||
base_url = InvenTreeSetting.get_setting('INVENTREE_BASE_URL')
|
url = InvenTree.helpers.construct_absolute_url(link)
|
||||||
|
|
||||||
# If the base URL is not set, just return the text
|
# If the base URL is not set, just return the text
|
||||||
if not base_url:
|
if not url:
|
||||||
return text
|
return text
|
||||||
|
|
||||||
if not base_url.endswith('/'):
|
|
||||||
base_url += '/'
|
|
||||||
|
|
||||||
if base_url.endswith('/') and link.startswith('/'):
|
|
||||||
link = link[1:]
|
|
||||||
|
|
||||||
url = f"{base_url}{link}"
|
|
||||||
|
|
||||||
return mark_safe(f'<a href="{url}">{text}</a>')
|
return mark_safe(f'<a href="{url}">{text}</a>')
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
{% load i18n %}
|
|
||||||
|
|
||||||
<p>{% trans "Hi, " %} {{ part_name }} {% trans "is low on stock. Kindly do the needful." %}</p>
|
|
||||||
|
|
||||||
<table style="border-collapse:collapse; width: 80%;margin-left: 10%; font-size: 1rem">
|
|
||||||
|
|
||||||
<tr style="background: aliceblue; height: 4rem;">
|
|
||||||
<th colspan="3" style="padding-bottom: 1rem; font-size: 1.5rem; color:rgb(210,0, 0)">{% trans "Part low on stock" %}</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr style="height: 3rem; border-bottom: 1px solid">
|
|
||||||
<th>{% trans "Part Name" %}</th>
|
|
||||||
<th>{% trans "Available Quantity" %}</th>
|
|
||||||
<th>{% trans "Minimum Quantity" %}</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr style="height: 3rem">
|
|
||||||
<td style="text-align: center">{{ part_name }}</td>
|
|
||||||
<td style="text-align: center">{{ part_quantity }}</td>
|
|
||||||
<td style="text-align: center">{{ minimum_quantity }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr style="background-color: aliceblue;height: 4rem;">
|
|
||||||
<td colspan="3" style="padding-top:1rem; text-align: center">{% trans "You are receiving this mail because you have starred the part " %} {{ part_name }}
|
|
||||||
{% trans "Inventree application" %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
35
InvenTree/templates/email/low_stock_notification.html
Normal file
35
InvenTree/templates/email/low_stock_notification.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
|
<table style="border-collapse:collapse; width: 80%;margin-left: 10%; font-size: 1rem">
|
||||||
|
|
||||||
|
<tr style="background: aliceblue; height: 4rem;">
|
||||||
|
<th colspan="3" style="padding-bottom: 1rem; font-size: 1.25rem; color:rgb(210, 20, 20)">
|
||||||
|
<p>{% blocktrans with part=part.name %} The available stock for {{ part }} has fallen below the configured minimum level{% endblocktrans %}</p>
|
||||||
|
{% if link %}
|
||||||
|
<p>{% trans "Click on the following link to view this part" %}: <a href="{{ link }}">{{ link }}</a></p>
|
||||||
|
{% endif %}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr style="height: 3rem; border-bottom: 1px solid">
|
||||||
|
<th>{% trans "Part Name" %}</th>
|
||||||
|
<th>{% trans "Available Quantity" %}</th>
|
||||||
|
<th>{% trans "Minimum Quantity" %}</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr style="height: 3rem">
|
||||||
|
<td style="text-align: center;">{{ part.full_name }}</td>
|
||||||
|
<td style="text-align: center;">{{ part.total_stock }}</td>
|
||||||
|
<td style="text-align: center;">{{ part.minimum_stock }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr style="background-color: aliceblue;height: 4rem;">
|
||||||
|
<td colspan="3" style="padding-top:1rem; text-align: center">
|
||||||
|
<p><em>{% blocktrans with part=part.name %}You are receiving this email because you are subscribed to notifications for this part {% endblocktrans %}.</em></p>
|
||||||
|
<p><em><small>{% trans "InvenTree version" %}: {% inventree_version %}</small></em></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user