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 */