diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index bb403d837d..06d90e33df 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -46,6 +46,18 @@ class AssignStockItemToCustomerForm(HelperForm): ] +class ReturnStockItemForm(HelperForm): + """ + Form for manually returning a StockItem into stock + """ + + class Meta: + model = StockItem + fields = [ + 'location', + ] + + class EditStockItemTestResultForm(HelperForm): """ Form for creating / editing a StockItemTestResult object. diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 736e2218bf..38e2a35fff 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -495,6 +495,23 @@ class StockItem(MPTTModel): # Return the reference to the stock item return item + def returnFromCustomer(self, location, user=None): + """ + Return stock item from customer, back into the specified location. + """ + + self.addTransactionNote( + _("Returned from customer") + " " + self.customer.name, + user, + notes=_("Returned to location") + " " + location.name, + system=True + ) + + self.customer = None + self.location = location + + self.save() + # If stock item is incoming, an (optional) ETA field # expected_arrival = models.DateField(null=True, blank=True) diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index 8a57c8bdaf..00ad0063d5 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -354,7 +354,6 @@ $("#unlink-barcode").click(function() { {% if item.in_stock %} -{% if item.part.salable %} $("#stock-assign-to-customer").click(function() { launchModalForm("{% url 'stock-item-assign' item.id %}", { @@ -362,7 +361,6 @@ $("#stock-assign-to-customer").click(function() { } ); }); -{% endif %} function itemAdjust(action) { launchModalForm("/stock/adjust/", @@ -403,6 +401,16 @@ $('#stock-add').click(function() { itemAdjust('add'); }); +{% else %} + +$("#stock-return-from-customer").click(function() { + launchModalForm("{% url 'stock-item-return' item.id %}", + { + reload: true, + } + ); +}); + {% endif %} $("#stock-delete").click(function () { diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index 65e9c6742b..b48795b86e 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -24,6 +24,7 @@ stock_item_detail_urls = [ url(r'^qr_code/', views.StockItemQRCode.as_view(), name='stock-item-qr'), url(r'^delete_test_data/', views.StockItemDeleteTestData.as_view(), name='stock-item-delete-test-data'), url(r'^assign/', views.StockItemAssignToCustomer.as_view(), name='stock-item-assign'), + url(r'^return/', views.StockItemReturnToStock.as_view(), name='stock-item-return'), url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'), diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 672f0a3892..56a3abaaad 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -260,6 +260,41 @@ class StockItemAssignToCustomer(AjaxUpdateView): return self.renderJsonResponse(request, self.get_form(), data) +class StockItemReturnToStock(AjaxUpdateView): + """ + View for returning a stock item (which is assigned to a customer) to stock. + """ + + model = StockItem + ajax_form_title = _("Return to Stock") + context_object_name = "item" + form_class = StockForms.ReturnStockItemForm + + def post(self, request, *args, **kwargs): + + location = request.POST.get('location', None) + + if location: + try: + location = StockLocation.objects.get(pk=location) + except (ValueError, StockLocation.DoesNotExist): + location = None + + if location: + stock_item = self.get_object() + + stock_item.returnFromCustomer(location, request.user) + else: + raise ValidationError({'location': _("Specify a valid location")}) + + data = { + 'form_valid': True, + 'success': _("Stock item returned from customer") + } + + return self.renderJsonResponse(request, self.get_form(), data) + + class StockItemDeleteTestData(AjaxUpdateView): """ View for deleting all test data