mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add functionality to cancel a sales order
This commit is contained in:
parent
e384f9e94c
commit
e5fa94b4f8
@ -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):
|
class ReceivePurchaseOrderForm(HelperForm):
|
||||||
|
|
||||||
location = TreeNodeChoiceField(queryset=StockLocation.objects.all(), required=True, help_text=_('Receive parts to this location'))
|
location = TreeNodeChoiceField(queryset=StockLocation.objects.all(), required=True, help_text=_('Receive parts to this location'))
|
||||||
|
@ -289,6 +289,10 @@ class SalesOrder(Order):
|
|||||||
related_name='+'
|
related_name='+'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_pending(self):
|
||||||
|
return self.status == SalesOrderStatus.PENDING
|
||||||
|
|
||||||
def is_fully_allocated(self):
|
def is_fully_allocated(self):
|
||||||
""" Return True if all line items are fully allocated """
|
""" Return True if all line items are fully allocated """
|
||||||
|
|
||||||
@ -298,6 +302,42 @@ class SalesOrder(Order):
|
|||||||
|
|
||||||
return True
|
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):
|
class PurchaseOrderAttachment(InvenTreeAttachment):
|
||||||
"""
|
"""
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
{% extends "modal_form.html" %}
|
{% extends "modal_form.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
{% block pre_form_content %}
|
{% 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 %}
|
{% endblock %}
|
@ -27,6 +27,7 @@ src="{% static 'img/blank_image.png' %}"
|
|||||||
/>
|
/>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block page_data %}
|
{% block page_data %}
|
||||||
<h3>{% trans "Sales Order" %}</h3>
|
<h3>{% trans "Sales Order" %}</h3>
|
||||||
<hr>
|
<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" %}'>
|
<button type='button' class='btn btn-default' id='packing-list' title='{% trans "Packing List" %}'>
|
||||||
<span class='fas fa-clipboard-list'></span>
|
<span class='fas fa-clipboard-list'></span>
|
||||||
</button>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -82,11 +88,11 @@ src="{% static 'img/blank_image.png' %}"
|
|||||||
<td>{% trans "Created" %}</td>
|
<td>{% trans "Created" %}</td>
|
||||||
<td>{{ order.creation_date }}<span class='badge'>{{ order.created_by }}</span></td>
|
<td>{{ order.creation_date }}<span class='badge'>{{ order.created_by }}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% if order.issue_date %}
|
{% if order.shipment_date %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-calendar-alt'></span></td>
|
<td><span class='fas fa-truck'></span></td>
|
||||||
<td>{% trans "Issued" %}</td>
|
<td>{% trans "Shipped" %}</td>
|
||||||
<td>{{ order.issue_date }}</td>
|
<td>{{ order.shipment_date }}<span class='badge'>{{ order.shipped_by }}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if order.status == OrderStatus.COMPLETE %}
|
{% 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 %}
|
{% endblock %}
|
9
InvenTree/order/templates/order/sales_order_cancel.html
Normal file
9
InvenTree/order/templates/order/sales_order_cancel.html
Normal 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 %}
|
@ -55,6 +55,7 @@ purchase_order_urls = [
|
|||||||
sales_order_detail_urls = [
|
sales_order_detail_urls = [
|
||||||
|
|
||||||
url(r'^edit/', views.SalesOrderEdit.as_view(), name='so-edit'),
|
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'^attachments/', views.SalesOrderDetail.as_view(template_name='order/so_attachments.html'), name='so-attachments'),
|
||||||
url(r'^notes/', views.SalesOrderNotes.as_view(), name='so-notes'),
|
url(r'^notes/', views.SalesOrderNotes.as_view(), name='so-notes'),
|
||||||
|
@ -394,6 +394,38 @@ class PurchaseOrderCancel(AjaxUpdateView):
|
|||||||
return self.renderJsonResponse(request, form, data)
|
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):
|
class PurchaseOrderIssue(AjaxUpdateView):
|
||||||
""" View for changing a purchase order from 'PENDING' to 'ISSUED' """
|
""" View for changing a purchase order from 'PENDING' to 'ISSUED' """
|
||||||
|
|
||||||
|
@ -30,16 +30,7 @@ def build_status(key, *args, **kwargs):
|
|||||||
return mark_safe(BuildStatus.render(key))
|
return mark_safe(BuildStatus.render(key))
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag(takes_context=True)
|
@register.simple_tag
|
||||||
def load_status_codes(context):
|
def sales_order_codes(*args, **kwargs):
|
||||||
"""
|
print("doing")
|
||||||
Make the various StatusCodes available to the page context
|
return "hello world"
|
||||||
"""
|
|
||||||
|
|
||||||
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 ''
|
|
@ -1,8 +1,6 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load status_codes %}
|
{% load status_codes %}
|
||||||
|
|
||||||
{% load_status_codes %}
|
|
||||||
|
|
||||||
<script type='text/javascript'>
|
<script type='text/javascript'>
|
||||||
|
|
||||||
{% include "status_codes.html" with label='stock' options=stock_status_codes %}
|
{% include "status_codes.html" with label='stock' options=stock_status_codes %}
|
||||||
|
Loading…
Reference in New Issue
Block a user