diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index 7ca2e942fd..aae5e5bfe9 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -6,6 +6,7 @@ Order model definitions from django.db import models from django.core.validators import MinValueValidator +from django.core.exceptions import ValidationError from django.contrib.auth.models import User from django.urls import reverse from django.utils.translation import ugettext as _ @@ -101,6 +102,50 @@ class PurchaseOrder(Order): def get_absolute_url(self): return reverse('purchase-order-detail', kwargs={'pk': self.id}) + def add_line_item(self, supplier_part, quantity, group=True, reference=''): + """ Add a new line item to this purchase order. + This function will check that: + + * The supplier part matches the supplier specified for this purchase order + * The quantity is greater than zero + + Args: + supplier_part - The supplier_part to add + quantity - The number of items to add + group - If True, this new quantity will be added to an existing line item for the same supplier_part (if it exists) + """ + + try: + quantity = int(quantity) + if quantity <= 0: + raise ValidationError({ + 'quantity': _("Quantity must be greater than zero")}) + except ValueError: + raise ValidationError({'quantity': _("Invalid quantity provided")}) + + if not supplier_part.supplier == self.supplier: + raise ValidationError({'supplier': _("Part supplier must match PO supplier")}) + + if group: + # Check if there is already a matching line item + matches = PurchaseOrderLineItem.objects.filter(part=supplier_part) + + if matches.count() > 0: + line = matches.first() + + line.quantity += quantity + line.save() + + return + + line = PurchaseOrderLineItem( + order=self, + part=supplier_part, + quantity=quantity, + reference=reference) + + line.save() + class OrderLineItem(models.Model): """ Abstract model for an order line item diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 53e8355d79..69766db282 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -9,6 +9,8 @@ from django.utils.translation import ugettext as _ from django.views.generic import DetailView, ListView from django.forms import HiddenInput +import logging + from .models import PurchaseOrder, PurchaseOrderLineItem from build.models import Build from company.models import Company, SupplierPart @@ -22,6 +24,8 @@ from InvenTree.helpers import str2bool from InvenTree.status_codes import OrderStatus +logger = logging.getLogger(__name__) + class PurchaseOrderIndex(ListView): """ List view for all purchase orders """ @@ -323,7 +327,6 @@ class OrderParts(AjaxView): supplier_part = SupplierPart.objects.get(id=supplier_part_id) except (SupplierPart.DoesNotExist, ValueError): supplier_part = None - print('Error getting supplier part for ID', supplier_part_id) # Ensure a valid quantity is passed try: @@ -350,8 +353,6 @@ class OrderParts(AjaxView): # Which purchase order is selected for a given supplier? pk = item.replace('purchase-order-', '') - print(item) - # Check that the Supplier actually exists try: supplier = Company.objects.get(id=pk) @@ -379,6 +380,8 @@ class OrderParts(AjaxView): # Map parts to suppliers self.get_suppliers() + valid = False + if form_step == 'select_parts': # No errors? Proceed to PO selection form if part_errors == False: @@ -389,15 +392,55 @@ class OrderParts(AjaxView): elif form_step == 'select_purchase_orders': - self.ajax_template_name = 'order/order_wizard/select_pos.html' + valid = part_errors is False and supplier_errors is False + + # Form wizard is complete! Add items to purchase orders + if valid: + self.order_items() + data = { - 'form_valid': False, + 'form_valid': valid, + 'success': 'Ordered {n} parts'.format(n=len(self.parts)) } return self.renderJsonResponse(self.request, data=data) + def order_items(self): + """ Add the selected items to the purchase orders. """ + + for supplier in self.suppliers: + + # Check that the purchase order does actually exist + try: + order = PurchaseOrder.objects.get(pk=supplier.selected_purchase_order) + except PurchaseOrder.DoesNotExist: + logger.critical('Could not add items to purchase order {po} - Order does not exist'.format(po=supplier.selected_purchase_order)) + continue + + for item in supplier.order_items: + + # Ensure that the quantity is valid + try: + quantity = int(item.order_quantity) + if quantity <= 0: + continue + except ValueError: + logger.warning("Did not add part to purchase order - incorrect quantity") + continue + + # Check that the supplier part does actually exist + try: + supplier_part = SupplierPart.objects.get(pk=item.order_supplier) + except SupplierPart.DoesNotExist: + logger.critical("Could not add part '{part}' to purchase order - selected supplier part '{sp}' does not exist.".format( + part=item, + sp=item.order_supplier)) + continue + + order.add_line_item(supplier_part, quantity) + class POLineItemCreate(AjaxCreateView): """ AJAX view for creating a new PurchaseOrderLineItem object