mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 13:15:43 +00:00 
			
		
		
		
	More stuff
This commit is contained in:
		| @@ -42,6 +42,10 @@ | ||||
|     opacity: 60%; | ||||
| } | ||||
|  | ||||
| .progress-bar-exceed { | ||||
|     background: #eeaa33; | ||||
| } | ||||
|  | ||||
| .progress-value { | ||||
|     width: 100%; | ||||
|     color: #333; | ||||
|   | ||||
| @@ -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 ` | ||||
|     <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> | ||||
|     `; | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -9,6 +9,14 @@ | ||||
| InvenTree | {% trans "Sales Order" %} | ||||
| {% 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 %} | ||||
| <img class='part-thumb' | ||||
| {% if order.customer.image %} | ||||
|   | ||||
| @@ -190,7 +190,7 @@ $("#so-lines-table").on('load-success.bs.table', function() { | ||||
|         var pk = $(this).attr('pk'); | ||||
|  | ||||
|         launchModalForm(`/order/sales-order/allocation/new/`, { | ||||
|             reload: table, | ||||
|             success: reloadTable, | ||||
|             data: { | ||||
|                 line: pk, | ||||
|             }, | ||||
|   | ||||
| @@ -95,6 +95,9 @@ sales_order_urls = [ | ||||
|     # URLs for sales order allocations | ||||
|     url(r'^allocation/', include([ | ||||
|         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)), | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user