diff --git a/InvenTree/InvenTree/static/script/inventree/tables.js b/InvenTree/InvenTree/static/script/inventree/tables.js index be0e1e6325..cc4320307b 100644 --- a/InvenTree/InvenTree/static/script/inventree/tables.js +++ b/InvenTree/InvenTree/static/script/inventree/tables.js @@ -157,6 +157,11 @@ $.fn.inventreeTable = function(options) { console.log('Could not get list of visible columns!'); } } + + // Optionally, link buttons to the table selection + if (options.buttons) { + linkButtonsToSelection(table, options.buttons); + } } function customGroupSorter(sortName, sortOrder, sortData) { diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index e0b1623a54..37d8d91c8a 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -271,6 +271,24 @@ class ExportOptionsForm(HelperForm): self.fields['file_format'].choices = self.get_format_choices() +class UninstallStockForm(forms.ModelForm): + """ + Form for uninstalling a stock item which is installed in another item. + """ + + location = TreeNodeChoiceField(queryset=StockLocation.objects.all(), label=_('Location'), help_text=_('Destination location for uninstalled items')) + + confirm = forms.BooleanField(required=False, initial=False, label=_('Confirm uninstall'), help_text=_('Confirm removal of installed stock items')) + + class Meta: + + model = StockItem + + fields = [ + 'location', + 'confirm', + ] + class AdjustStockForm(forms.ModelForm): """ Form for performing simple stock adjustments. @@ -282,15 +300,15 @@ class AdjustStockForm(forms.ModelForm): This form is used for managing stock adjuments for single or multiple stock items. """ - destination = TreeNodeChoiceField(queryset=StockLocation.objects.all(), label='Destination', required=True, help_text=_('Destination stock location')) + destination = TreeNodeChoiceField(queryset=StockLocation.objects.all(), label=_('Destination'), required=True, help_text=_('Destination stock location')) - note = forms.CharField(label='Notes', required=True, help_text='Add note (required)') + note = forms.CharField(label=_('Notes'), required=True, help_text=_('Add note (required)')) # transaction = forms.BooleanField(required=False, initial=False, label='Create Transaction', help_text='Create a stock transaction for these parts') - confirm = forms.BooleanField(required=False, initial=False, label='Confirm stock adjustment', help_text=_('Confirm movement of stock items')) + confirm = forms.BooleanField(required=False, initial=False, label=_('Confirm stock adjustment'), help_text=_('Confirm movement of stock items')) - set_loc = forms.BooleanField(required=False, initial=False, label='Set Default Location', help_text=_('Set the destination as the default location for selected parts')) + set_loc = forms.BooleanField(required=False, initial=False, label=_('Set Default Location'), help_text=_('Set the destination as the default location for selected parts')) class Meta: model = StockItem diff --git a/InvenTree/stock/templates/stock/item_installed.html b/InvenTree/stock/templates/stock/item_installed.html index 72451f11e9..d6a4675bf4 100644 --- a/InvenTree/stock/templates/stock/item_installed.html +++ b/InvenTree/stock/templates/stock/item_installed.html @@ -10,7 +10,18 @@

{% trans "Installed Items" %}


- +
+
+
+ + +
+
+
+ +
{% endblock %} @@ -37,7 +48,6 @@ $('#installed-table').inventreeTable({ title: '{% trans 'Select' %}', searchable: false, switchable: false, - visible: false, }, { field: 'pk', @@ -133,8 +143,20 @@ $('#installed-table').inventreeTable({ // Find buttons and associate actions table.find('.button-uninstall').click(function() { var pk = $(this).attr('pk'); + + launchModalForm( + "{% url 'stock-item-uninstall' %}", + { + data: { + 'items[]': [pk], + } + } + ); }); - } + }, + buttons: [ + '#stock-options', + ] }); {% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/stock_uninstall.html b/InvenTree/stock/templates/stock/stock_uninstall.html new file mode 100644 index 0000000000..2a8d9c7ee4 --- /dev/null +++ b/InvenTree/stock/templates/stock/stock_uninstall.html @@ -0,0 +1,28 @@ +{% extends "modal_form.html" %} +{% load i18n %} +{% load inventree_extras %} + +{% block pre_form_content %} + +
+ {% trans "The following stock items will be uninstalled" %} +
+ + + +{% endblock %} + +{% block form_data %} + +{% for item in stock_items %} + +{% endfor %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index c6b0b2b54c..4c86995cda 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -60,6 +60,8 @@ stock_urls = [ url(r'^item/new/?', views.StockItemCreate.as_view(), name='stock-item-create'), + url(r'^item/uninstall/', views.StockItemUninstall.as_view(), name='stock-item-uninstall'), + url(r'^item/test-report-download/', views.StockItemTestReportDownload.as_view(), name='stock-item-test-report-download'), url(r'^item/print-stock-labels/', views.StockItemPrintLabels.as_view(), name='stock-item-print-labels'), diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index aadac17c7a..6aedfe1b4c 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -683,6 +683,89 @@ class StockItemQRCode(QRCodeView): return None +class StockItemUninstall(AjaxView, FormMixin): + """ + View for uninstalling one or more StockItems, + which are installed in another stock item. + + Stock items are uninstalled into a location, + defaulting to the location that they were "in" before they were installed. + + If multiple default locations are detected, + leave the final location up to the user. + """ + + ajax_template_name = 'stock/stock_uninstall.html' + ajax_form_title = _('Uninstall Stock Items') + form_class = StockForms.UninstallStockForm + + # List of stock items to uninstall (initially empty) + stock_items = [] + + def get_stock_items(self): + + return self.stock_items + + def get(self, request, *args, **kwargs): + + """ Extract list of stock items, which are supplied as a list, + e.g. items[]=1,2,3 + """ + + if 'items[]' in request.GET: + self.stock_items = StockItem.objects.filter(id__in=request.GET.getlist('items[]')) + else: + self.stock_items = [] + + print("GET:", request.GET) + + return self.renderJsonResponse(request, self.get_form()) + + def post(self, request, *args, **kwargs): + + """ + Extract a list of stock items which are included as hidden inputs in the form data. + """ + + items = [] + + for item in self.request.POST: + if item.startswith('stock-item-'): + pk = item.replace('stock-item', '') + + try: + stock_item = StockItem.objects.get(pk=pk) + items.append(stock_item) + except (ValueError, StockItem.DoesNotExist): + pass + + self.stock_items = items + + confirmed = str2bool(request.POST.get('confirm')) + + valid = False + + form = self.get_form() + + if not confirmed: + valid = False + form.errors['confirm'] = [_('Confirm stock adjustment')] + + data = { + 'form_valid': valid, + } + + return self.renderJsonResponse(request, form=form, data=data) + + def get_context_data(self): + + context = super().get_context_data() + + context['stock_items'] = self.get_stock_items() + + return context + + class StockAdjust(AjaxView, FormMixin): """ View for enacting simple stock adjustments: