Form for shipping a SalesOrder

- Returns "False" for now
This commit is contained in:
Oliver Walters 2020-04-24 10:20:56 +10:00
parent b45fec221c
commit 77471cb89c
13 changed files with 155 additions and 14 deletions

View File

@ -125,7 +125,7 @@ class BuildAutoAllocate(AjaxUpdateView):
if confirm is False: if confirm is False:
form.errors['confirm'] = [_('Confirm stock allocation')] form.errors['confirm'] = [_('Confirm stock allocation')]
form.non_field_errors = _('Check the confirmation box at the bottom of the list') form.non_field_errors = [_('Check the confirmation box at the bottom of the list')]
else: else:
build.autoAllocate() build.autoAllocate()
valid = True valid = True
@ -159,7 +159,7 @@ class BuildUnallocate(AjaxUpdateView):
if confirm is False: if confirm is False:
form.errors['confirm'] = [_('Confirm unallocation of build stock')] form.errors['confirm'] = [_('Confirm unallocation of build stock')]
form.non_field_errors = _('Check the confirmation box') form.non_field_errors = [_('Check the confirmation box')]
else: else:
build.unallocateStock() build.unallocateStock()
valid = True valid = True

View File

@ -63,6 +63,17 @@ class CancelSalesOrderForm(HelperForm):
] ]
class ShipSalesOrderForm(HelperForm):
confirm = forms.BooleanField(required=False, help_text=_('Ship 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'))

View File

@ -302,10 +302,21 @@ class SalesOrder(Order):
return True return True
def is_over_allocated(self):
""" Return true if any lines in the order are over-allocated """
for line in self.lines.all():
if line.is_over_allocated():
return True
return False
@transaction.atomic @transaction.atomic
def ship_order(self, user): def ship_order(self, user):
""" Mark this order as 'shipped' """ """ Mark this order as 'shipped' """
return False
if not self.status == SalesOrderStatus.PENDING: if not self.status == SalesOrderStatus.PENDING:
return False return False
@ -447,6 +458,10 @@ class SalesOrderLineItem(OrderLineItem):
return query['allocated'] return query['allocated']
def is_fully_allocated(self): def is_fully_allocated(self):
print("Line:", self.pk)
print("Allocated:", self.allocated_quantity())
print("Quantity:", self.quantity)
return self.allocated_quantity() >= self.quantity return self.allocated_quantity() >= self.quantity
def is_over_allocated(self): def is_over_allocated(self):

View File

@ -124,4 +124,10 @@ $("#cancel-order").click(function() {
}); });
}); });
$("#ship-order").click(function() {
launchModalForm("{% url 'so-ship' order.id %}", {
reload: true,
});
});
{% endblock %} {% endblock %}

View File

@ -4,6 +4,9 @@
{% block pre_form_content %} {% block pre_form_content %}
<div class='alert alert-block alert-warning'>
<h4>{% trans "Warning" %}</h4>
{% trans "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." %}
</div>
{% endblock %} {% endblock %}

View File

@ -23,9 +23,13 @@
{% block js_ready %} {% block js_ready %}
{{ block.super }} {{ block.super }}
function reloadTable() {
$("#so-lines-table").bootstrapTable("refresh");
}
$("#new-so-line").click(function() { $("#new-so-line").click(function() {
launchModalForm("{% url 'so-line-item-create' %}", { launchModalForm("{% url 'so-line-item-create' %}", {
reload: true, success: reloadTable,
data: { data: {
order: {{ order.id }}, order: {{ order.id }},
}, },
@ -200,10 +204,6 @@ $("#so-lines-table").inventreeTable({
], ],
}); });
function reloadTable() {
$("#so-lines-table").bootstrapTable("refresh");
}
function setupCallbacks(table) { function setupCallbacks(table) {
var table = $("#so-lines-table"); var table = $("#so-lines-table");

View File

@ -0,0 +1,28 @@
{% extends "modal_form.html" %}
{% load i18n %}
{% block pre_form_content %}
{% if not order.is_fully_allocated %}
<div class='alert alert-block alert-danger'>
<h4>{% trans "Warning" %}</h4>
{% trans "This order has not been fully allocated. If the order is marked as shipped, it can no longer be adjusted." %}
<br>
{% trans "Ensure that the order allocation is correct before shipping the order." %}
</div>
{% endif %}
{% if order.is_over_allocated %}
<div class='alert alert-block alert-warning'>
{% trans "Some line items in this order have been over-allocated" %}
<br>
{% trans "Ensure that this is correct before shipping the order." %}
</div>
{% endif %}
<div class='alert alert-block alert-info'>
{% trans "Shipping this order means that the order will no longer be editable." %}
</div>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% extends "modal_delete_form.html" %}
{% load i18n %}
{% load inventree_extras %}
{% block pre_form_content %}
<div class='alert alert-block alert-warning'>
{% trans "This action will unallocate the following stock from the Sales Order" %}:
<br>
<b>
{% decimal allocation.get_allocated %} x {{ allocation.line.part.full_name }}
{% if allocation.item.location %} ({{ allocation.get_location }}){% endif %}
</b>
</div>
{% endblock %}

View File

@ -1,5 +1,6 @@
{% extends "modal_delete_form.html" %} {% extends "modal_delete_form.html" %}
{% load i18n %}
{% block pre_form_content %} {% block pre_form_content %}
Are you sure you wish to delete this line item? {% trans "Are you sure you wish to delete this line item?" %}
{% endblock %} {% endblock %}

View File

@ -56,6 +56,7 @@ 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'^cancel/', views.SalesOrderCancel.as_view(), name='so-cancel'),
url(r'^ship/', views.SalesOrderShip.as_view(), name='so-ship'),
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'),

View File

@ -416,13 +416,16 @@ class SalesOrderCancel(AjaxUpdateView):
else: else:
valid = True valid = True
if valid:
if not order.cancel_order():
form.non_field_errors = [_('Could not cancel order')]
valid = False
data = { data = {
'form_valid': valid, 'form_valid': valid,
} }
if valid:
order.cancel_order()
return self.renderJsonResponse(request, form, data) return self.renderJsonResponse(request, form, data)
@ -495,6 +498,47 @@ class PurchaseOrderComplete(AjaxUpdateView):
return self.renderJsonResponse(request, form, data) return self.renderJsonResponse(request, form, data)
class SalesOrderShip(AjaxUpdateView):
""" View for 'shipping' a SalesOrder """
form_class = order_forms.ShipSalesOrderForm
model = SalesOrder
context_object_name = 'order'
ajax_template_name = 'order/sales_order_ship.html'
ajax_form_title = _('Ship Order')
def context_data(self):
ctx = super().get_context_data()
ctx['order'] = self.get_object()
return ctx
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:
form.errors['confirm'] = [_('Confirm order shipment')]
else:
valid = True
if valid:
if not order.ship_order(request.user):
form.non_field_errors = [_('Could not ship order')]
valid = False
data = {
'form_valid': valid,
}
return self.renderJsonResponse(request, form, data)
class PurchaseOrderExport(AjaxView): class PurchaseOrderExport(AjaxView):
""" File download for a purchase order """ File download for a purchase order
@ -1111,6 +1155,18 @@ class SOLineItemCreate(AjaxCreateView):
form_class = order_forms.EditSalesOrderLineItemForm form_class = order_forms.EditSalesOrderLineItemForm
ajax_form_title = _('Add Line Item') ajax_form_title = _('Add Line Item')
def get_form(self, *args, **kwargs):
form = super().get_form(*args, **kwargs)
# If the order is specified, hide the widget
order_id = form['order'].value()
if SalesOrder.objects.filter(id=order_id).exists():
form.fields['order'].widget = HiddenInput()
return form
def get_initial(self): def get_initial(self):
""" """
Extract initial data for this line item: Extract initial data for this line item:
@ -1293,3 +1349,5 @@ class SalesOrderAllocationDelete(AjaxDeleteView):
model = SalesOrderAllocation model = SalesOrderAllocation
ajax_form_title = _("Remove allocation") ajax_form_title = _("Remove allocation")
context_object_name = 'allocation'
ajax_template_name = "order/so_allocation_delete.html"

View File

@ -731,7 +731,7 @@ class StockItemSerialize(AjaxUpdateView):
if k in ['quantity', 'destination', 'serial_numbers']: if k in ['quantity', 'destination', 'serial_numbers']:
form.errors[k] = messages[k] form.errors[k] = messages[k]
else: else:
form.non_field_errors = messages[k] form.non_field_errors = [messages[k]]
valid = False valid = False

View File

@ -13,7 +13,11 @@
{% if form.non_field_errors %} {% if form.non_field_errors %}
<div class='alert alert-danger alert-block' role='alert'> <div class='alert alert-danger alert-block' role='alert'>
<b>Error Submitting Form:</b> <b>Error Submitting Form:</b>
{{ form.non_field_errors }} <ul>
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</ul>
</div> </div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}