mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
More stuff
This commit is contained in:
parent
6ab03bd05a
commit
fd42149f67
@ -42,6 +42,10 @@
|
|||||||
opacity: 60%;
|
opacity: 60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.progress-bar-exceed {
|
||||||
|
background: #eeaa33;
|
||||||
|
}
|
||||||
|
|
||||||
.progress-value {
|
.progress-value {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
@ -113,11 +113,17 @@ function makeProgressBar(value, maximum, opts) {
|
|||||||
percent = 100;
|
percent = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var extraclass = '';
|
||||||
|
|
||||||
|
if (value > maximum) {
|
||||||
|
extraclass='progress-bar-exceed';
|
||||||
|
}
|
||||||
|
|
||||||
var id = opts.id || 'progress-bar';
|
var id = opts.id || 'progress-bar';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div id='${id}' class='progress'>
|
<div id='${id}' class='progress'>
|
||||||
<div class='progress-bar' role='progressbar' aria-valuenow='${percent}' aria-valuemin='0' aria-valuemax='100' style='width:${percent}%'></div>
|
<div class='progress-bar ${extraclass}' role='progressbar' aria-valuenow='${percent}' aria-valuemin='0' aria-valuemax='100' style='width:${percent}%'></div>
|
||||||
<div class='progress-value'>${value} / ${maximum}</div>
|
<div class='progress-value'>${value} / ${maximum}</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
@ -24,7 +24,7 @@ from stock import models as stock_models
|
|||||||
from company.models import Company, SupplierPart
|
from company.models import Company, SupplierPart
|
||||||
|
|
||||||
from InvenTree.fields import RoundingDecimalField
|
from InvenTree.fields import RoundingDecimalField
|
||||||
from InvenTree.helpers import decimal2string
|
from InvenTree.helpers import decimal2string, normalize
|
||||||
from InvenTree.status_codes import OrderStatus
|
from InvenTree.status_codes import OrderStatus
|
||||||
from InvenTree.models import InvenTreeAttachment
|
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"))
|
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):
|
class PurchaseOrderAttachment(InvenTreeAttachment):
|
||||||
"""
|
"""
|
||||||
@ -385,6 +394,12 @@ class SalesOrderLineItem(OrderLineItem):
|
|||||||
|
|
||||||
return query['allocated']
|
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):
|
class SalesOrderAllocation(models.Model):
|
||||||
"""
|
"""
|
||||||
@ -457,7 +472,7 @@ class SalesOrderAllocation(models.Model):
|
|||||||
if self.item.serial and self.quantity == 1:
|
if self.item.serial and self.quantity == 1:
|
||||||
return "# {sn}".format(sn=self.item.serial)
|
return "# {sn}".format(sn=self.item.serial)
|
||||||
else:
|
else:
|
||||||
return self.quantity
|
return normalize(self.quantity)
|
||||||
|
|
||||||
def get_location(self):
|
def get_location(self):
|
||||||
return self.item.location.id if self.item.location else None
|
return self.item.location.id if self.item.location else None
|
||||||
|
@ -9,6 +9,14 @@
|
|||||||
InvenTree | {% trans "Sales Order" %}
|
InvenTree | {% trans "Sales Order" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block pre_content %}
|
||||||
|
{% if not order.is_fully_allocated %}
|
||||||
|
<div class='alert alert-block alert-danger'>
|
||||||
|
{% trans "This SalesOrder has not been fully allocated" %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block thumbnail %}
|
{% block thumbnail %}
|
||||||
<img class='part-thumb'
|
<img class='part-thumb'
|
||||||
{% if order.customer.image %}
|
{% if order.customer.image %}
|
||||||
|
@ -190,7 +190,7 @@ $("#so-lines-table").on('load-success.bs.table', function() {
|
|||||||
var pk = $(this).attr('pk');
|
var pk = $(this).attr('pk');
|
||||||
|
|
||||||
launchModalForm(`/order/sales-order/allocation/new/`, {
|
launchModalForm(`/order/sales-order/allocation/new/`, {
|
||||||
reload: table,
|
success: reloadTable,
|
||||||
data: {
|
data: {
|
||||||
line: pk,
|
line: pk,
|
||||||
},
|
},
|
||||||
|
@ -95,6 +95,9 @@ sales_order_urls = [
|
|||||||
# URLs for sales order allocations
|
# URLs for sales order allocations
|
||||||
url(r'^allocation/', include([
|
url(r'^allocation/', include([
|
||||||
url(r'^new/', views.SalesOrderAllocationCreate.as_view(), name='so-allocation-create'),
|
url(r'^new/', views.SalesOrderAllocationCreate.as_view(), name='so-allocation-create'),
|
||||||
|
url(r'(?P<pk>\d+)/', include([
|
||||||
|
url(r'^edit/', views.SalesOrderAllocationEdit.as_view(), name='so-allocation-edit'),
|
||||||
|
])),
|
||||||
])),
|
])),
|
||||||
|
|
||||||
url(r'^attachments/', include(sales_order_attachment_urls)),
|
url(r'^attachments/', include(sales_order_attachment_urls)),
|
||||||
|
@ -1173,11 +1173,33 @@ class SalesOrderAllocationCreate(AjaxCreateView):
|
|||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
initials = super().get_initial().copy()
|
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:
|
if line_id is not None:
|
||||||
initials['line'] = SalesOrderLineItem.objects.get(pk=line)
|
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
|
return initials
|
||||||
|
|
||||||
def get_form(self):
|
def get_form(self):
|
||||||
@ -1209,3 +1231,18 @@ class SalesOrderAllocationCreate(AjaxCreateView):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
return form
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user