diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index d14cfbdfd5..e47396d714 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -558,6 +558,22 @@ {% endif %} $("#part-order").click(function() { + + inventreeGet( + '{% url "api-part-detail" part.pk %}', + {}, + { + success: function(part) { + orderParts( + [part], + {} + ); + } + } + ); + + return; + launchModalForm("{% url 'order-parts' %}", { data: { part: {{ part.id }}, diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js index ed0ddbb4fa..78f6d39ee9 100644 --- a/InvenTree/templates/js/translated/order.js +++ b/InvenTree/templates/js/translated/order.js @@ -33,6 +33,7 @@ loadSalesOrderTable, newPurchaseOrderFromOrderWizard, newSupplierPartFromOrderWizard, + orderParts, removeOrderRowFromOrderWizard, removePurchaseOrderLineItem, */ @@ -450,6 +451,217 @@ function exportOrder(redirect_url, options={}) { }); } + +/* + * Create a new form to order parts based on the list of provided parts. + */ +function orderParts(parts_list, options={}) { + + var parts = []; + + parts_list.forEach(function(part) { + if (part.purchaseable) { + parts.push(part); + } + }); + + if (parts.length == 0) { + showAlertDialog( + '{% trans "Select Parts" %}', + '{% trans "At least one purchaseable part must be selected" %}', + ); + return; + } + + // Render a single part within the dialog + function renderPart(part, opts={}) { + + var pk = part.pk; + + var thumb = thumbnailImage(part.thumbnail || part.image); + + // The "quantity" field should have been provided for each part + var quantity = part.quantity || 0; + + if (quantity < 0) { + quantity = 0; + } + + var quantity_input = constructField( + `items_quantity_${pk}`, + { + type: 'decimal', + min_value: 0, + value: quantity, + title: '{% trans "Quantity to order" %}', + required: true, + }, + { + hideLabels: true, + } + ) + + var supplier_part_prefix = ` + + + + `; + + var supplier_part_input = constructField( + `supplier_part_${pk}`, + { + type: 'related field', + required: true, + prefixRaw: supplier_part_prefix, + }, + { + hideLabels: true, + } + ); + + var purchase_order_prefix = ` + + + + `; + + var purchase_order_input = constructField( + `purchase_order_${pk}`, + { + type: 'related field', + required: true, + prefixRaw: purchase_order_prefix, + }, + { + hideLabels: 'true', + } + ); + + var buttons = `
`; + + buttons += makeIconButton( + 'fa-check-circle icon-green', + 'button-row-complete', + pk, + '{% trans "Add to order" %}', + ); + + if (parts.length > 1) { + buttons += makeIconButton( + 'fa-times icon-red', + 'button-row-remove', + pk, + '{% trans "Remove row" %}', + ); + } + + buttons += `
`; + + var html = ` + + ${thumb} ${part.full_name} + ${supplier_part_input} + ${purchase_order_input} + ${quantity_input} + ${buttons} + + `; + + return html; + } + + var table_entries = ''; + + parts.forEach(function(part) { + table_entries += renderPart(part); + }); + + var html = ''; + + // Add table + html += ` + + + + + + + + + + + + ${table_entries} + +
{% trans "Part" %}{% trans "Supplier Part" %}{% trans "Purchase Order" %}{% trans "Quantity" %}
+ `; + + constructFormBody({}, { + preFormContent: html, + title: '{% trans "Order Parts" %}', + hideSubmitButton: true, + afterRender: function(fields, opts) { + // TODO + parts.forEach(function(part) { + // Configure the "supplier part" field + initializeRelatedField({ + name: `supplier_part_${part.pk}`, + model: 'supplierpart', + api_url: '{% url "api-supplier-part-list" %}', + required: true, + type: 'related field', + auto_fill: true, + filters: { + part: part.pk, + supplier_detail: true, + part_detail: false, + }, + noResults: function(query) { + return '{% trans "No matching supplier parts" %}'; + } + }, null, opts); + + // Configure the "purchase order" field + initializeRelatedField({ + name: `purchase_order_${part.pk}`, + model: 'purchaseorder', + api_url: '{% url "api-po-list" %}', + required: true, + type: 'related field', + auto_fill: false, + filters: { + status: {{ PurchaseOrderStatus.PENDING }}, + }, + adjustFilters: function(query, opts) { + + // Whenever we open the drop-down to select an order, + // ensure we are only displaying orders which match the selected supplier part + var supplier_part_pk = getFormFieldValue(`supplier_part_${part.pk}`, opts); + + inventreeGet( + `/api/company/part/${supplier_part_pk}/`, + {}, + { + async: false, + success: function(data) { + query.supplier = data.supplier; + } + } + ); + + return query; + }, + noResults: function(query) { + return '{% trans "No matching purchase orders" %}'; + } + }, null, opts); + + }); + } + }); + +} + function newPurchaseOrderFromOrderWizard(e) { /* Create a new purchase order directly from an order form. * Launches a secondary modal and (if successful),