From ac3dcac64167700ea701c898117aaf71171d57a4 Mon Sep 17 00:00:00 2001 From: eeintech <eeintech@eeinte.ch> Date: Mon, 2 Aug 2021 15:05:24 -0400 Subject: [PATCH] Re-enabled installing stock items into others --- .../build/templates/build/build_base.html | 4 +- InvenTree/stock/forms.py | 23 +++-- InvenTree/stock/templates/stock/item.html | 19 ++++ .../stock/templates/stock/item_base.html | 24 ++++- .../stock/templates/stock/item_install.html | 22 ++++- InvenTree/stock/views.py | 92 +++++++++++++++---- 6 files changed, 146 insertions(+), 38 deletions(-) diff --git a/InvenTree/build/templates/build/build_base.html b/InvenTree/build/templates/build/build_base.html index 5770777d28..e3119e6fdb 100644 --- a/InvenTree/build/templates/build/build_base.html +++ b/InvenTree/build/templates/build/build_base.html @@ -111,8 +111,8 @@ src="{% static 'img/blank_image.png' %}" <li><a href='#' id='build-cancel'><span class='fas fa-times-circle icon-red'></span> {% trans "Cancel Build" %}</a></li> {% endif %} {% if build.status == BuildStatus.CANCELLED and roles.build.delete %} - <li><a href='#' id='build-delete'><span class='fas fa-trash-alt'></span> {% trans "Delete Build"% }</a> - {% endif %} + <li><a href='#' id='build-delete'><span class='fas fa-trash-alt'></span> {% trans "Delete Build" %}</a> + {% endif %} </ul> </div> {% endif %} diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index b23b71a2d6..b088a6cdef 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -241,16 +241,21 @@ class InstallStockForm(HelperForm): help_text=_('Stock item to install') ) - quantity_to_install = RoundingDecimalFormField( - max_digits=10, decimal_places=5, - initial=1, - label=_('Quantity'), - help_text=_('Stock quantity to assign'), - validators=[ - MinValueValidator(0.001) - ] + to_install = forms.BooleanField( + widget=forms.HiddenInput(), + required=False ) + # quantity_to_install = RoundingDecimalFormField( + # max_digits=10, decimal_places=5, + # initial=1, + # label=_('Quantity'), + # help_text=_('Stock quantity to assign'), + # validators=[ + # MinValueValidator(0.001) + # ] + # ) + notes = forms.CharField( required=False, help_text=_('Notes') @@ -261,7 +266,7 @@ class InstallStockForm(HelperForm): fields = [ 'part', 'stock_item', - 'quantity_to_install', + # 'quantity_to_install', 'notes', ] diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html index 8a00c1c5e6..d380ea3369 100644 --- a/InvenTree/stock/templates/stock/item.html +++ b/InvenTree/stock/templates/stock/item.html @@ -119,6 +119,11 @@ <h4>{% trans "Installed Stock Items" %}</h4> </div> <div class='panel-content'> + <div class='btn-group'> + <button type='button' class='btn btn-success' id='stock-item-install'> + <span class='fas fa-plus-circle'></span> {% trans "Install Stock Item" %} + </button> + </div> <table class='table table-striped table-condensed' id='installed-table'></table> </div> </div> @@ -128,6 +133,20 @@ {% block js_ready %} {{ block.super }} + $('#stock-item-install').click(function() { + + launchModalForm( + "{% url 'stock-item-install' item.pk %}", + { + data: { + 'part': {{ item.part.pk }}, + 'install_item': true, + }, + reload: true, + } + ); + }); + loadInstalledInTable( $('#installed-table'), { diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index b16d9b0b1a..93698e3d05 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -127,9 +127,11 @@ <li><a href='#' id='stock-return-from-customer' title='{% trans "Return to stock" %}'><span class='fas fa-undo'></span> {% trans "Return to stock" %}</a></li> {% endif %} {% if item.belongs_to %} - <li> - <a href='#' id='stock-uninstall' title='{% trans "Uninstall stock item" %}'><span class='fas fa-unlink'></span> {% trans "Uninstall" %}</a> - </li> + <li><a href='#' id='stock-uninstall' title='{% trans "Uninstall stock item" %}'><span class='fas fa-unlink'></span> {% trans "Uninstall" %}</a></li> + {% else %} + {% if item.part.get_used_in %} + <li><a href='#' id='stock-install-in' title='{% trans "Install stock item" %}'><span class='fas fa-link'></span> {% trans "Install" %}</a></li> + {% endif %} {% endif %} </ul> </div> @@ -461,13 +463,27 @@ $("#stock-serialize").click(function() { ); }); +$('#stock-install-in').click(function() { + + launchModalForm( + "{% url 'stock-item-install' item.pk %}", + { + data: { + 'part': {{ item.part.pk }}, + 'install_in': true, + }, + reload: true, + } + ); +}); + $('#stock-uninstall').click(function() { launchModalForm( "{% url 'stock-item-uninstall' %}", { data: { - 'items[]': [{{ item.pk}}], + 'items[]': [{{ item.pk }}], }, reload: true, } diff --git a/InvenTree/stock/templates/stock/item_install.html b/InvenTree/stock/templates/stock/item_install.html index 04798972d2..8a94f304d3 100644 --- a/InvenTree/stock/templates/stock/item_install.html +++ b/InvenTree/stock/templates/stock/item_install.html @@ -3,15 +3,31 @@ {% block pre_form_content %} +{% if install_item %} <p> - {% trans "Install another StockItem into this item." %} + {% trans "Install another Stock Item into this item." %} </p> <p> {% trans "Stock items can only be installed if they meet the following criteria" %}: <ul> - <li>{% trans "The StockItem links to a Part which is in the BOM for this StockItem" %}</li> - <li>{% trans "The StockItem is currently in stock" %}</li> + <li>{% trans "The Stock Item links to a Part which is in the BOM for this Stock Item" %}</li> + <li>{% trans "The Stock Item is currently in stock" %}</li> + <li>{% trans "The Stock Item is serialized and does not belong to another item" %}</li> </ul> </p> +{% elif install_in %} +<p> + {% trans "Install this Stock Item in another stock item." %} +</p> +<p> + {% trans "Stock items can only be installed if they meet the following criteria" %}: + + <ul> + <li>{% trans "The part associated to this Stock Item belongs to another part's BOM" %}</li> + <li>{% trans "This Stock Item is serialized and does not belong to another item" %}</li> + </ul> +</p> +{% endif %} + {% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 80968e5aa9..25f8cefac1 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -518,36 +518,73 @@ class StockItemInstall(AjaxUpdateView): part = None + def get_params(self): + """ Retrieve GET parameters """ + + # Look at GET params + self.part_id = self.request.GET.get('part', None) + self.install_in = self.request.GET.get('install_in', False) + self.install_item = self.request.GET.get('install_item', False) + + if self.part_id is None: + # Look at POST params + self.part_id = self.request.POST.get('part', None) + + try: + self.part = Part.objects.get(pk=self.part_id) + except (ValueError, Part.DoesNotExist): + self.part = None + def get_stock_items(self): """ Return a list of stock items suitable for displaying to the user. Requirements: - Items must be in stock - - Filters: - - Items can be filtered by Part reference + - Items must be in BOM of stock item + - Items must be serialized """ - + + # Filter items in stock items = StockItem.objects.filter(StockItem.IN_STOCK_FILTER) - # Filter by Part association + # Filter serialized stock items + items = items.exclude(serial__isnull=True).exclude(serial__exact='') - # Look at GET params - part_id = self.request.GET.get('part', None) + if self.part: + # Filter for parts to install this item in + if self.install_in: + # Get parts using this part + allowed_parts = self.part.get_used_in() + # Filter + items = items.filter(part__in=allowed_parts) - if part_id is None: - # Look at POST params - part_id = self.request.POST.get('part', None) - - try: - self.part = Part.objects.get(pk=part_id) - items = items.filter(part=self.part) - except (ValueError, Part.DoesNotExist): - self.part = None + # Filter for parts to install in this item + if self.install_item: + # Get parts used in this part's BOM + bom_items = self.part.get_bom_items() + allowed_parts = [item.sub_part for item in bom_items] + # Filter + items = items.filter(part__in=allowed_parts) return items + def get_context_data(self, **kwargs): + """ Retrieve parameters and update context """ + + ctx = super().get_context_data(**kwargs) + + # Get request parameters + self.get_params() + + ctx.update({ + 'part': self.part, + 'install_in': self.install_in, + 'install_item': self.install_item, + }) + + return ctx + def get_initial(self): initials = super().get_initial() @@ -558,11 +595,17 @@ class StockItemInstall(AjaxUpdateView): if items.count() == 1: item = items.first() initials['stock_item'] = item.pk - initials['quantity_to_install'] = item.quantity + # initials['quantity_to_install'] = item.quantity if self.part: initials['part'] = self.part + try: + # Is this stock item being installed in the other stock item? + initials['to_install'] = self.install_in or not self.install_item + except AttributeError: + pass + return initials def get_form(self): @@ -575,6 +618,8 @@ class StockItemInstall(AjaxUpdateView): def post(self, request, *args, **kwargs): + self.get_params() + form = self.get_form() valid = form.is_valid() @@ -584,13 +629,20 @@ class StockItemInstall(AjaxUpdateView): data = form.cleaned_data other_stock_item = data['stock_item'] - quantity = data['quantity_to_install'] + # quantity = data['quantity_to_install'] + # Quantity will always be 1 for serialized item + quantity = 1 notes = data['notes'] - # Install the other stock item into this one + # Get stock item this_stock_item = self.get_object() - this_stock_item.installStockItem(other_stock_item, quantity, request.user, notes) + if data['to_install']: + # Install this stock item into the other stock item + other_stock_item.installStockItem(this_stock_item, quantity, request.user, notes) + else: + # Install the other stock item into this one + this_stock_item.installStockItem(other_stock_item, quantity, request.user, notes) data = { 'form_valid': valid,