diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index 834070adae..f95f81ec1e 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -42,6 +42,10 @@ opacity: 60%; } +.progress-bar-exceed { + background: #eeaa33; +} + .progress-value { width: 100%; color: #333; diff --git a/InvenTree/InvenTree/static/script/inventree/inventree.js b/InvenTree/InvenTree/static/script/inventree/inventree.js index 6d29ca3704..fdf9b2281d 100644 --- a/InvenTree/InvenTree/static/script/inventree/inventree.js +++ b/InvenTree/InvenTree/static/script/inventree/inventree.js @@ -113,11 +113,17 @@ function makeProgressBar(value, maximum, opts) { percent = 100; } + var extraclass = ''; + + if (value > maximum) { + extraclass='progress-bar-exceed'; + } + var id = opts.id || 'progress-bar'; return `
-
+
${value} / ${maximum}
`; diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index bcc2beb1a5..942a22a316 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -24,7 +24,7 @@ from stock import models as stock_models from company.models import Company, SupplierPart from InvenTree.fields import RoundingDecimalField -from InvenTree.helpers import decimal2string +from InvenTree.helpers import decimal2string, normalize from InvenTree.status_codes import OrderStatus from InvenTree.models import InvenTreeAttachment @@ -277,6 +277,15 @@ class SalesOrder(Order): customer_reference = models.CharField(max_length=64, blank=True, help_text=_("Customer order reference code")) + def is_fully_allocated(self): + """ Return True if all line items are fully allocated """ + + for line in self.lines.all(): + if not line.is_fully_allocated(): + return False + + return True + class PurchaseOrderAttachment(InvenTreeAttachment): """ @@ -385,6 +394,12 @@ class SalesOrderLineItem(OrderLineItem): return query['allocated'] + def is_fully_allocated(self): + return self.allocated_quantity() >= self.quantity + + def is_over_allocated(self): + return self.allocated_quantity() > self.quantity + class SalesOrderAllocation(models.Model): """ @@ -457,7 +472,7 @@ class SalesOrderAllocation(models.Model): if self.item.serial and self.quantity == 1: return "# {sn}".format(sn=self.item.serial) else: - return self.quantity + return normalize(self.quantity) def get_location(self): return self.item.location.id if self.item.location else None diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html index 98faadb1f4..a3b38b1f90 100644 --- a/InvenTree/order/templates/order/sales_order_base.html +++ b/InvenTree/order/templates/order/sales_order_base.html @@ -9,6 +9,14 @@ InvenTree | {% trans "Sales Order" %} {% endblock %} +{% block pre_content %} +{% if not order.is_fully_allocated %} +
+ {% trans "This SalesOrder has not been fully allocated" %} +
+{% endif %} +{% endblock %} + {% block thumbnail %} \d+)/', include([ + url(r'^edit/', views.SalesOrderAllocationEdit.as_view(), name='so-allocation-edit'), + ])), ])), url(r'^attachments/', include(sales_order_attachment_urls)), diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 82b83b92cb..98dad9511a 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -1173,11 +1173,33 @@ class SalesOrderAllocationCreate(AjaxCreateView): def get_initial(self): initials = super().get_initial().copy() - line = self.request.GET.get('line', None) + line_id = self.request.GET.get('line', None) - if line is not None: - initials['line'] = SalesOrderLineItem.objects.get(pk=line) + if line_id is not None: + line = SalesOrderLineItem.objects.get(pk=line_id) + + initials['line'] = line + + # Search for matching stock items, pre-fill if there is only one + items = StockItem.objects.filter(part=line.part) + + quantity = line.quantity - line.allocated_quantity() + + if quantity < 0: + quantity = 0 + if items.count() == 1: + item = items.first() + initials['item'] = item + + # Reduce the quantity IF there is not enough stock + qmax = item.quantity - item.allocation_count() + + if qmax < quantity: + quantity = qmax + + initials['quantity'] = quantity + return initials def get_form(self): @@ -1209,3 +1231,18 @@ class SalesOrderAllocationCreate(AjaxCreateView): pass return form + + +class SalesOrderAllocationEdit(AjaxUpdateView): + + model = SalesOrderAllocation + ajax_form_title = _('Edit Allocation Quantity') + + def get_form(self): + form = super().get_form() + + # Prevent the user from editing particular fields + form.fields.pop('item') + form.fields.pop('line') + + return form