Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2022-06-26 16:39:04 +10:00
commit f33bae3918
8 changed files with 100 additions and 13 deletions

View File

@ -44,8 +44,9 @@ class InvenTreeExchange(SimpleExchangeBackend):
response = urlopen(url, timeout=5, context=context) response = urlopen(url, timeout=5, context=context)
return response.read() return response.read()
except Exception: except Exception:
# Returning None here will raise an error upstream # Something has gone wrong, but we can just try again next time
return None # Raise a TypeError so the outer function can handle this
raise TypeError
def update_rates(self, base_currency=None): def update_rates(self, base_currency=None):
"""Set the requested currency codes and get rates.""" """Set the requested currency codes and get rates."""
@ -60,6 +61,8 @@ class InvenTreeExchange(SimpleExchangeBackend):
# catch connection errors # catch connection errors
except URLError: except URLError:
print('Encountered connection error while updating') print('Encountered connection error while updating')
except TypeError:
print('Exchange returned invalid response')
except OperationalError as e: except OperationalError as e:
if 'SerializationFailure' in e.__cause__.__class__.__name__: if 'SerializationFailure' in e.__cause__.__class__.__name__:
print('Serialization Failure while updating exchange rates') print('Serialization Failure while updating exchange rates')

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -32,6 +32,7 @@ import InvenTree.tasks
from plugin.events import trigger_event from plugin.events import trigger_event
import common.notifications
from part import models as PartModels from part import models as PartModels
from stock import models as StockModels from stock import models as StockModels
from users import models as UserModels from users import models as UserModels
@ -534,12 +535,51 @@ class Build(MPTTModel, ReferenceIndexingMixin):
self.subtract_allocated_stock(user) self.subtract_allocated_stock(user)
# Ensure that there are no longer any BuildItem objects # Ensure that there are no longer any BuildItem objects
# which point to thisFcan Build Order # which point to this Build Order
self.allocated_stock.all().delete() self.allocated_stock.all().delete()
# Register an event # Register an event
trigger_event('build.completed', id=self.pk) trigger_event('build.completed', id=self.pk)
# Notify users that this build has been completed
targets = [
self.issued_by,
self.responsible,
]
# Notify those users interested in the parent build
if self.parent:
targets.append(self.parent.issued_by)
targets.append(self.parent.responsible)
# Notify users if this build points to a sales order
if self.sales_order:
targets.append(self.sales_order.created_by)
targets.append(self.sales_order.responsible)
build = self
name = _(f'Build order {build} has been completed')
context = {
'build': build,
'name': name,
'slug': 'build.completed',
'message': _('A build order has been completed'),
'link': InvenTree.helpers.construct_absolute_url(self.get_absolute_url()),
'template': {
'html': 'email/build_order_completed.html',
'subject': name,
}
}
common.notifications.trigger_notification(
build,
'build.completed',
targets=targets,
context=context,
target_exclude=[user],
)
@transaction.atomic @transaction.atomic
def cancel_build(self, user, **kwargs): def cancel_build(self, user, **kwargs):
"""Mark the Build as CANCELLED. """Mark the Build as CANCELLED.

View File

@ -291,7 +291,7 @@ class InvenTreeNotificationBodies:
NewOrder = NotificationBody( NewOrder = NotificationBody(
name=_("New {verbose_name}"), name=_("New {verbose_name}"),
slug='{app_label}.new_{model_name}', slug='{app_label}.new_{model_name}',
message=_("A new {verbose_name} has been created and ,assigned to you"), message=_("A new order has been created and assigned to you"),
template='email/new_order_assigned.html', template='email/new_order_assigned.html',
) )
"""Send when a new order (build, sale or purchase) was created.""" """Send when a new order (build, sale or purchase) was created."""
@ -344,8 +344,10 @@ def trigger_notification(obj, category=None, obj_ref='pk', **kwargs):
if targets: if targets:
for target in targets: for target in targets:
if target is None:
continue
# User instance is provided # User instance is provided
if isinstance(target, get_user_model()): elif isinstance(target, get_user_model()):
if target not in target_exclude: if target not in target_exclude:
target_users.add(target) target_users.add(target)
# Group instance is provided # Group instance is provided

View File

@ -0,0 +1,27 @@
{% extends "email/email.html" %}
{% load i18n %}
{% load inventree_extras %}
{% block title %}
{{ message }}
{% if link %}
<p>{% trans "Click on the following link to view this order" %}: <a href="{{ link }}">{{ link }}</a></p>
{% endif %}
{% endblock title %}
{% block body %}
<tr style="height: 3rem; border-bottom: 1px solid">
<th>{% trans "Build Order" %}</th>
<th>{% trans "Part" %}</th>
<th>{% trans "Quantity" %}</th>
</tr>
<tr style="height: 3rem">
<td style="text-align: center;">{{ build }}</td>
<td style="text-align: center;">{{ build.part.full_name }}</td>
<td style="text-align: center;">{{ build.quantity }}</td>
</tr>
{% endblock body %}

View File

@ -938,7 +938,7 @@ function getFormFieldElement(name, options) {
/* /*
* Check that a "numerical" input field has a valid number in it. * Check that a "numerical" input field has a valid number in it.
* An invalid number is expunged at the client side by the getFormFieldValue() function, * An invalid number is expunged at the client side by the getFormFieldValue() function,
* which means that an empty string '' is sent to the server if the number is not valud. * which means that an empty string '' is sent to the server if the number is not valid.
* This can result in confusing error messages displayed under the form field. * This can result in confusing error messages displayed under the form field.
* *
* So, we can invalid numbers and display errors *before* the form is submitted! * So, we can invalid numbers and display errors *before* the form is submitted!
@ -947,7 +947,8 @@ function validateFormField(name, options) {
if (getFormFieldElement(name, options)) { if (getFormFieldElement(name, options)) {
var el = document.getElementById(`id_${name}`); var field_name = getFieldName(name, options);
var el = document.getElementById(`id_${field_name}`);
if (el.validity.valueMissing) { if (el.validity.valueMissing) {
// Accept empty strings (server will validate) // Accept empty strings (server will validate)

View File

@ -31,6 +31,18 @@
*/ */
/*
* Trim the supplied string to ensure the string length is limited to the provided value
*/
function trim(data, max_length=100) {
if (data.length > max_length) {
data = data.slice(0, max_length - 3) + '...';
}
return data;
}
// Should the ID be rendered for this string // Should the ID be rendered for this string
function renderId(title, pk, parameters={}) { function renderId(title, pk, parameters={}) {
@ -55,7 +67,7 @@ function renderCompany(name, data, parameters={}, options={}) {
var html = select2Thumbnail(data.image); var html = select2Thumbnail(data.image);
html += `<span><b>${data.name}</b></span> - <i>${data.description}</i>`; html += `<span><b>${data.name}</b></span> - <i>${trim(data.description)}</i>`;
html += renderId('{% trans "Company ID" %}', data.pk, parameters); html += renderId('{% trans "Company ID" %}', data.pk, parameters);
@ -141,7 +153,7 @@ function renderStockLocation(name, data, parameters={}, options={}) {
} }
if (render_description && data.description) { if (render_description && data.description) {
html += ` - <i>${data.description}</i>`; html += ` - <i>${trim(data.description)}</i>`;
} }
html += renderId('{% trans "Location ID" %}', data.pk, parameters); html += renderId('{% trans "Location ID" %}', data.pk, parameters);
@ -177,7 +189,7 @@ function renderPart(name, data, parameters={}, options={}) {
html += ` <span>${data.full_name || data.name}</span>`; html += ` <span>${data.full_name || data.name}</span>`;
if (data.description) { if (data.description) {
html += ` - <i><small>${data.description}</small></i>`; html += ` - <i><small>${trim(data.description)}</small></i>`;
} }
var stock_data = ''; var stock_data = '';
@ -256,7 +268,7 @@ function renderPurchaseOrder(name, data, parameters={}, options={}) {
} }
if (data.description) { if (data.description) {
html += ` - <em>${data.description}</em>`; html += ` - <em>${trim(data.description)}</em>`;
} }
html += renderId('{% trans "Order ID" %}', data.pk, parameters); html += renderId('{% trans "Order ID" %}', data.pk, parameters);
@ -282,7 +294,7 @@ function renderSalesOrder(name, data, parameters={}, options={}) {
} }
if (data.description) { if (data.description) {
html += ` - <em>${data.description}</em>`; html += ` - <em>${trim(data.description)}</em>`;
} }
html += renderId('{% trans "Order ID" %}', data.pk, parameters); html += renderId('{% trans "Order ID" %}', data.pk, parameters);
@ -319,7 +331,7 @@ function renderPartCategory(name, data, parameters={}, options={}) {
var html = `<span>${level}${data.pathstring}</span>`; var html = `<span>${level}${data.pathstring}</span>`;
if (data.description) { if (data.description) {
html += ` - <i>${data.description}</i>`; html += ` - <i>${trim(data.description)}</i>`;
} }
html += renderId('{% trans "Category ID" %}', data.pk, parameters); html += renderId('{% trans "Category ID" %}', data.pk, parameters);