diff --git a/InvenTree/part/templates/part/prices.html b/InvenTree/part/templates/part/prices.html index b1403b3157..9c216eb534 100644 --- a/InvenTree/part/templates/part/prices.html +++ b/InvenTree/part/templates/part/prices.html @@ -281,7 +281,15 @@
- PLACEHOLDER FOR SALE HISTORY + {% if sale_history|length > 0 %} +
+ +
+ {% else %} +
+ {% trans 'No sale pice history available for this part.' %} +
+ {% endif %}
{% endif %} @@ -444,4 +452,35 @@ ); {% endif %} + // Sale price history + {% if sale_history %} + var salepricedata = { + labels: [ + {% for line in sale_history %}'{{ line.date }}',{% endfor %} + ], + datasets: [{ + label: '{% blocktrans %}Unit Price - {{currency}}{% endblocktrans %}', + backgroundColor: 'rgba(255, 99, 132, 0.2)', + borderColor: 'rgb(255, 99, 132)', + yAxisID: 'y', + data: [ + {% for line in sale_history %}{{ line.price|stringformat:".2f" }},{% endfor %} + ], + borderWidth: 1, + }, + { + label: '{% trans "Quantity" %}', + backgroundColor: 'rgba(255, 206, 86, 0.2)', + borderColor: 'rgb(255, 206, 86)', + yAxisID: 'y1', + data: [ + {% for line in sale_history %}{{ line.qty|stringformat:"f" }},{% endfor %} + ], + borderWidth: 1, + type: 'bar', + }] + } + var SalePriceChart = loadSellPricingChart($('#SalePriceChart'), salepricedata) + {% endif %} + {% endblock %} diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 7a683a29b5..30e95535d6 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -50,6 +50,7 @@ import common.settings as inventree_settings from . import forms as part_forms from .bom import MakeBomTemplate, BomUploadManager, ExportBom, IsValidBOMFormat +from order.models import PurchaseOrderLineItem from .admin import PartResource @@ -1038,6 +1039,36 @@ class PartPricingView(PartDetail): # add to global context ctx['bom_parts'] = ctx_bom_parts + # Sale price history + sale_items = PurchaseOrderLineItem.objects.filter(part__part=part).order_by('order__issue_date').\ + prefetch_related('order', ).all() + + if sale_items: + sale_history = [] + + for sale_item in sale_items: + # check for not fully defined elements + if None in [sale_item.purchase_price, sale_item.quantity]: + continue + + price = convert_money(sale_item.purchase_price, default_currency) + line = { + 'price': price.amount if price else 0, + 'qty': sale_item.quantity, + } + + # set date for graph labels + if sale_item.order.issue_date: + line['date'] = sale_item.order.issue_date.strftime('%d.%m.%Y') + elif sale_item.order.creation_date: + line['date'] = sale_item.order.creation_date.strftime('%d.%m.%Y') + else: + line['date'] = _('None') + + sale_history.append(line) + + ctx['sale_history'] = sale_history + return ctx def get_initials(self): diff --git a/InvenTree/templates/js/part.js b/InvenTree/templates/js/part.js index 888f1d245a..7fa63098e1 100644 --- a/InvenTree/templates/js/part.js +++ b/InvenTree/templates/js/part.js @@ -977,3 +977,36 @@ function loadBomChart(context, data) { } }); } + +function loadSellPricingChart(context, data) { + return new Chart(context, { + type: 'line', + data: data, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: {legend: {position: 'bottom'}}, + scales: { + y: { + type: 'linear', + position: 'left', + grid: {display: false}, + title: { + display: true, + text: '{% trans "Unit Price" %}' + } + }, + y1: { + type: 'linear', + position: 'right', + grid: {display: false}, + titel: { + display: true, + text: '{% trans "Quantity" %}', + position: 'right' + } + }, + }, + } + }); +}