diff --git a/InvenTree/build/templates/build/detail.html b/InvenTree/build/templates/build/detail.html
index 3b612bcfed..f99a7efb95 100644
--- a/InvenTree/build/templates/build/detail.html
+++ b/InvenTree/build/templates/build/detail.html
@@ -355,8 +355,9 @@ onPanelLoad('completed', function() {
onPanelLoad('children', function() {
loadBuildTable($('#sub-build-table'), {
- url: '{% url "api-build-list" %}',
+ locale: '{{ request.LANGUAGE_CODE }}',
filterTarget: "#filter-list-sub-build",
+ parentBuild: {{ build.pk }},
params: {
ancestor: {{ build.pk }},
}
diff --git a/InvenTree/build/templates/build/index.html b/InvenTree/build/templates/build/index.html
index a70d5d0d95..4d1476f959 100644
--- a/InvenTree/build/templates/build/index.html
+++ b/InvenTree/build/templates/build/index.html
@@ -40,13 +40,6 @@
{% endif %}
-
-
-
{% include "filter_list.html" with id="build" %}
@@ -54,133 +47,19 @@
-
-
{% endblock %}
-{% block js_load %}
-{{ block.super }}
-
-
-{% endblock %}
-
{% block js_ready %}
{{ block.super }}
-$('#build-order-calendar').hide();
-$('#view-list').hide();
-
-$('#view-calendar').click(function() {
- // Hide the list view, show the calendar view
- $("#build-table").hide();
- $("#view-calendar").hide();
- $(".fixed-table-pagination").hide();
- $(".columns-right").hide();
- $(".search").hide();
-
- $("#build-order-calendar").show();
- $("#view-list").show();
-
- calendar.render();
-});
-
-$("#view-list").click(function() {
- // Hide the calendar view, show the list view
- $("#build-order-calendar").hide();
- $("#view-list").hide();
-
- $(".fixed-table-pagination").show();
- $(".columns-right").show();
- $(".search").show();
- $("#build-table").show();
- $("#view-calendar").show();
-});
-
-$("#collapse-item-active").collapse().show();
-
$("#new-build").click(function() {
newBuildOrder();
});
loadBuildTable($("#build-table"), {
- url: "{% url 'api-build-list' %}",
+ locale: '{{ request.LANGUAGE_CODE }}',
});
{% if report_enabled %}
diff --git a/InvenTree/order/templates/order/purchase_orders.html b/InvenTree/order/templates/order/purchase_orders.html
index e66863cbb5..7f91f01600 100644
--- a/InvenTree/order/templates/order/purchase_orders.html
+++ b/InvenTree/order/templates/order/purchase_orders.html
@@ -31,12 +31,6 @@
{% endif %}
-
-
{% include "filter_list.html" with id="purchaseorder" %}
@@ -54,122 +48,11 @@
{% block js_load %}
{{ block.super }}
-
-
{% endblock %}
{% block js_ready %}
{{ block.super }}
-$('#purchase-order-calendar').hide();
-$('#view-list').hide();
-
-$('#view-calendar').click(function() {
- // Hide the list view, show the calendar view
- $("#purchase-order-table").hide();
- $("#view-calendar").hide();
- $(".fixed-table-pagination").hide();
- $(".columns-right").hide();
- $(".search").hide();
- $('#filter-list-salesorder').hide();
-
- $("#purchase-order-calendar").show();
- $("#view-list").show();
-
- calendar.render();
-});
-
-$("#view-list").click(function() {
- // Hide the calendar view, show the list view
- $("#purchase-order-calendar").hide();
- $("#view-list").hide();
-
- $(".fixed-table-pagination").show();
- $(".columns-right").show();
- $(".search").show();
- $("#purchase-order-table").show();
- $('#filter-list-salesorder').show();
- $("#view-calendar").show();
-});
-
{% if report_enabled %}
$("#order-print").click(function() {
var rows = getTableData('#purchase-order-table');
diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html
index 48a62114dc..89346c8118 100644
--- a/InvenTree/order/templates/order/sales_order_detail.html
+++ b/InvenTree/order/templates/order/sales_order_detail.html
@@ -231,7 +231,7 @@
});
loadBuildTable($("#builds-table"), {
- url: "{% url 'api-build-list' %}",
+ locale: '{{ request.LANGUAGE_CODE }}',
params: {
sales_order: {{ order.id }},
},
diff --git a/InvenTree/order/templates/order/sales_orders.html b/InvenTree/order/templates/order/sales_orders.html
index 23580567b9..9b85df95b7 100644
--- a/InvenTree/order/templates/order/sales_orders.html
+++ b/InvenTree/order/templates/order/sales_orders.html
@@ -34,12 +34,6 @@
{% endif %}
-
-
{% include "filter_list.html" with id="salesorder" %}
@@ -53,123 +47,9 @@
{% endblock %}
-{% block js_load %}
-{{ block.super }}
-
-
-{% endblock %}
-
{% block js_ready %}
{{ block.super }}
-$("#sales-order-calendar").hide();
-$("#view-list").hide();
-
-$('#view-calendar').click(function() {
- // Hide the list view, show the calendar view
- $("#sales-order-table").hide();
- $("#view-calendar").hide();
- $(".fixed-table-pagination").hide();
- $(".columns-right").hide();
- $(".search").hide();
- $('#filter-list-salesorder').hide();
-
- $("#sales-order-calendar").show();
- $("#view-list").show();
-
- calendar.render();
-});
-
-$("#view-list").click(function() {
- // Hide the calendar view, show the list view
- $("#sales-order-calendar").hide();
- $("#view-list").hide();
-
- $(".fixed-table-pagination").show();
- $(".columns-right").show();
- $(".search").show();
- $("#sales-order-table").show();
- $('#filter-list-salesorder').show();
- $("#view-calendar").show();
-});
-
loadSalesOrderTable("#sales-order-table", {
url: "{% url 'api-so-list' %}",
});
diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html
index 4f67a9bbc9..0fbe7828dc 100644
--- a/InvenTree/part/templates/part/detail.html
+++ b/InvenTree/part/templates/part/detail.html
@@ -514,7 +514,7 @@
});
loadBuildTable($("#build-table"), {
- url: "{% url 'api-build-list' %}",
+ locale: '{{ request.LANGUAGE_CODE }}',
params: {
part: {{ part.id }},
}
diff --git a/InvenTree/templates/InvenTree/index.html b/InvenTree/templates/InvenTree/index.html
index 44bc70fc37..836da5f870 100644
--- a/InvenTree/templates/InvenTree/index.html
+++ b/InvenTree/templates/InvenTree/index.html
@@ -223,7 +223,7 @@ addHeaderTitle('{% trans "Build Orders" %}');
{% if setting_build_pending %}
addHeaderAction('build-pending', '{% trans "Build Orders In Progress" %}', 'fa-cogs');
loadBuildTable("#table-build-pending", {
- url: "{% url 'api-build-list' %}",
+ locale: '{{ request.LANGUAGE_CODE }}',
params: {
active: true,
},
@@ -234,7 +234,7 @@ loadBuildTable("#table-build-pending", {
{% if setting_build_overdue %}
addHeaderAction('build-overdue', '{% trans "Overdue Build Orders" %}', 'fa-calendar-times');
loadBuildTable("#table-build-overdue", {
- url: "{% url 'api-build-list' %}",
+ locale: '{{ request.LANGUAGE_CODE }}',
params: {
overdue: true,
},
diff --git a/InvenTree/templates/InvenTree/search.html b/InvenTree/templates/InvenTree/search.html
index 5ba618137e..eb22cc0889 100644
--- a/InvenTree/templates/InvenTree/search.html
+++ b/InvenTree/templates/InvenTree/search.html
@@ -139,6 +139,7 @@
addItem('build-order', '{% trans "Build Orders" %}', 'fa-tools');
loadBuildTable('#table-build-order', {
+ locale: '{{ request.LANGUAGE_CODE }}',
params: {
original_search: '{{ query }}',
}
diff --git a/InvenTree/templates/js/translated/build.js b/InvenTree/templates/js/translated/build.js
index 8c8152becd..7d7cb59240 100644
--- a/InvenTree/templates/js/translated/build.js
+++ b/InvenTree/templates/js/translated/build.js
@@ -2320,6 +2320,9 @@ function autoAllocateStockToBuild(build_id, bom_items=[], options={}) {
*/
function loadBuildTable(table, options) {
+ // Ensure the table starts in a known state
+ $(table).bootstrapTable('destroy');
+
var params = options.params || {};
var filters = {};
@@ -2334,23 +2337,105 @@ function loadBuildTable(table, options) {
filters[key] = params[key];
}
- options.url = options.url || '{% url "api-build-list" %}';
-
var filterTarget = options.filterTarget || null;
setupFilterList('build', table, filterTarget, {download: true});
+ // Which display mode to use for the build table?
+ var display_mode = inventreeLoad('build-table-display-mode', 'list');
+ var tree_enable = display_mode == 'tree';
+
+ var loaded_calendar = false;
+
+ // Function for rendering BuildOrder calendar display
+ function buildEvents(calendar) {
+ var start = startDate(calendar);
+ var end = endDate(calendar);
+
+ clearEvents(calendar);
+
+ // Extract current filters from table
+ var table_options = $(table).bootstrapTable('getOptions');
+ var filters = table_options.query_params || {};
+
+ filters.min_date = start;
+ filters.max_date = end;
+ filters.part_detail = true;
+
+ // Request build orders from the server within specified date range
+ inventreeGet(
+ '{% url "api-build-list" %}',
+ filters,
+ {
+ success: function(response) {
+ var prefix = global_settings.BUILDORDER_REFERENCE_PREFIX;
+
+ for (var idx = 0; idx < response.length; idx++) {
+
+ var order = response[idx];
+
+ var date = order.creation_date;
+
+ if (order.completion_date) {
+ date = order.completion_date;
+ } else if (order.target_date) {
+ date = order.target_date;
+ }
+
+ var title = `${prefix}${order.reference}`;
+
+ var color = '#4c68f5';
+
+ if (order.completed) {
+ color = '#25c234';
+ } else if (order.overdue) {
+ color = '#c22525';
+ }
+
+ var event = {
+ title: title,
+ start: date,
+ end: date,
+ url: `/build/${order.pk}/`,
+ backgroundColor: color,
+ };
+
+ calendar.addEvent(event);
+ }
+ }
+ }
+ );
+ }
+
$(table).inventreeTable({
method: 'get',
formatNoMatches: function() {
return '{% trans "No builds matching query" %}';
},
- url: options.url,
+ url: '{% url "api-build-list" %}',
queryParams: filters,
groupBy: false,
sidePagination: 'server',
name: 'builds',
original: params,
+ treeEnable: tree_enable,
+ uniqueId: 'pk',
+ rootParentId: options.parentBuild || null,
+ idField: 'pk',
+ parentIdField: 'parent',
+ treeShowField: tree_enable ? 'reference' : null,
+ showColumns: display_mode == 'list' || display_mode == 'tree',
+ showCustomView: display_mode == 'calendar',
+ showCustomViewButton: false,
+ disablePagination: display_mode == 'calendar',
+ search: display_mode != 'calendar',
+ buttons: constructOrderTableButtons({
+ prefix: 'build',
+ callback: function() {
+ // Force complete reload of the table
+ loadBuildTable(table, options);
+ }
+ }),
columns: [
{
field: 'pk',
@@ -2477,6 +2562,43 @@ function loadBuildTable(table, options) {
}
},
],
+ customView: function(data) {
+ return ``;
+ },
+ onRefresh: function() {
+ loadBuildTable(table, options);
+ },
+ onLoadSuccess: function() {
+
+ if (tree_enable) {
+ $(table).treegrid({
+ treeColumn: 1,
+ });
+
+ table.treegrid('expandAll');
+ } else if (display_mode == 'calendar') {
+
+ if (!loaded_calendar) {
+ loaded_calendar = true;
+
+ var el = document.getElementById('build-order-calendar');
+
+ calendar = new FullCalendar.Calendar(el, {
+ initialView: 'dayGridMonth',
+ nowIndicator: true,
+ aspectRatio: 2.5,
+ locale: options.locale,
+ datesSet: function() {
+ buildEvents(calendar);
+ }
+ });
+
+ calendar.render();
+ } else {
+ calendar.render();
+ }
+ }
+ }
});
linkButtonsToSelection(
diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js
index 03e967deee..4b39f11ee8 100644
--- a/InvenTree/templates/js/translated/order.js
+++ b/InvenTree/templates/js/translated/order.js
@@ -1504,7 +1504,8 @@ function removePurchaseOrderLineItem(e) {
* Load a table displaying list of purchase orders
*/
function loadPurchaseOrderTable(table, options) {
- /* Create a purchase-order table */
+ // Ensure the table starts in a known state
+ $(table).bootstrapTable('destroy');
options.params = options.params || {};
@@ -1520,6 +1521,71 @@ function loadPurchaseOrderTable(table, options) {
setupFilterList('purchaseorder', $(table), target, {download: true});
+ var display_mode = inventreeLoad('purchaseorder-table-display-mode', 'list');
+
+ // Function for rendering PurchaseOrder calendar display
+ function buildEvents(calendar) {
+
+ var start = startDate(calendar);
+ var end = endDate(calendar);
+
+ clearEvents(calendar);
+
+ // Extract current filters from table
+ var table_options = $(table).bootstrapTable('getOptions');
+ var filters = table_options.query_params || {};
+
+ filters.supplier_detail = true;
+ filters.min_date = start;
+ filters.max_date = end;
+
+ // Request purchase orders from the server within specified date range
+ inventreeGet(
+ '{% url "api-po-list" %}',
+ filters,
+ {
+ success: function(response) {
+ var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
+
+ for (var idx = 0; idx < response.length; idx++) {
+
+ var order = response[idx];
+
+ var date = order.creation_date;
+
+ if (order.complete_date) {
+ date = order.complete_date;
+ } else if (order.target_date) {
+ date = order.target_date;
+ }
+
+ var title = `${prefix}${order.reference} - ${order.supplier_detail.name}`;
+
+ var color = '#4c68f5';
+
+ if (order.complete_date) {
+ color = '#25c235';
+ } else if (order.overdue) {
+ color = '#c22525';
+ } else {
+ color = '#4c68f5';
+ }
+
+ var event = {
+ title: title,
+ start: date,
+ end: date,
+ url: `/order/purchase-order/${order.pk}/`,
+ backgroundColor: color,
+ };
+
+ calendar.addEvent(event);
+ }
+ }
+ }
+ );
+ }
+
$(table).inventreeTable({
url: '{% url "api-po-list" %}',
queryParams: filters,
@@ -1527,9 +1593,22 @@ function loadPurchaseOrderTable(table, options) {
groupBy: false,
sidePagination: 'server',
original: options.params,
+ showColumns: display_mode == 'list',
+ disablePagination: display_mode == 'calendar',
+ showCustomViewButton: false,
+ showCustomView: display_mode == 'calendar',
+ search: display_mode != 'calendar',
formatNoMatches: function() {
return '{% trans "No purchase orders found" %}';
},
+ buttons: constructOrderTableButtons({
+ prefix: 'purchaseorder',
+ disableTreeView: true,
+ callback: function() {
+ // Reload the entire table
+ loadPurchaseOrderTable(table, options);
+ }
+ }),
columns: [
{
title: '',
@@ -1629,6 +1708,30 @@ function loadPurchaseOrderTable(table, options) {
}
},
],
+ customView: function(data) {
+ return ``;
+ },
+ onRefresh: function() {
+ loadPurchaseOrderTable(table, options);
+ },
+ onLoadSuccess: function() {
+
+ if (display_mode == 'calendar') {
+ var el = document.getElementById('purchase-order-calendar');
+
+ calendar = new FullCalendar.Calendar(el, {
+ initialView: 'dayGridMonth',
+ nowIndicator: true,
+ aspectRatio: 2.5,
+ locale: options.locale,
+ datesSet: function() {
+ buildEvents(calendar);
+ }
+ });
+
+ calendar.render();
+ }
+ }
});
}
@@ -2191,6 +2294,9 @@ function loadPurchaseOrderExtraLineTable(table, options={}) {
*/
function loadSalesOrderTable(table, options) {
+ // Ensure the table starts in a known state
+ $(table).bootstrapTable('destroy');
+
options.params = options.params || {};
options.params['customer_detail'] = true;
@@ -2206,6 +2312,70 @@ function loadSalesOrderTable(table, options) {
setupFilterList('salesorder', $(table), target, {download: true});
+ var display_mode = inventreeLoad('salesorder-table-display-mode', 'list');
+
+ function buildEvents(calendar) {
+
+ var start = startDate(calendar);
+ var end = endDate(calendar);
+
+ clearEvents(calendar);
+
+ // Extract current filters from table
+ var table_options = $(table).bootstrapTable('getOptions');
+ var filters = table_options.query_params || {};
+
+ filters.customer_detail = true;
+ filters.min_date = start;
+ filters.max_date = end;
+
+ // Request orders from the server within specified date range
+ inventreeGet(
+ '{% url "api-so-list" %}',
+ filters,
+ {
+ success: function(response) {
+
+ var prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
+
+ for (var idx = 0; idx < response.length; idx++) {
+ var order = response[idx];
+
+ var date = order.creation_date;
+
+ if (order.shipment_date) {
+ date = order.shipment_date;
+ } else if (order.target_date) {
+ date = order.target_date;
+ }
+
+ var title = `${prefix}${order.reference} - ${order.customer_detail.name}`;
+
+ // Default color is blue
+ var color = '#4c68f5';
+
+ // Overdue orders are red
+ if (order.overdue) {
+ color = '#c22525';
+ } else if (order.status == {{ SalesOrderStatus.SHIPPED }}) {
+ color = '#25c235';
+ }
+
+ var event = {
+ title: title,
+ start: date,
+ end: date,
+ url: `/order/sales-order/${order.pk}/`,
+ backgroundColor: color,
+ };
+
+ calendar.addEvent(event);
+ }
+ }
+ }
+ );
+ }
+
$(table).inventreeTable({
url: options.url,
queryParams: filters,
@@ -2213,9 +2383,46 @@ function loadSalesOrderTable(table, options) {
groupBy: false,
sidePagination: 'server',
original: options.params,
+ showColums: display_mode != 'calendar',
+ search: display_mode != 'calendar',
+ showCustomViewButton: false,
+ showCustomView: display_mode == 'calendar',
+ disablePagination: display_mode == 'calendar',
formatNoMatches: function() {
return '{% trans "No sales orders found" %}';
},
+ buttons: constructOrderTableButtons({
+ prefix: 'salesorder',
+ disableTreeView: true,
+ callback: function() {
+ // Reload the entire table
+ loadSalesOrderTable(table, options);
+ },
+ }),
+ customView: function(data) {
+ return ``;
+ },
+ onRefresh: function() {
+ loadPurchaseOrderTable(table, options);
+ },
+ onLoadSuccess: function() {
+
+ if (display_mode == 'calendar') {
+ var el = document.getElementById('purchase-order-calendar');
+
+ calendar = new FullCalendar.Calendar(el, {
+ initialView: 'dayGridMonth',
+ nowIndicator: true,
+ aspectRatio: 2.5,
+ locale: options.locale,
+ datesSet: function() {
+ buildEvents(calendar);
+ }
+ });
+
+ calendar.render();
+ }
+ },
columns: [
{
title: '',
diff --git a/InvenTree/templates/js/translated/tables.js b/InvenTree/templates/js/translated/tables.js
index 8f25372f55..7525620bb3 100644
--- a/InvenTree/templates/js/translated/tables.js
+++ b/InvenTree/templates/js/translated/tables.js
@@ -12,6 +12,7 @@
reloadtable,
renderLink,
reloadTableFilters,
+ constructOrderTableButtons,
*/
/**
@@ -24,7 +25,80 @@ function reloadtable(table) {
/*
- * Return the 'selected' data rows from a bootstrap table.
+ * Construct a set of extra buttons to display against a list of orders,
+ * allowing the orders to be displayed in various 'view' modes:
+ *
+ * - Calendar view
+ * - List view
+ * - Tree view
+ *
+ * Options:
+ * - callback: Callback function to be called when one of the buttons is pressed
+ * - prefix: The prefix to use when saving display data to user session
+ * - display: Which button to set as 'active' by default
+ *
+ */
+function constructOrderTableButtons(options={}) {
+
+ var display_mode = options.display;
+
+ var key = `${options.prefix || order}-table-display-mode`;
+
+ // If display mode is not provided, look up from session
+ if (!display_mode) {
+ display_mode = inventreeLoad(key, 'list');
+ }
+
+ var idx = 0;
+ var buttons = [];
+
+ function buttonCallback(view_mode) {
+ inventreeSave(key, view_mode);
+
+ if (options.callback) {
+ options.callback(view_mode);
+ }
+ }
+
+ var class_calendar = display_mode == 'calendar' ? 'btn-secondary' : 'btn-outline-secondary';
+ var class_list = display_mode == 'list' ? 'btn-secondary' : 'btn-outline-secondary';
+ var class_tree = display_mode == 'tree' ? 'btn-secondary' : 'btn-outline-secondary';
+
+ // Calendar view button
+ if (!options.disableCalendarView) {
+ buttons.push({
+ html: ``,
+ event: function() {
+ buttonCallback('calendar');
+ }
+ });
+ }
+
+ // List view button
+ if (!options.disableListView) {
+ buttons.push({
+ html: ``,
+ event: function() {
+ buttonCallback('list');
+ }
+ });
+ }
+
+ // Tree view button
+ if (!options.disableTreeView) {
+ buttons.push({
+ html: ``,
+ event: function() {
+ buttonCallback('tree');
+ }
+ });
+ }
+
+ return buttons;
+}
+
+
+/* Return the 'selected' data rows from a bootstrap table.
* If allowEmpty = false, and the returned dataset is empty,
* then instead try to return *all* the data
*/