From ca1281ee109c7d184b5f294988274d9feed5a9fc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 18 Sep 2020 22:11:51 +1000 Subject: [PATCH] Adds ajax table for part sale price information --- InvenTree/part/api.py | 27 +++++++ InvenTree/part/serializers.py | 27 +++++++ .../part/templates/part/sale_prices.html | 77 ++++++++++++++++++- 3 files changed, 128 insertions(+), 3 deletions(-) diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index abc4181895..225e2402e1 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -20,6 +20,7 @@ from django.urls import reverse from .models import Part, PartCategory, BomItem, PartStar from .models import PartParameter, PartParameterTemplate from .models import PartAttachment, PartTestTemplate +from .models import PartSellPriceBreak from . import serializers as part_serializers @@ -107,6 +108,27 @@ class CategoryDetail(generics.RetrieveUpdateDestroyAPIView): queryset = PartCategory.objects.all() +class PartSalePriceList(generics.ListCreateAPIView): + """ + API endpoint for list view of PartSalePriceBreak model + """ + + queryset = PartSellPriceBreak.objects.all() + serializer_class = part_serializers.PartSalePriceSerializer + + permission_classes = [ + permissions.IsAuthenticated, + ] + + filter_backends = [ + DjangoFilterBackend + ] + + filter_fields = [ + 'part', + ] + + class PartAttachmentList(generics.ListCreateAPIView, AttachmentMixin): """ API endpoint for listing (and creating) a PartAttachment (file upload). @@ -755,6 +777,11 @@ part_api_urls = [ url(r'^(?P\d+)/?', PartStarDetail.as_view(), name='api-part-star-detail'), url(r'^$', PartStarList.as_view(), name='api-part-star-list'), ])), + + # Base URL for part sale pricing + url(r'^sale-price/', include([ + url(r'^.*$', PartSalePriceList.as_view(), name='api-part-sale-price-list'), + ])), # Base URL for PartParameter API endpoints url(r'^parameter/', include([ diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 8adb26680e..62f7eebbbb 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -12,6 +12,7 @@ from .models import BomItem from .models import PartParameter, PartParameterTemplate from .models import PartAttachment from .models import PartTestTemplate +from .models import PartSellPriceBreak from stock.models import StockItem @@ -87,6 +88,32 @@ class PartTestTemplateSerializer(InvenTreeModelSerializer): ] +class PartSalePriceSerializer(InvenTreeModelSerializer): + """ + Serializer for sale prices for Part model. + """ + + symbol = serializers.CharField(read_only=True) + + suffix = serializers.CharField(read_only=True) + + quantity = serializers.FloatField() + + cost = serializers.FloatField() + + class Meta: + model = PartSellPriceBreak + fields = [ + 'pk', + 'part', + 'quantity', + 'cost', + 'currency', + 'symbol', + 'suffix', + ] + + class PartThumbSerializer(serializers.Serializer): """ Serializer for the 'image' field of the Part model. diff --git a/InvenTree/part/templates/part/sale_prices.html b/InvenTree/part/templates/part/sale_prices.html index b8992e093e..8d3cc61afd 100644 --- a/InvenTree/part/templates/part/sale_prices.html +++ b/InvenTree/part/templates/part/sale_prices.html @@ -9,7 +9,7 @@

{% trans "Sale Price" %}


-
+
@@ -21,14 +21,14 @@ {% block js_ready %} {{ block.super }} -function reloadTable() { +function reloadPriceBreaks() { $("#price-break-table").bootstrapTable("refresh"); } $('#new-price-break').click(function() { launchModalForm("{% url 'sale-price-break-create' %}", { - success: reloadTable, + success: reloadPriceBreaks, data: { part: {{ part.id }}, } @@ -36,4 +36,75 @@ $('#new-price-break').click(function() { ); }); +$('#price-break-table').inventreeTable({ + name: 'saleprice', + formatNoMatches: function() { return "{% trans 'No price break information found' %}"; }, + queryParams: { + part: {{ part.id }}, + }, + url: "{% url 'api-part-sale-price-list' %}", + onLoadSuccess: function() { + var table = $('#price-break-table'); + + table.find('.button-price-break-delete').click(function() { + var pk = $(this).attr('pk'); + + launchModalForm( + `/part/sale-price/${pk}/delete/`, + { + success: reloadPriceBreaks + } + ); + }); + + table.find('.button-price-break-edit').click(function() { + var pk = $(this).attr('pk'); + + launchModalForm( + `/part/sale-price/${pk}/edit/`, + { + success: reloadPriceBreaks + } + ); + }); + }, + columns: [ + { + field: 'pk', + title: 'ID', + visible: false, + switchable: false, + }, + { + field: 'quantity', + title: '{% trans "Quantity" %}', + sortable: true, + }, + { + field: 'cost', + title: '{% trans "Price" %}', + sortable: true, + formatter: function(value, row, index) { + var html = ''; + + html += row.symbol || ''; + html += value; + + if (row.suffix) { + html += ' ' + row.suffix || ''; + } + + html += `
` + + html += makeIconButton('fa-edit icon-blue', 'button-price-break-edit', row.pk, '{% trans "Edit price break" %}'); + html += makeIconButton('fa-trash-alt icon-red', 'button-price-break-delete', row.pk, '{% trans "Delete price break" %}'); + + html += `
`; + + return html; + } + }, + ] +}) + {% endblock %} \ No newline at end of file