Add functionality to cancel a sales order

This commit is contained in:
Oliver Walters 2020-04-23 21:38:40 +10:00
parent e384f9e94c
commit e5fa94b4f8
9 changed files with 116 additions and 20 deletions

View File

@ -52,6 +52,17 @@ class CancelPurchaseOrderForm(HelperForm):
]
class CancelSalesOrderForm(HelperForm):
confirm = forms.BooleanField(required=False, help_text=_('Cancel order'))
class Meta:
model = SalesOrder
fields = [
'confirm',
]
class ReceivePurchaseOrderForm(HelperForm):
location = TreeNodeChoiceField(queryset=StockLocation.objects.all(), required=True, help_text=_('Receive parts to this location'))

View File

@ -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):
"""

View File

@ -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 %}

View File

@ -27,6 +27,7 @@ src="{% static 'img/blank_image.png' %}"
/>
{% endblock %}
{% block page_data %}
<h3>{% trans "Sales Order" %}</h3>
<hr>
@ -40,6 +41,11 @@ src="{% static 'img/blank_image.png' %}"
<button type='button' class='btn btn-default' id='packing-list' title='{% trans "Packing List" %}'>
<span class='fas fa-clipboard-list'></span>
</button>
{% if order.is_pending %}
<button type='button' class='btn btn-default' id='cancel-order' title='{% trans "Cancel order" %}'>
<span class='fas fa-times-circle icon-red'></span>
</button>
{% endif %}
</div>
</div>
{% endblock %}
@ -82,11 +88,11 @@ src="{% static 'img/blank_image.png' %}"
<td>{% trans "Created" %}</td>
<td>{{ order.creation_date }}<span class='badge'>{{ order.created_by }}</span></td>
</tr>
{% if order.issue_date %}
{% if order.shipment_date %}
<tr>
<td><span class='fas fa-calendar-alt'></span></td>
<td>{% trans "Issued" %}</td>
<td>{{ order.issue_date }}</td>
<td><span class='fas fa-truck'></span></td>
<td>{% trans "Shipped" %}</td>
<td>{{ order.shipment_date }}<span class='badge'>{{ order.shipped_by }}</span></td>
</tr>
{% 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 %}

View File

@ -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 %}

View File

@ -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'),

View File

@ -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' """

View File

@ -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"

View File

@ -1,8 +1,6 @@
{% load i18n %}
{% load status_codes %}
{% load_status_codes %}
<script type='text/javascript'>
{% include "status_codes.html" with label='stock' options=stock_status_codes %}