diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py index e93c5b093f..c54476a733 100644 --- a/InvenTree/order/api.py +++ b/InvenTree/order/api.py @@ -287,6 +287,7 @@ class PurchaseOrderDetail(generics.RetrieveUpdateDestroyAPIView): class PurchaseOrderContextMixin: + """ Mixin to add purchase order object as serializer context variable """ def get_serializer_context(self): """ Add the PurchaseOrder object to the serializer context """ @@ -871,13 +872,8 @@ class SalesOrderLineItemDetail(generics.RetrieveUpdateDestroyAPIView): serializer_class = serializers.SalesOrderLineItemSerializer -class SalesOrderComplete(generics.CreateAPIView): - """ - API endpoint for manually marking a SalesOrder as "complete". - """ - - queryset = models.SalesOrder.objects.all() - serializer_class = serializers.SalesOrderCompleteSerializer +class SalesOrderContextMixin: + """ Mixin to add sales order object as serializer context variable """ def get_serializer_context(self): @@ -893,7 +889,22 @@ class SalesOrderComplete(generics.CreateAPIView): return ctx -class SalesOrderAllocateSerials(generics.CreateAPIView): +class SalesOrderCancel(SalesOrderContextMixin, generics.CreateAPIView): + + queryset = models.SalesOrder.objects.all() + serializer_class = serializers.SalesOrderCancelSerializer + + +class SalesOrderComplete(SalesOrderContextMixin, generics.CreateAPIView): + """ + API endpoint for manually marking a SalesOrder as "complete". + """ + + queryset = models.SalesOrder.objects.all() + serializer_class = serializers.SalesOrderCompleteSerializer + + +class SalesOrderAllocateSerials(SalesOrderContextMixin, generics.CreateAPIView): """ API endpoint to allocation stock items against a SalesOrder, by specifying serial numbers. @@ -902,22 +913,8 @@ class SalesOrderAllocateSerials(generics.CreateAPIView): queryset = models.SalesOrder.objects.none() serializer_class = serializers.SalesOrderSerialAllocationSerializer - def get_serializer_context(self): - ctx = super().get_serializer_context() - - # Pass through the SalesOrder object to the serializer - try: - ctx['order'] = models.SalesOrder.objects.get(pk=self.kwargs.get('pk', None)) - except: - pass - - ctx['request'] = self.request - - return ctx - - -class SalesOrderAllocate(generics.CreateAPIView): +class SalesOrderAllocate(SalesOrderContextMixin, generics.CreateAPIView): """ API endpoint to allocate stock items against a SalesOrder @@ -928,20 +925,6 @@ class SalesOrderAllocate(generics.CreateAPIView): queryset = models.SalesOrder.objects.none() serializer_class = serializers.SalesOrderShipmentAllocationSerializer - def get_serializer_context(self): - - ctx = super().get_serializer_context() - - # Pass through the SalesOrder object to the serializer - try: - ctx['order'] = models.SalesOrder.objects.get(pk=self.kwargs.get('pk', None)) - except: - pass - - ctx['request'] = self.request - - return ctx - class SalesOrderAllocationDetail(generics.RetrieveUpdateDestroyAPIView): """ @@ -1183,6 +1166,7 @@ order_api_urls = [ # Sales order detail view re_path(r'^(?P\d+)/', include([ + re_path(r'^cancel/', SalesOrderCancel.as_view(), name='api-so-cancel'), re_path(r'^complete/', SalesOrderComplete.as_view(), name='api-so-complete'), re_path(r'^allocate/', SalesOrderAllocate.as_view(), name='api-so-allocate'), re_path(r'^allocate-serials/', SalesOrderAllocateSerials.as_view(), name='api-so-allocate-serials'), diff --git a/InvenTree/order/forms.py b/InvenTree/order/forms.py index 75b6cb94ec..a08cf81ab1 100644 --- a/InvenTree/order/forms.py +++ b/InvenTree/order/forms.py @@ -8,28 +8,12 @@ from __future__ import unicode_literals from django import forms from django.utils.translation import gettext_lazy as _ -from InvenTree.forms import HelperForm from InvenTree.fields import InvenTreeMoneyField from InvenTree.helpers import clean_decimal from common.forms import MatchItemForm -from .models import PurchaseOrder -from .models import SalesOrder - - - -class CancelSalesOrderForm(HelperForm): - - confirm = forms.BooleanField(required=True, label=_('Confirm'), help_text=_('Cancel order')) - - class Meta: - model = SalesOrder - fields = [ - 'confirm', - ] - class OrderMatchItemForm(MatchItemForm): """ Override MatchItemForm fields """ diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py index 5bd753f17f..6f6654db1f 100644 --- a/InvenTree/order/serializers.py +++ b/InvenTree/order/serializers.py @@ -1041,6 +1041,25 @@ class SalesOrderCompleteSerializer(serializers.Serializer): order.complete_order(user) +class SalesOrderCancelSerializer(serializers.Serializer): + """ Serializer for marking a SalesOrder as cancelled + """ + + def get_context_data(self): + + order = self.context['order'] + + return { + 'can_cancel': order.can_cancel(), + } + + def save(self): + + order = self.context['order'] + + order.cancel_order() + + class SalesOrderSerialAllocationSerializer(serializers.Serializer): """ DRF serializer for allocation of serial numbers against a sales order / shipment diff --git a/InvenTree/order/templates/order/delete_attachment.html b/InvenTree/order/templates/order/delete_attachment.html deleted file mode 100644 index 4ee7f03cb1..0000000000 --- a/InvenTree/order/templates/order/delete_attachment.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "modal_delete_form.html" %} -{% load i18n %} - -{% block pre_form_content %} -{% trans "Are you sure you want to delete this attachment?" %} -
-{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html index 9abd058996..5593918a38 100644 --- a/InvenTree/order/templates/order/sales_order_base.html +++ b/InvenTree/order/templates/order/sales_order_base.html @@ -224,9 +224,13 @@ $("#edit-order").click(function() { }); $("#cancel-order").click(function() { - launchModalForm("{% url 'so-cancel' order.id %}", { - reload: true, - }); + + cancelSalesOrder( + {{ order.pk }}, + { + reload: true, + } + ); }); $("#complete-order").click(function() { diff --git a/InvenTree/order/templates/order/sales_order_cancel.html b/InvenTree/order/templates/order/sales_order_cancel.html deleted file mode 100644 index 2f0fe3beb1..0000000000 --- a/InvenTree/order/templates/order/sales_order_cancel.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "modal_form.html" %} - -{% load i18n %} - -{% block pre_form_content %} - -
-

{% trans "Warning" %}

- {% trans "Cancelling this order means that the order will no longer be editable." %} -
- -{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/urls.py b/InvenTree/order/urls.py index 9536d96963..15e7f5b1bb 100644 --- a/InvenTree/order/urls.py +++ b/InvenTree/order/urls.py @@ -29,7 +29,6 @@ purchase_order_urls = [ ] sales_order_detail_urls = [ - re_path(r'^cancel/', views.SalesOrderCancel.as_view(), name='so-cancel'), re_path(r'^export/', views.SalesOrderExport.as_view(), name='so-export'), re_path(r'^.*$', views.SalesOrderDetail.as_view(), name='so-detail'), diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 4620c34210..73c22aca22 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -87,32 +87,6 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView): template_name = 'order/sales_order_detail.html' -class SalesOrderCancel(AjaxUpdateView): - """ View for cancelling a sales order """ - - model = SalesOrder - ajax_form_title = _("Cancel sales order") - ajax_template_name = "order/sales_order_cancel.html" - form_class = order_forms.CancelSalesOrderForm - - def validate(self, order, form, **kwargs): - - confirm = str2bool(form.cleaned_data.get('confirm', False)) - - if not confirm: - form.add_error('confirm', _('Confirm order cancellation')) - - if not order.can_cancel(): - form.add_error(None, _('Order cannot be cancelled')) - - def save(self, order, form, **kwargs): - """ - Once the form has been validated, cancel the SalesOrder - """ - - order.cancel_order() - - class PurchaseOrderUpload(FileManagementFormView): ''' PurchaseOrder: Upload file, match to fields and parts (using multi-Step form) ''' diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js index 9fe50e3548..6b163afa1e 100644 --- a/InvenTree/templates/js/translated/order.js +++ b/InvenTree/templates/js/translated/order.js @@ -21,6 +21,7 @@ /* exported allocateStockToSalesOrder, cancelPurchaseOrder, + cancelSalesOrder, completePurchaseOrder, completeShipment, createSalesOrder, @@ -246,6 +247,32 @@ function issuePurchaseOrder(order_id, options={}) { } +/* + * Launches a modal form to mark a SalesOrder as "cancelled" + */ +function cancelSalesOrder(order_id, options={}) { + + constructForm( + `/api/order/so/${order_id}/cancel/`, + { + method: 'POST', + title: '{% trans "Cancel Sales Order" %}', + confirm: true, + preFormContent: function(opts) { + var html = ` +
+ {% trans "Cancelling this order means that the order will no longer be editable." %} +
`; + + return html; + }, + onSuccess: function(response) { + handleFormSuccess(response, options); + } + } + ); +} + // Open a dialog to create a new sales order shipment function createSalesOrderShipment(options={}) {