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