diff --git a/InvenTree/order/admin.py b/InvenTree/order/admin.py index 4519f8a2a9..1e7b20e5a1 100644 --- a/InvenTree/order/admin.py +++ b/InvenTree/order/admin.py @@ -13,6 +13,10 @@ from .models import SalesOrder, SalesOrderLineItem from .models import SalesOrderAllocation +class PurchaseOrderLineItemInlineAdmin(admin.StackedInline): + model = PurchaseOrderLineItem + + class PurchaseOrderAdmin(ImportExportModelAdmin): list_display = ( @@ -29,6 +33,10 @@ class PurchaseOrderAdmin(ImportExportModelAdmin): 'description', ] + inlines = [ + PurchaseOrderLineItemInlineAdmin + ] + class SalesOrderAdmin(ImportExportModelAdmin): diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index 5305038b4f..fb169e0536 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -826,6 +826,9 @@ class SalesOrderAllocation(models.Model): else: return "" + def get_po(self): + return self.item.purchase_order + def complete_allocation(self, user): """ Complete this allocation (called when the parent SalesOrder is marked as "shipped"): diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py index 062e8986b2..6091140313 100644 --- a/InvenTree/order/serializers.py +++ b/InvenTree/order/serializers.py @@ -235,6 +235,7 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer): location_path = serializers.CharField(source='get_location_path') location_id = serializers.IntegerField(source='get_location') serial = serializers.CharField(source='get_serial') + po = serializers.CharField(source='get_po') quantity = serializers.FloatField() class Meta: @@ -247,6 +248,7 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer): 'quantity', 'location_id', 'location_path', + 'po', 'item', ] diff --git a/InvenTree/order/templates/order/sales_order_detail.html b/InvenTree/order/templates/order/sales_order_detail.html index 72b7d63911..a90e61bff9 100644 --- a/InvenTree/order/templates/order/sales_order_detail.html +++ b/InvenTree/order/templates/order/sales_order_detail.html @@ -87,6 +87,9 @@ function showAllocationSubTable(index, row, element) { return renderLink(row.location_path, `/stock/location/${row.location_id}/`); }, }, + { + field: 'po' + }, { field: 'buttons', title: '{% trans "Actions" %}', @@ -159,9 +162,12 @@ function showFulfilledSubTable(index, row, element) { text = `{% trans "Quantity" %}: ${row.quantity}`; } - return renderLink(text, `/stock/item/${row.pk}/`); + return renderLink(text, `/stock/item/${row.pk}/`); }, - } + }, + { + field: 'po' + }, ], }); } @@ -271,6 +277,25 @@ $("#so-lines-table").inventreeTable({ field: 'notes', title: '{% trans "Notes" %}', }, + { + field: 'po', + title: '{% trans "PO" %}', + formatter: function(value, row, index, field) { + var po_name = ""; + if (row.allocated) { + row.allocations.forEach(function(allocation) { + if (allocation.po != po_name) { + if (po_name) { + po_name = "-"; + } else { + po_name = allocation.po + } + } + }) + } + return `
` + po_name + `
`; + } + }, {% if order.status == SalesOrderStatus.PENDING %} { field: 'buttons', diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index cf79746f0d..c8ec42d3e7 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -90,7 +90,7 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView): """ Detail view for a SalesOrder object """ context_object_name = 'order' - queryset = SalesOrder.objects.all().prefetch_related('lines') + queryset = SalesOrder.objects.all().prefetch_related('lines__allocations__item__purchase_order') template_name = 'order/sales_order_detail.html' diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 28123ebc41..88f8dd081c 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -1370,6 +1370,12 @@ class StockItem(MPTTModel): if self.location: s += ' @ {loc}'.format(loc=self.location.name) + if self.purchase_order: + s += " ({pre}{po})".format( + pre=helpers.getSetting("PURCHASEORDER_REFERENCE_PREFIX"), + po=self.purchase_order, + ) + return s @transaction.atomic