diff --git a/InvenTree/order/forms.py b/InvenTree/order/forms.py index 43a8d4a529..cc7535bac9 100644 --- a/InvenTree/order/forms.py +++ b/InvenTree/order/forms.py @@ -50,6 +50,17 @@ class CancelPurchaseOrderForm(HelperForm): fields = [ 'confirm', ] + + +class CancelSalesOrderForm(HelperForm): + + confirm = forms.BooleanField(required=False, help_text=_('Cancel order')) + + class Meta: + model = SalesOrder + fields = [ + 'confirm', + ] class ReceivePurchaseOrderForm(HelperForm): diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index 136402f471..85eabfa3d0 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -289,6 +289,10 @@ class SalesOrder(Order): related_name='+' ) + @property + def is_pending(self): + return self.status == SalesOrderStatus.PENDING + def is_fully_allocated(self): """ Return True if all line items are fully allocated """ @@ -298,6 +302,42 @@ class SalesOrder(Order): return True + @transaction.atomic + def ship_order(self, user): + """ Mark this order as 'shipped' """ + + if not self.status == SalesOrderStatus.PENDING: + return False + + # Ensure the order status is marked as "Shipped" + self.status = SalesOrderStatus.SHIPPED + self.shipment_date = datetime.now().date() + self.shipped_by = user + self.save() + + return True + + @transaction.atomic + def cancel_order(self): + """ + Cancel this order (only if it is "pending") + + - Mark the order as 'cancelled' + - Delete any StockItems which have been allocated + """ + + if not self.status == SalesOrderStatus.PENDING: + return False + + self.status = SalesOrderStatus.CANCELLED + self.save() + + for line in self.lines.all(): + for allocation in line.allocations.all(): + allocation.delete() + + return True + class PurchaseOrderAttachment(InvenTreeAttachment): """ diff --git a/InvenTree/order/templates/order/order_cancel.html b/InvenTree/order/templates/order/order_cancel.html index 3c71028b06..91707ae737 100644 --- a/InvenTree/order/templates/order/order_cancel.html +++ b/InvenTree/order/templates/order/order_cancel.html @@ -1,7 +1,9 @@ {% extends "modal_form.html" %} +{% load i18n %} + {% block pre_form_content %} -Cancelling this order means that the order will no longer be editable. +{% 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/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html index 234a040a31..5cba99a0cb 100644 --- a/InvenTree/order/templates/order/sales_order_base.html +++ b/InvenTree/order/templates/order/sales_order_base.html @@ -27,6 +27,7 @@ src="{% static 'img/blank_image.png' %}" /> {% endblock %} + {% block page_data %}

{% trans "Sales Order" %}


@@ -40,6 +41,11 @@ src="{% static 'img/blank_image.png' %}" + {% if order.is_pending %} + + {% endif %} {% endblock %} @@ -82,11 +88,11 @@ src="{% static 'img/blank_image.png' %}" {% trans "Created" %} {{ order.creation_date }}{{ order.created_by }} - {% if order.issue_date %} + {% if order.shipment_date %} - - {% trans "Issued" %} - {{ order.issue_date }} + + {% trans "Shipped" %} + {{ order.shipment_date }}{{ order.shipped_by }} {% endif %} {% if order.status == OrderStatus.COMPLETE %} @@ -108,4 +114,10 @@ $("#edit-order").click(function() { }); }); +$("#cancel-order").click(function() { + launchModalForm("{% url 'so-cancel' order.id %}", { + reload: true, + }); +}); + {% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/sales_order_cancel.html b/InvenTree/order/templates/order/sales_order_cancel.html new file mode 100644 index 0000000000..91707ae737 --- /dev/null +++ b/InvenTree/order/templates/order/sales_order_cancel.html @@ -0,0 +1,9 @@ +{% extends "modal_form.html" %} + +{% load i18n %} + +{% block pre_form_content %} + +{% 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 87b8e9e0e4..b6b57e9518 100644 --- a/InvenTree/order/urls.py +++ b/InvenTree/order/urls.py @@ -55,6 +55,7 @@ purchase_order_urls = [ sales_order_detail_urls = [ url(r'^edit/', views.SalesOrderEdit.as_view(), name='so-edit'), + url(r'^cancel/', views.SalesOrderCancel.as_view(), name='so-cancel'), url(r'^attachments/', views.SalesOrderDetail.as_view(template_name='order/so_attachments.html'), name='so-attachments'), url(r'^notes/', views.SalesOrderNotes.as_view(), name='so-notes'), diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 79edc22bd6..9f150246b7 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -394,6 +394,38 @@ class PurchaseOrderCancel(AjaxUpdateView): return self.renderJsonResponse(request, form, data) +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 post(self, request, *args, **kwargs): + + order = self.get_object() + form = self.get_form() + + confirm = str2bool(request.POST.get('confirm', False)) + + valid = False + + if not confirm: + forms.errors['confirm'] = [_('Confirm order cancellation')] + else: + valid = True + + data = { + 'form_valid': valid, + } + + if valid: + order.cancel_order() + + return self.renderJsonResponse(request, form, data) + + class PurchaseOrderIssue(AjaxUpdateView): """ View for changing a purchase order from 'PENDING' to 'ISSUED' """ diff --git a/InvenTree/part/templatetags/status_codes.py b/InvenTree/part/templatetags/status_codes.py index 704bcd3b7c..6ede4415e2 100644 --- a/InvenTree/part/templatetags/status_codes.py +++ b/InvenTree/part/templatetags/status_codes.py @@ -30,16 +30,7 @@ def build_status(key, *args, **kwargs): return mark_safe(BuildStatus.render(key)) -@register.simple_tag(takes_context=True) -def load_status_codes(context): - """ - Make the various StatusCodes available to the page context - """ - - context['purchase_order_status_codes'] = PurchaseOrderStatus.list() - context['sales_order_status_codes'] = SalesOrderStatus.list() - context['stock_status_codes'] = StockStatus.list() - context['build_status_codes'] = BuildStatus.list() - - # Need to return something as the result is rendered to the page - return '' +@register.simple_tag +def sales_order_codes(*args, **kwargs): + print("doing") + return "hello world" \ No newline at end of file diff --git a/InvenTree/templates/table_filters.html b/InvenTree/templates/table_filters.html index ccaea8ecab..31264f461a 100644 --- a/InvenTree/templates/table_filters.html +++ b/InvenTree/templates/table_filters.html @@ -1,8 +1,6 @@ {% load i18n %} {% load status_codes %} -{% load_status_codes %} -