mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 13:15:43 +00:00 
			
		
		
		
	Refactor POLineItemCreate form
This commit is contained in:
		| @@ -20,7 +20,7 @@ from common.forms import MatchItemForm | ||||
| import part.models | ||||
|  | ||||
| from stock.models import StockLocation | ||||
| from .models import PurchaseOrder, PurchaseOrderLineItem | ||||
| from .models import PurchaseOrder | ||||
| from .models import SalesOrder, SalesOrderLineItem | ||||
| from .models import SalesOrderAllocation | ||||
|  | ||||
| @@ -96,24 +96,6 @@ class ReceivePurchaseOrderForm(HelperForm): | ||||
|         ] | ||||
|  | ||||
|  | ||||
| class EditPurchaseOrderLineItemForm(HelperForm): | ||||
|     """ Form for editing a PurchaseOrderLineItem object """ | ||||
|  | ||||
|     quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5, label=_('Quantity')) | ||||
|  | ||||
|     class Meta: | ||||
|         model = PurchaseOrderLineItem | ||||
|         fields = [ | ||||
|             'order', | ||||
|             'part', | ||||
|             'quantity', | ||||
|             'reference', | ||||
|             'purchase_price', | ||||
|             'destination', | ||||
|             'notes', | ||||
|         ] | ||||
|  | ||||
|  | ||||
| class EditSalesOrderLineItemForm(HelperForm): | ||||
|     """ Form for editing a SalesOrderLineItem object """ | ||||
|  | ||||
|   | ||||
| @@ -350,7 +350,7 @@ class SOLineItemSerializer(InvenTreeModelSerializer): | ||||
|         max_digits=19, | ||||
|         decimal_places=4, | ||||
|         allow_null=True | ||||
|     )     | ||||
|     ) | ||||
|  | ||||
|     sale_price_string = serializers.CharField(source='sale_price', read_only=True) | ||||
|  | ||||
|   | ||||
| @@ -38,26 +38,34 @@ | ||||
|  | ||||
| {% if order.status == PurchaseOrderStatus.PENDING %} | ||||
| $('#new-po-line').click(function() { | ||||
|     launchModalForm("{% url 'po-line-item-create' %}", | ||||
|         { | ||||
|             reload: true, | ||||
|             data: { | ||||
|                 order: {{ order.id }}, | ||||
|  | ||||
|  | ||||
|     constructForm('{% url "api-po-line-list" %}', { | ||||
|         fields: { | ||||
|             order: { | ||||
|                 value: {{ order.pk }}, | ||||
|                 hidden: true, | ||||
|             }, | ||||
|             secondary: [ | ||||
|                 { | ||||
|                     field: 'part', | ||||
|                     label: '{% trans "New Supplier Part" %}', | ||||
|                     title: '{% trans "Create new supplier part" %}', | ||||
|                     url: "{% url 'supplier-part-create' %}", | ||||
|                     data: { | ||||
|                         supplier: {{ order.supplier.id }}, | ||||
|                     }, | ||||
|             part: { | ||||
|                 filters: { | ||||
|                     part_detail: true, | ||||
|                     supplier_detail: true, | ||||
|                     supplier: {{ order.supplier.pk }}, | ||||
|                 }, | ||||
|             ], | ||||
|         } | ||||
|     ); | ||||
|             }, | ||||
|             quantity: {}, | ||||
|             reference: {}, | ||||
|             purchase_price: {}, | ||||
|             purchase_price_currency: {}, | ||||
|             destination: {}, | ||||
|             notes: {}, | ||||
|         }, | ||||
|         method: 'POST', | ||||
|         title: '{% trans "Add Line Item" %}', | ||||
|         onSuccess: reloadTable, | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| {% endif %} | ||||
|  | ||||
| function reloadTable() { | ||||
| @@ -77,6 +85,7 @@ function setupCallbacks() { | ||||
|             fields: { | ||||
|                 part: { | ||||
|                     filters: { | ||||
|                         part_detail: true, | ||||
|                         supplier_detail: true, | ||||
|                         supplier: {{ order.supplier.pk }}, | ||||
|                     } | ||||
|   | ||||
| @@ -104,57 +104,6 @@ class POTests(OrderViewTestCase): | ||||
|         order = PurchaseOrder.objects.get(pk=1) | ||||
|         self.assertEqual(order.status, PurchaseOrderStatus.PLACED) | ||||
|  | ||||
|     def test_line_item_create(self): | ||||
|         """ Test the form for adding a new LineItem to a PurchaseOrder """ | ||||
|  | ||||
|         # Record the number of line items in the PurchaseOrder | ||||
|         po = PurchaseOrder.objects.get(pk=1) | ||||
|         n = po.lines.count() | ||||
|         self.assertEqual(po.status, PurchaseOrderStatus.PENDING) | ||||
|  | ||||
|         url = reverse('po-line-item-create') | ||||
|  | ||||
|         # GET the form (pass the correct info) | ||||
|         response = self.client.get(url, {'order': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') | ||||
|  | ||||
|         post_data = { | ||||
|             'part': 100, | ||||
|             'quantity': 45, | ||||
|             'reference': 'Test reference field', | ||||
|             'notes': 'Test notes field' | ||||
|         } | ||||
|  | ||||
|         # POST with an invalid purchase order | ||||
|         post_data['order'] = 99 | ||||
|         response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') | ||||
|         data = json.loads(response.content) | ||||
|         self.assertFalse(data['form_valid']) | ||||
|  | ||||
|         # POST with a part that does not match the purchase order | ||||
|         post_data['order'] = 1 | ||||
|         post_data['part'] = 7 | ||||
|         response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') | ||||
|         data = json.loads(response.content) | ||||
|         self.assertFalse(data['form_valid']) | ||||
|  | ||||
|         # POST with an invalid part | ||||
|         post_data['part'] = 12345 | ||||
|         response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') | ||||
|         data = json.loads(response.content) | ||||
|         self.assertFalse(data['form_valid']) | ||||
|  | ||||
|         # POST the form with valid data | ||||
|         post_data['part'] = 100 | ||||
|         response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         data = json.loads(response.content) | ||||
|         self.assertTrue(data['form_valid']) | ||||
|  | ||||
|         self.assertEqual(n + 1, PurchaseOrder.objects.get(pk=1).lines.count()) | ||||
|  | ||||
|         line = PurchaseOrderLineItem.objects.get(order=1, part=100) | ||||
|         self.assertEqual(line.quantity, 45) | ||||
|  | ||||
|  | ||||
| class TestPOReceive(OrderViewTestCase): | ||||
|     """ Tests for receiving a purchase order """ | ||||
|   | ||||
| @@ -1049,90 +1049,6 @@ class OrderParts(AjaxView): | ||||
|                 order.add_line_item(supplier_part, quantity, purchase_price=purchase_price) | ||||
|  | ||||
|  | ||||
| class POLineItemCreate(AjaxCreateView): | ||||
|     """ AJAX view for creating a new PurchaseOrderLineItem object | ||||
|     """ | ||||
|  | ||||
|     model = PurchaseOrderLineItem | ||||
|     context_object_name = 'line' | ||||
|     form_class = order_forms.EditPurchaseOrderLineItemForm | ||||
|     ajax_form_title = _('Add Line Item') | ||||
|  | ||||
|     def validate(self, item, form, **kwargs): | ||||
|  | ||||
|         order = form.cleaned_data.get('order', None) | ||||
|  | ||||
|         part = form.cleaned_data.get('part', None) | ||||
|  | ||||
|         if not part: | ||||
|             form.add_error('part', _('Supplier part must be specified')) | ||||
|  | ||||
|         if part and order: | ||||
|             if not part.supplier == order.supplier: | ||||
|                 form.add_error( | ||||
|                     'part', | ||||
|                     _('Supplier must match for Part and Order') | ||||
|                 ) | ||||
|  | ||||
|     def get_form(self): | ||||
|         """ Limit choice options based on the selected order, etc | ||||
|         """ | ||||
|  | ||||
|         form = super().get_form() | ||||
|  | ||||
|         # Limit the available to orders to ones that are PENDING | ||||
|         query = form.fields['order'].queryset | ||||
|         query = query.filter(status=PurchaseOrderStatus.PENDING) | ||||
|         form.fields['order'].queryset = query | ||||
|  | ||||
|         order_id = form['order'].value() | ||||
|  | ||||
|         try: | ||||
|             order = PurchaseOrder.objects.get(id=order_id) | ||||
|  | ||||
|             query = form.fields['part'].queryset | ||||
|  | ||||
|             # Only allow parts from the selected supplier | ||||
|             query = query.filter(supplier=order.supplier.id) | ||||
|  | ||||
|             exclude = [] | ||||
|  | ||||
|             for line in order.lines.all(): | ||||
|                 if line.part and line.part.id not in exclude: | ||||
|                     exclude.append(line.part.id) | ||||
|  | ||||
|             # Remove parts that are already in the order | ||||
|             query = query.exclude(id__in=exclude) | ||||
|  | ||||
|             form.fields['part'].queryset = query | ||||
|             form.fields['order'].widget = HiddenInput() | ||||
|         except (ValueError, PurchaseOrder.DoesNotExist): | ||||
|             pass | ||||
|  | ||||
|         return form | ||||
|  | ||||
|     def get_initial(self): | ||||
|         """ Extract initial data for the line item. | ||||
|  | ||||
|         - The 'order' will be passed as a query parameter | ||||
|         - Use this to set the 'order' field and limit the options for 'part' | ||||
|         """ | ||||
|  | ||||
|         initials = super().get_initial().copy() | ||||
|  | ||||
|         order_id = self.request.GET.get('order', None) | ||||
|  | ||||
|         if order_id: | ||||
|             try: | ||||
|                 order = PurchaseOrder.objects.get(id=order_id) | ||||
|                 initials['order'] = order | ||||
|  | ||||
|             except (PurchaseOrder.DoesNotExist, ValueError): | ||||
|                 pass | ||||
|  | ||||
|         return initials | ||||
|  | ||||
|  | ||||
| class SOLineItemCreate(AjaxCreateView): | ||||
|     """ Ajax view for creating a new SalesOrderLineItem object """ | ||||
|  | ||||
|   | ||||
| @@ -145,9 +145,11 @@ function renderSupplierPart(name, data, parameters, options) { | ||||
|     var html = `<img src='${image}' class='select2-thumbnail'>`; | ||||
|      | ||||
|     html += ` <span><b>${data.supplier_detail.name}</b> - ${data.SKU}</span>`; | ||||
|     html += ` - <i>${data.part_detail.full_name}</i>`; | ||||
|  | ||||
|     html += `<span class='float-right'>{% trans "Supplier Part ID" %}: ${data.pk}</span>`; | ||||
|  | ||||
|  | ||||
|     return html; | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user