diff --git a/InvenTree/InvenTree/status_codes.py b/InvenTree/InvenTree/status_codes.py index ffe22039c9..93f213445c 100644 --- a/InvenTree/InvenTree/status_codes.py +++ b/InvenTree/InvenTree/status_codes.py @@ -255,6 +255,9 @@ class StockHistoryCode(StatusCode): # Stock merging operations MERGED_STOCK_ITEMS = 45 + # Convert stock item to variant + CONVERTED_TO_VARIANT = 48 + # Build order codes BUILD_OUTPUT_CREATED = 50 BUILD_OUTPUT_COMPLETED = 55 @@ -294,6 +297,8 @@ class StockHistoryCode(StatusCode): MERGED_STOCK_ITEMS: _('Merged stock items'), + CONVERTED_TO_VARIANT: _('Converted to variant'), + SENT_TO_CUSTOMER: _('Sent to customer'), RETURNED_FROM_CUSTOMER: _('Returned from customer'), diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index e176948599..3768cd8787 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -1234,6 +1234,15 @@ class StockTrackingList(generics.ListAPIView): if not deltas: deltas = {} + # Add part detail + if 'part' in deltas: + try: + part = Part.objects.get(pk=deltas['part']) + serializer = PartBriefSerializer(part) + deltas['part_detail'] = serializer.data + except: + pass + # Add location detail if 'location' in deltas: try: diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 171ee7e0a3..dc93f61e81 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -718,6 +718,33 @@ class StockItem(MPTTModel): help_text=_('Select Owner'), related_name='stock_items') + @transaction.atomic + def convert_to_variant(self, variant, user, notes=None): + """ + Convert this StockItem instance to a "variant", + i.e. change the "part" reference field + """ + + if not variant: + # Ignore null values + return + + if variant == self.part: + # Variant is the same as the current part + return + + self.part = variant + self.save() + + self.add_tracking_entry( + StockHistoryCode.CONVERTED_TO_VARIANT, + user, + deltas={ + 'part': variant.pk, + }, + notes=_('Converted to part') + ': ' + variant.full_name, + ) + def get_item_owner(self): """ Return the closest "owner" for this StockItem. diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html index ae0742e99e..75e53d6758 100644 --- a/InvenTree/stock/templates/stock/item.html +++ b/InvenTree/stock/templates/stock/item.html @@ -26,11 +26,12 @@
-
+
+ {% include "filter_list.html" with id="stocktracking" %}
- +
@@ -342,7 +343,6 @@ ); }); - loadStockTrackingTable($("#track-table"), { params: { ordering: '-date', diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 079f9c2dc9..b0661dd0e3 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -644,6 +644,16 @@ class StockItemConvert(AjaxUpdateView): return form + def save(self, obj, form): + + stock_item = self.get_object() + + variant = form.cleaned_data.get('part', None) + + stock_item.convert_to_variant(variant, user=self.request.user) + + return stock_item + class StockLocationCreate(AjaxCreateView): """ diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js index 42ed04265d..c13ea41f99 100644 --- a/InvenTree/templates/js/translated/stock.js +++ b/InvenTree/templates/js/translated/stock.js @@ -2319,6 +2319,23 @@ function loadStockTrackingTable(table, options) { var cols = []; + var filterTarget = '#filter-list-stocktracking'; + + var filterKey = 'stocktracking'; + + var filters = loadTableFilters(filterKey); + + var params = options.params; + + var original = {}; + + for (var k in params) { + original[k] = params[k]; + filters[k] = params[k]; + } + + setupFilterList(filterKey, table, filterTarget); + // Date cols.push({ field: 'date', @@ -2356,6 +2373,19 @@ function loadStockTrackingTable(table, options) { return html; } + // Part information + if (details.part) { + html += `{% trans "Part" %}`; + + if (details.part_detail) { + html += renderLink(details.part_detail.full_name, `/part/${details.part}/`); + } else { + html += `{% trans "Part information unavailable" %}`; + } + + html += ``; + } + // Location information if (details.location) { @@ -2493,27 +2523,10 @@ function loadStockTrackingTable(table, options) { } }); - /* - // 2021-05-11 - Ability to edit or delete StockItemTracking entries is now removed - cols.push({ - sortable: false, - formatter: function(value, row, index, field) { - // Manually created entries can be edited or deleted - if (false && !row.system) { - var bEdit = ""; - var bDel = ""; - - return "
" + bEdit + bDel + "
"; - } else { - return ""; - } - } - }); - */ - table.inventreeTable({ method: 'get', - queryParams: options.params, + queryParams: filters, + original: original, columns: cols, url: options.url, });