diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index eed6c6ad21..7bdc6e8a9b 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -960,4 +960,14 @@ input[type="date"].form-control, input[type="time"].form-control, input[type="da .sidebar-icon { min-width: 19px; -} \ No newline at end of file +} + +.row.full-height { + display: flex; + flex-wrap: wrap; + } + +.row.full-height > [class*='col-'] { + display: flex; + flex-direction: column; + } diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html index cf719711dc..1214239fe4 100644 --- a/InvenTree/part/templates/part/prices.html +++ b/InvenTree/part/templates/part/prices.html @@ -176,8 +176,11 @@

{% trans "Internal Cost" %}

-
+
+
+ +
@@ -224,8 +227,11 @@

{% trans "Sale Cost" %}

-
+
+
+ +
@@ -376,6 +382,7 @@ pb_url: '{% url 'api-part-internal-price-list' %}', pb_new_btn: $('#new-internal-price-break'), pb_new_url: '{% url 'internal-price-break-create' %}', + linkedGraph: $('#InternalPriceBreakChart'), }, ); {% endif %} @@ -402,6 +409,7 @@ pb_url: "{% url 'api-part-sale-price-list' %}", pb_new_btn: $('#new-price-break'), pb_new_url: '{% url 'sale-price-break-create' %}', + linkedGraph: $('#SalePriceBreakChart'), }, ); {% endif %} diff --git a/InvenTree/templates/js/part.js b/InvenTree/templates/js/part.js index 37fd36486b..75e925266a 100644 --- a/InvenTree/templates/js/part.js +++ b/InvenTree/templates/js/part.js @@ -776,6 +776,8 @@ function loadPriceBreakTable(table, options) { var name = options.name || 'pricebreak'; var human_name = options.human_name || 'price break'; + var linkedGraph = options.linkedGraph || null; + var chart = null; table.inventreeTable({ name: name, @@ -784,6 +786,31 @@ function loadPriceBreakTable(table, options) { return `{% trans "No ${human_name} information found" %}`; }, url: options.url, + onLoadSuccess: function(tableData) { + if (linkedGraph) { + var labels = Array.from(tableData, x => x.quantity); + var data = Array.from(tableData, x => parseFloat(x.price)); + + // destroy chart if exists + if (chart){ + chart.destroy(); + } + chart = loadLineChart(linkedGraph, + { + labels: labels, + datasets: [ + { + label: '{% trans "Unit Price" %}', + data: data, + backgroundColor: 'rgba(255, 206, 86, 0.2)', + borderColor: 'rgb(255, 206, 86)', + stepped: true, + fill: true, + },] + } + ); + } + }, columns: [ { field: 'pk', @@ -817,6 +844,20 @@ function loadPriceBreakTable(table, options) { }); } +function loadLineChart(context, data) { + return new Chart(context, { + type: 'line', + data: data, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: {position: 'bottom'}, + } + } + }); +} + function initPriceBreakSet(table, options) { var part_id = options.part_id; @@ -826,14 +867,15 @@ function initPriceBreakSet(table, options) { var pb_new_btn = options.pb_new_btn; var pb_new_url = options.pb_new_url; -function initPriceBreakSet(table, part_id, pb_human_name, pb_url_slug, pb_url, pb_new_btn, pb_new_url) { - + var linkedGraph = options.linkedGraph || null; + loadPriceBreakTable( table, { name: pb_url_slug, human_name: pb_human_name, url: pb_url, + linkedGraph: linkedGraph, } );