Merge pull request #2229 from SchrodingersGat/low-stock-email-template

Low stock email updates
This commit is contained in:
Oliver 2021-11-02 01:06:51 +11:00 committed by GitHub
commit c31a62cc02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 99 additions and 59 deletions

View File

@ -69,6 +69,35 @@ def getStaticUrl(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():
"""
Return the qualified path for the 'blank image' placeholder.

View File

@ -1,12 +1,18 @@
# Author: Roche Christopher
# Created at 10:26 AM on 31/10/21
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import logging
from django.utils.translation import ugettext_lazy as _
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
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
"""
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)
# TODO: In the future, include the part image in the email template
if len(starred_users_email) > 0:
logger.info(f"Notify users regarding low stock of {part.name}")
context = {
'part_name': part.name,
# Part url can be used to open the page of part in application from the email.
# It can be facilitated when the application base url is accessible programmatically.
# '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
# Pass the "Part" object through to the template context
'part': part,
'link': InvenTree.helpers.construct_absolute_url(part.get_absolute_url()),
}
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)
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):
"""
Check if the stock quantity has fallen below the minimum threshold of part. If yes, notify the users who have
starred the part
Check if the stock quantity has fallen below the minimum threshold of part.
If true, notify the users who have subscribed to the part
"""
if part.is_part_low_on_stock():
inventree_tasks.offload_task(
InvenTree.tasks.offload_task(
'part.tasks.notify_low_stock',
part
)

View File

@ -122,6 +122,12 @@ def inventree_title(*args, **kwargs):
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()
def python_version(*args, **kwargs):
"""

View File

@ -14,6 +14,8 @@ from stock.models import StockItem
from common.models import InvenTreeSetting
import InvenTree.helpers
register = template.Library()
@ -119,18 +121,10 @@ def internal_link(link, 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 not base_url:
if not url:
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>')

View File

@ -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>

View 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>