diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html
index a7cceb0d8a..7743e6c630 100644
--- a/InvenTree/order/templates/order/purchase_order_detail.html
+++ b/InvenTree/order/templates/order/purchase_order_detail.html
@@ -259,19 +259,21 @@ $("#new-po-extra-line").click(function() {
});
});
-loadPurchaseOrderExtraLineTable(
- '#po-extra-lines-table',
- {
- order: {{ order.pk }},
- status: {{ order.status }},
- {% if order.is_pending %}
- pending: true,
- {% endif %}
- {% if roles.purchase_order.change %}
- allow_edit: true,
- {% endif %}
- }
-);
+loadExtraLineTable({
+ table: '#po-extra-lines-table',
+ order: {{ order.pk }},
+ url: '{% url "api-po-extra-line-list" %}',
+ name: 'purchaseorderextraline',
+ filtertarget: '#filter-list-purchase-order-extra-lines',
+ {% settings_value "PURCHASEORDER_EDIT_COMPLETED_ORDERS" as allow_edit %}
+ {% if order.is_pending or allow_edit %}
+ allow_edit: {% js_bool roles.purchase_order.change %},
+ allow_delete: {% js_bool roles.purchase_order.delete %},
+ {% else %}
+ allow_edit: false,
+ allow_delete: false,
+ {% endif %}
+});
loadOrderTotal(
'#poTotalPrice',
diff --git a/InvenTree/order/templates/order/return_order_detail.html b/InvenTree/order/templates/order/return_order_detail.html
index 8cff9bbf9a..54107d6cf2 100644
--- a/InvenTree/order/templates/order/return_order_detail.html
+++ b/InvenTree/order/templates/order/return_order_detail.html
@@ -13,11 +13,42 @@
-
{% trans "Order Details" %}
- {% include "spacer.html" %}
+
+
{% trans "Line Items" %}
+ {% include "spacer.html" %}
+
+
+
+
+
{% trans "Extra Lines" %}
+ {% include "spacer.html" %}
+
+ {% if roles.return_order.change %}
+
+ {% endif %}
+
+
+
+
+
+
@@ -59,7 +90,20 @@
// Callback function when the 'details' panel is loaded
onPanelLoad('order-details', function() {
- // TODO
+
+ loadExtraLineTable({
+ order: {{ order.pk }},
+ url: '{% url "api-return-order-extra-line-list" %}',
+ table: "#return-order-extra-lines-table",
+ name: 'returnorderextralines',
+ filtertarget: '#filter-list-return-order-extra-lines',
+ allow_edit: {% js_bool roles.return_order.change %},
+ allow_delete: {% js_bool roles.return_order.delete %},
+ });
+
+ $('#new-return-order-extra-line').click(function() {
+ // TODO: Create new return order extra line item
+ });
});
// Callback function when the 'notes' panel is loaded
diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html
index 269a1f1397..864c112c3f 100644
--- a/InvenTree/order/templates/order/sales_order_detail.html
+++ b/InvenTree/order/templates/order/sales_order_detail.html
@@ -289,15 +289,21 @@
});
});
- loadSalesOrderExtraLineTable(
- '#so-extra-lines-table',
- {
- order: {{ order.pk }},
- status: {{ order.status }},
- {% if roles.sales_order.change %}allow_edit: true,{% endif %}
- {% if order.is_pending %}pending: true,{% endif %}
- }
- );
+ loadExtraLineTable({
+ order: {{ order.pk }},
+ table: '#so-extra-lines-table',
+ url: '{% url "api-so-extra-line-list" %}',
+ name: 'salesorderextraline',
+ filtertarget: '#filter-list-sales-order-extra-lines',
+ {% settings_value "SALESORDER_EDIT_COMPLETED_ORDERS" as allow_edit %}
+ {% if order.is_pending or allow_edit %}
+ allow_edit: {% js_bool roles.sales_order.change %},
+ allow_delete: {% js_bool roles.sales_order.delete %},
+ {% else %}
+ allow_edit: false,
+ allow_delete: false,
+ {% endif %}
+ });
loadOrderTotal(
'#soTotalPrice',
diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js
index b1fc49639d..d255f45c25 100644
--- a/InvenTree/templates/js/translated/order.js
+++ b/InvenTree/templates/js/translated/order.js
@@ -14,6 +14,7 @@
removeOrderRowFromOrderWizard,
removePurchaseOrderLineItem,
loadOrderTotal,
+ loadExtraLineTable,
extraLineFields,
reloadTotal,
*/
@@ -122,3 +123,197 @@ function reloadTotal() {
}
);
};
+
+
+/*
+ * Load a table displaying "extra" line items for a given order.
+ * Used for all external order types (e.g. PurchaseOrder / SalesOrder / ReturnOrder)
+ *
+ * options:
+ * - table: The DOM ID of the table element
+ * - order: The ID of the related order (required)
+ * - name: The unique 'name' for this table
+ * - url: The API URL for the extra line item model (required)
+ * - filtertarget: The DOM ID for the filter list element
+ */
+function loadExtraLineTable(options={}) {
+
+ const table = options.table;
+
+ options.params = options.params || {};
+
+ // Filtering
+ options.params.order = options.order;
+
+ var filters = {};
+
+ if (options.name) {
+ filters = loadTableFilters(options.name);
+ }
+
+ for (var key in options.params) {
+ filters[key] = options.params[key];
+ }
+
+ setupFilterList(
+ options.name,
+ $(table),
+ options.filtertarget,
+ {
+ download: true
+ }
+ );
+
+ // Helper function to reload table
+ function reloadExtraLineTable() {
+ $(table).bootstrapTable('refresh');
+ reloadTotal();
+ }
+
+ // Configure callback functions once the table is loaded
+ function setupCallbacks() {
+
+ if (options.allow_edit) {
+
+ // Callback to duplicate line item
+ $(table).find('.button-duplicate').click(function() {
+ var pk = $(this).attr('pk');
+
+ inventreeGet(`${options.url}${pk}/`, {}, {
+ success: function(data) {
+
+ var fields = extraLineFields();
+
+ constructForm(options.url, {
+ method: 'POST',
+ fields: fields,
+ data: data,
+ title: '{% trans "Duplicate Line" %}',
+ onSuccess: reloadExtraLineTable,
+ });
+ }
+ });
+ });
+
+ // Callback to edit line item
+ // Callback for editing lines
+ $(table).find('.button-edit').click(function() {
+ var pk = $(this).attr('pk');
+
+ constructForm(`${options.url}${pk}/`, {
+ fields: extraLineFields(),
+ title: '{% trans "Edit Line" %}',
+ onSuccess: reloadExtraLineTable,
+ });
+ });
+ }
+
+ if (options.allow_delete) {
+ // Callback for deleting lines
+ $(table).find('.button-delete').click(function() {
+ var pk = $(this).attr('pk');
+
+ constructForm(`${options.url}${pk}/`, {
+ method: 'DELETE',
+ title: '{% trans "Delete Line" %}',
+ onSuccess: reloadExtraLineTable,
+ });
+ });
+ }
+ }
+
+ $(table).inventreeTable({
+ url: options.url,
+ name: options.name,
+ sidePagination: 'server',
+ onPostBody: setupCallbacks,
+ formatNoMatches: function() {
+ return '{% trans "No line items found" %}';
+ },
+ queryParams: filters,
+ original: options.params,
+ showFooter: true,
+ uniqueId: 'pk',
+ columns: [
+ {
+ sortable: true,
+ field: 'reference',
+ title: '{% trans "Reference" %}',
+ switchable: false,
+ },
+ {
+ sortable: true,
+ switchable: false,
+ field: 'quantity',
+ title: '{% trans "Quantity" %}',
+ footerFormatter: function(data) {
+ return data.map(function(row) {
+ return +row['quantity'];
+ }).reduce(function(sum, i) {
+ return sum + i;
+ }, 0);
+ },
+ },
+ {
+ sortable: true,
+ field: 'price',
+ title: '{% trans "Unit Price" %}',
+ formatter: function(value, row) {
+ return formatCurrency(row.price, {
+ currency: row.price_currency,
+ });
+ }
+ },
+ {
+ field: 'total_price',
+ sortable: true,
+ switchable: true,
+ title: '{% trans "Total Price" %}',
+ formatter: function(value, row) {
+ return formatCurrency(row.price * row.quantity, {
+ currency: row.price_currency,
+ });
+ },
+ footerFormatter: function(data) {
+ return calculateTotalPrice(
+ data,
+ function(row) {
+ return row.price ? row.price * row.quantity : null;
+ },
+ function(row) {
+ return row.price_currency;
+ }
+ );
+ }
+ },
+ {
+ field: 'notes',
+ title: '{% trans "Notes" %}',
+ },
+ {
+ field: 'buttons',
+ switchable: false,
+ formatter: function(value, row, index, field) {
+
+ var html = ``;
+
+ if (options.allow_edit || options.allow_delete) {
+ var pk = row.pk;
+
+ if (options.allow_edit) {
+ html += makeIconButton('fa-clone', 'button-duplicate', pk, '{% trans "Duplicate line" %}');
+ html += makeIconButton('fa-edit icon-blue', 'button-edit', pk, '{% trans "Edit line" %}');
+ }
+
+ if (options.allow_delete) {
+ html += makeIconButton('fa-trash-alt icon-red', 'button-delete', pk, '{% trans "Delete line" %}', );
+ }
+ }
+
+ html += `
`;
+ return html;
+ }
+ },
+ ]
+ })
+}
diff --git a/InvenTree/templates/js/translated/purchase_order.js b/InvenTree/templates/js/translated/purchase_order.js
index 85df6c4a76..f3586cfb96 100644
--- a/InvenTree/templates/js/translated/purchase_order.js
+++ b/InvenTree/templates/js/translated/purchase_order.js
@@ -28,7 +28,6 @@
editPurchaseOrderLineItem,
issuePurchaseOrder,
loadPurchaseOrderLineItemTable,
- loadPurchaseOrderExtraLineTable
loadPurchaseOrderTable,
newPurchaseOrderFromOrderWizard,
newSupplierPartFromOrderWizard,
@@ -2085,198 +2084,3 @@ function loadPurchaseOrderLineItemTable(table, options={}) {
);
}
-
-
-/**
- * Load a table displaying lines for a particular PurchaseOrder
- *
- * @param {String} table : HTML ID tag e.g. '#table'
- * @param {Object} options : object which contains:
- * - order {integer} : pk of the PurchaseOrder
- * - status: {integer} : status code for the order
- */
-function loadPurchaseOrderExtraLineTable(table, options={}) {
-
- options.table = table;
-
- if (!options.pending && !global_settings.PURCHASEORDER_EDIT_COMPLETED_ORDERS) {
- options.allow_edit = false;
- }
-
- options.params = options.params || {};
-
- if (!options.order) {
- console.error('function called without order ID');
- return;
- }
-
- if (!options.status) {
- console.error('function called without order status');
- return;
- }
-
- options.params.order = options.order;
- options.params.part_detail = true;
- options.params.allocations = true;
-
- var filters = loadTableFilters('purchaseorderextraline');
-
- for (var key in options.params) {
- filters[key] = options.params[key];
- }
-
- options.url = options.url || '{% url "api-po-extra-line-list" %}';
-
- var filter_target = options.filter_target || '#filter-list-purchase-order-extra-lines';
-
- setupFilterList('purchaseorderextraline', $(table), filter_target, {download: true});
-
- // Table columns to display
- var columns = [
- {
- sortable: true,
- field: 'reference',
- title: '{% trans "Reference" %}',
- switchable: true,
- },
- {
- sortable: true,
- field: 'quantity',
- title: '{% trans "Quantity" %}',
- footerFormatter: function(data) {
- return data.map(function(row) {
- return +row['quantity'];
- }).reduce(function(sum, i) {
- return sum + i;
- }, 0);
- },
- switchable: false,
- },
- {
- sortable: true,
- field: 'price',
- title: '{% trans "Unit Price" %}',
- formatter: function(value, row) {
- return formatCurrency(row.price, {
- currency: row.price_currency,
- });
- }
- },
- {
- field: 'total_price',
- sortable: true,
- title: '{% trans "Total Price" %}',
- formatter: function(value, row) {
- return formatCurrency(row.price * row.quantity, {
- currency: row.price_currency,
- });
- },
- footerFormatter: function(data) {
- return calculateTotalPrice(
- data,
- function(row) {
- return row.price ? row.price * row.quantity : null;
- },
- function(row) {
- return row.price_currency;
- }
- );
- }
- }
- ];
-
- columns.push({
- field: 'notes',
- title: '{% trans "Notes" %}',
- });
-
- columns.push({
- field: 'buttons',
- switchable: false,
- formatter: function(value, row, index, field) {
-
- var html = ``;
-
- var pk = row.pk;
-
- if (options.allow_edit) {
- html += makeIconButton('fa-clone', 'button-duplicate', pk, '{% trans "Duplicate line" %}');
- html += makeIconButton('fa-edit icon-blue', 'button-edit', pk, '{% trans "Edit line" %}');
- html += makeIconButton('fa-trash-alt icon-red', 'button-delete', pk, '{% trans "Delete line" %}', );
- }
-
- html += `
`;
-
- return html;
- }
- });
-
- function reloadTable() {
- $(table).bootstrapTable('refresh');
- reloadTotal();
- }
-
- // Configure callback functions once the table is loaded
- function setupCallbacks() {
-
- // Callback for duplicating lines
- $(table).find('.button-duplicate').click(function() {
- var pk = $(this).attr('pk');
-
- inventreeGet(`/api/order/po-extra-line/${pk}/`, {}, {
- success: function(data) {
-
- var fields = extraLineFields();
-
- constructForm('{% url "api-po-extra-line-list" %}', {
- method: 'POST',
- fields: fields,
- data: data,
- title: '{% trans "Duplicate Line" %}',
- onSuccess: function(response) {
- $(table).bootstrapTable('refresh');
- }
- });
- }
- });
- });
-
- // Callback for editing lines
- $(table).find('.button-edit').click(function() {
- var pk = $(this).attr('pk');
-
- constructForm(`/api/order/po-extra-line/${pk}/`, {
- fields: extraLineFields(),
- title: '{% trans "Edit Line" %}',
- onSuccess: reloadTable,
- });
- });
-
- // Callback for deleting lines
- $(table).find('.button-delete').click(function() {
- var pk = $(this).attr('pk');
-
- constructForm(`/api/order/po-extra-line/${pk}/`, {
- method: 'DELETE',
- title: '{% trans "Delete Line" %}',
- onSuccess: reloadTable,
- });
- });
- }
-
- $(table).inventreeTable({
- onPostBody: setupCallbacks,
- name: 'purchaseorderextraline',
- sidePagination: 'client',
- formatNoMatches: function() {
- return '{% trans "No matching line" %}';
- },
- queryParams: filters,
- original: options.params,
- url: options.url,
- showFooter: true,
- uniqueId: 'pk',
- detailViewByClick: false,
- columns: columns,
- });
-}
diff --git a/InvenTree/templates/js/translated/sales_order.js b/InvenTree/templates/js/translated/sales_order.js
index 27a39fd7a8..8bb9ba9a84 100644
--- a/InvenTree/templates/js/translated/sales_order.js
+++ b/InvenTree/templates/js/translated/sales_order.js
@@ -29,7 +29,6 @@
exportOrder,
loadSalesOrderAllocationTable,
loadSalesOrderLineItemTable,
- loadSalesOrderExtraLineTable
loadSalesOrderShipmentTable,
loadSalesOrderTable,
orderParts,
@@ -2143,196 +2142,3 @@ function loadSalesOrderLineItemTable(table, options={}) {
columns: columns,
});
}
-
-
-/**
- * Load a table displaying lines for a particular SalesOrder
- *
- * @param {String} table : HTML ID tag e.g. '#table'
- * @param {Object} options : object which contains:
- * - order {integer} : pk of the SalesOrder
- * - status: {integer} : status code for the order
- */
-function loadSalesOrderExtraLineTable(table, options={}) {
-
- options.table = table;
-
- if (!options.pending && !global_settings.SALESORDER_EDIT_COMPLETED_ORDERS) {
- options.allow_edit = false;
- }
-
- options.params = options.params || {};
-
- if (!options.order) {
- console.error('function called without order ID');
- return;
- }
-
- if (!options.status) {
- console.error('function called without order status');
- return;
- }
-
- options.params.order = options.order;
- options.params.part_detail = true;
- options.params.allocations = true;
-
- var filters = loadTableFilters('salesorderextraline');
-
- for (var key in options.params) {
- filters[key] = options.params[key];
- }
-
- options.url = options.url || '{% url "api-so-extra-line-list" %}';
-
- var filter_target = options.filter_target || '#filter-list-sales-order-extra-lines';
-
- setupFilterList('salesorderextraline', $(table), filter_target, {download: true});
-
- // Table columns to display
- var columns = [
- {
- sortable: true,
- field: 'reference',
- title: '{% trans "Reference" %}',
- switchable: true,
- },
- {
- sortable: true,
- field: 'quantity',
- title: '{% trans "Quantity" %}',
- footerFormatter: function(data) {
- return data.map(function(row) {
- return +row['quantity'];
- }).reduce(function(sum, i) {
- return sum + i;
- }, 0);
- },
- switchable: false,
- },
- {
- sortable: true,
- field: 'price',
- title: '{% trans "Unit Price" %}',
- formatter: function(value, row) {
- return formatCurrency(row.price, {
- currency: row.price_currency,
- });
- }
- },
- {
- field: 'total_price',
- sortable: true,
- title: '{% trans "Total Price" %}',
- formatter: function(value, row) {
- return formatCurrency(row.price * row.quantity, {
- currency: row.price_currency,
- });
- },
- footerFormatter: function(data) {
- return calculateTotalPrice(
- data,
- function(row) {
- return row.price ? row.price * row.quantity : null;
- },
- function(row) {
- return row.price_currency;
- }
- );
- }
- }
- ];
-
- columns.push({
- field: 'notes',
- title: '{% trans "Notes" %}',
- });
-
- columns.push({
- field: 'buttons',
- switchable: false,
- formatter: function(value, row, index, field) {
-
- var html = ``;
-
- if (options.allow_edit) {
- var pk = row.pk;
- html += makeIconButton('fa-clone', 'button-duplicate', pk, '{% trans "Duplicate line" %}');
- html += makeIconButton('fa-edit icon-blue', 'button-edit', pk, '{% trans "Edit line" %}');
- html += makeIconButton('fa-trash-alt icon-red', 'button-delete', pk, '{% trans "Delete line" %}', );
- }
-
- html += `
`;
- return html;
- }
- });
-
- function reloadTable() {
- $(table).bootstrapTable('refresh');
- reloadTotal();
- }
-
- // Configure callback functions once the table is loaded
- function setupCallbacks() {
-
- // Callback for duplicating lines
- $(table).find('.button-duplicate').click(function() {
- var pk = $(this).attr('pk');
-
- inventreeGet(`/api/order/so-extra-line/${pk}/`, {}, {
- success: function(data) {
-
- var fields = extraLineFields();
-
- constructForm('{% url "api-so-extra-line-list" %}', {
- method: 'POST',
- fields: fields,
- data: data,
- title: '{% trans "Duplicate Line" %}',
- onSuccess: function(response) {
- $(table).bootstrapTable('refresh');
- }
- });
- }
- });
- });
-
- // Callback for editing lines
- $(table).find('.button-edit').click(function() {
- var pk = $(this).attr('pk');
-
- constructForm(`/api/order/so-extra-line/${pk}/`, {
- fields: extraLineFields(),
- title: '{% trans "Edit Line" %}',
- onSuccess: reloadTable,
- });
- });
-
- // Callback for deleting lines
- $(table).find('.button-delete').click(function() {
- var pk = $(this).attr('pk');
-
- constructForm(`/api/order/so-extra-line/${pk}/`, {
- method: 'DELETE',
- title: '{% trans "Delete Line" %}',
- onSuccess: reloadTable,
- });
- });
- }
-
- $(table).inventreeTable({
- onPostBody: setupCallbacks,
- name: 'salesorderextraline',
- sidePagination: 'client',
- formatNoMatches: function() {
- return '{% trans "No matching lines" %}';
- },
- queryParams: filters,
- original: options.params,
- url: options.url,
- showFooter: true,
- uniqueId: 'pk',
- detailViewByClick: false,
- columns: columns,
- });
-}