2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-17 20:45:44 +00:00

Merge remote-tracking branch 'inventree/master' into build-fixes

# Conflicts:
#	InvenTree/InvenTree/views.py
#	InvenTree/build/views.py
#	InvenTree/locale/de/LC_MESSAGES/django.po
#	InvenTree/locale/en/LC_MESSAGES/django.po
#	InvenTree/locale/es/LC_MESSAGES/django.po
#	InvenTree/order/views.py
#	InvenTree/part/api.py
#	InvenTree/part/views.py
#	InvenTree/templates/js/bom.js
This commit is contained in:
Oliver Walters
2020-10-30 22:44:25 +11:00
20 changed files with 1467 additions and 1132 deletions

View File

@ -21,7 +21,7 @@ from .models import SalesOrderAllocation
class IssuePurchaseOrderForm(HelperForm):
confirm = forms.BooleanField(required=False, help_text=_('Place order'))
confirm = forms.BooleanField(required=True, initial=False, help_text=_('Place order'))
class Meta:
model = PurchaseOrder
@ -32,7 +32,7 @@ class IssuePurchaseOrderForm(HelperForm):
class CompletePurchaseOrderForm(HelperForm):
confirm = forms.BooleanField(required=False, help_text=_("Mark order as complete"))
confirm = forms.BooleanField(required=True, help_text=_("Mark order as complete"))
class Meta:
model = PurchaseOrder
@ -43,7 +43,7 @@ class CompletePurchaseOrderForm(HelperForm):
class CancelPurchaseOrderForm(HelperForm):
confirm = forms.BooleanField(required=False, help_text=_('Cancel order'))
confirm = forms.BooleanField(required=True, help_text=_('Cancel order'))
class Meta:
model = PurchaseOrder
@ -54,7 +54,7 @@ class CancelPurchaseOrderForm(HelperForm):
class CancelSalesOrderForm(HelperForm):
confirm = forms.BooleanField(required=False, help_text=_('Cancel order'))
confirm = forms.BooleanField(required=True, help_text=_('Cancel order'))
class Meta:
model = SalesOrder
@ -65,7 +65,7 @@ class CancelSalesOrderForm(HelperForm):
class ShipSalesOrderForm(HelperForm):
confirm = forms.BooleanField(required=False, help_text=_('Ship order'))
confirm = forms.BooleanField(required=True, help_text=_('Ship order'))
class Meta:
model = SalesOrder

View File

@ -209,6 +209,7 @@ class PurchaseOrder(Order):
line.save()
@transaction.atomic
def place_order(self):
""" Marks the PurchaseOrder as PLACED. Order must be currently PENDING. """
@ -217,6 +218,7 @@ class PurchaseOrder(Order):
self.issue_date = datetime.now().date()
self.save()
@transaction.atomic
def complete_order(self):
""" Marks the PurchaseOrder as COMPLETE. Order must be currently PLACED. """
@ -225,10 +227,16 @@ class PurchaseOrder(Order):
self.complete_date = datetime.now().date()
self.save()
def can_cancel(self):
return self.status not in [
PurchaseOrderStatus.PLACED,
PurchaseOrderStatus.PENDING
]
def cancel_order(self):
""" Marks the PurchaseOrder as CANCELLED. """
if self.status in [PurchaseOrderStatus.PLACED, PurchaseOrderStatus.PENDING]:
if self.can_cancel():
self.status = PurchaseOrderStatus.CANCELLED
self.save()
@ -377,6 +385,16 @@ class SalesOrder(Order):
return True
def can_cancel(self):
"""
Return True if this order can be cancelled
"""
if not self.status == SalesOrderStatus.PENDING:
return False
return True
@transaction.atomic
def cancel_order(self):
"""
@ -386,7 +404,7 @@ class SalesOrder(Order):
- Delete any StockItems which have been allocated
"""
if not self.status == SalesOrderStatus.PENDING:
if not self.can_cancel():
return False
self.status = SalesOrderStatus.CANCELLED

View File

@ -113,6 +113,7 @@ class POTests(OrderViewTestCase):
self.assertEqual(response.status_code, 200)
data = json.loads(response.content)
self.assertFalse(data['form_valid'])
# Test WITH confirmation
@ -151,7 +152,6 @@ class POTests(OrderViewTestCase):
response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
data = json.loads(response.content)
self.assertFalse(data['form_valid'])
self.assertIn('Invalid Purchase Order', str(data['html_form']))
# POST with a part that does not match the purchase order
post_data['order'] = 1
@ -159,14 +159,12 @@ class POTests(OrderViewTestCase):
response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
data = json.loads(response.content)
self.assertFalse(data['form_valid'])
self.assertIn('must match for Part and Order', str(data['html_form']))
# POST with an invalid part
post_data['part'] = 12345
response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
data = json.loads(response.content)
self.assertFalse(data['form_valid'])
self.assertIn('Invalid SupplierPart selection', str(data['html_form']))
# POST the form with valid data
post_data['part'] = 100

View File

@ -100,9 +100,9 @@ class PurchaseOrderAttachmentCreate(AjaxCreateView):
ajax_template_name = "modal_form.html"
role_required = 'purchase_order.add'
def post_save(self, **kwargs):
self.object.user = self.request.user
self.object.save()
def post_save(self, attachment, form, **kwargs):
attachment.user = self.request.user
attachment.save()
def get_data(self):
return {
@ -148,7 +148,7 @@ class SalesOrderAttachmentCreate(AjaxCreateView):
ajax_form_title = _('Add Sales Order Attachment')
role_required = 'sales_order.add'
def post_save(self, **kwargs):
def post_save(self, attachment, form, **kwargs):
self.object.user = self.request.user
self.object.save()
@ -319,11 +319,11 @@ class PurchaseOrderCreate(AjaxCreateView):
return initials
def post_save(self, **kwargs):
def post_save(self, order, form, **kwargs):
# Record the user who created this purchase order
self.object.created_by = self.request.user
self.object.save()
order.created_by = self.request.user
order.save()
class SalesOrderCreate(AjaxCreateView):
@ -351,10 +351,10 @@ class SalesOrderCreate(AjaxCreateView):
return initials
def post_save(self, **kwargs):
def post_save(self, order, form, **kwargs):
# Record the user who created this sales order
self.object.created_by = self.request.user
self.object.save()
order.created_by = self.request.user
order.save()
class PurchaseOrderEdit(AjaxUpdateView):
@ -404,29 +404,19 @@ class PurchaseOrderCancel(AjaxUpdateView):
form_class = order_forms.CancelPurchaseOrderForm
role_required = 'purchase_order.change'
def post(self, request, *args, **kwargs):
""" Mark the PO as 'CANCELLED' """
order = self.get_object()
form = self.get_form()
confirm = str2bool(request.POST.get('confirm', False))
valid = False
def validate(self, order, form, **kwargs):
confirm = str2bool(form.cleaned_data.get('confirm', False))
if not confirm:
form.add_error('confirm', _('Confirm order cancellation'))
else:
valid = True
data = {
'form_valid': valid
}
if not order.can_cancel():
form.add_error(None, _('Order cannot be cancelled'))
if valid:
order.cancel_order()
def post_save(self, order, form, **kwargs):
return self.renderJsonResponse(request, form, data)
order.cancel_order()
class SalesOrderCancel(AjaxUpdateView):
@ -438,30 +428,19 @@ class SalesOrderCancel(AjaxUpdateView):
form_class = order_forms.CancelSalesOrderForm
role_required = 'sales_order.change'
def post(self, request, *args, **kwargs):
def validate(self, order, form, **kwargs):
order = self.get_object()
form = self.get_form()
confirm = str2bool(request.POST.get('confirm', False))
valid = False
confirm = str2bool(form.cleaned_data.get('confirm', False))
if not confirm:
form.add_error('confirm', _('Confirm order cancellation'))
else:
valid = True
if valid:
if not order.cancel_order():
form.add_error(None, _('Could not cancel order'))
valid = False
if not order.can_cancel():
form.add_error(None, _('Order cannot be cancelled'))
data = {
'form_valid': valid,
}
def post_save(self, order, form, **kwargs):
return self.renderJsonResponse(request, form, data)
order.cancel_order()
class PurchaseOrderIssue(AjaxUpdateView):
@ -473,30 +452,22 @@ class PurchaseOrderIssue(AjaxUpdateView):
form_class = order_forms.IssuePurchaseOrderForm
role_required = 'purchase_order.change'
def post(self, request, *args, **kwargs):
""" Mark the purchase order as 'PLACED' """
def validate(self, order, form, **kwargs):
order = self.get_object()
form = self.get_form()
confirm = str2bool(request.POST.get('confirm', False))
valid = False
confirm = str2bool(self.request.POST.get('confirm', False))
if not confirm:
form.add_error('confirm', _('Confirm order placement'))
else:
valid = True
data = {
'form_valid': valid,
def post_save(self, order, form, **kwargs):
order.place_order()
def get_data(self):
return {
'success': _('Purchase order issued')
}
if valid:
order.place_order()
return self.renderJsonResponse(request, form, data)
class PurchaseOrderComplete(AjaxUpdateView):
""" View for marking a PurchaseOrder as complete.
@ -517,23 +488,22 @@ class PurchaseOrderComplete(AjaxUpdateView):
return ctx
def post(self, request, *args, **kwargs):
def validate(self, order, form, **kwargs):
confirm = str2bool(request.POST.get('confirm', False))
confirm = str2bool(form.cleaned_data.get('confirm', False))
if confirm:
po = self.get_object()
po.status = PurchaseOrderStatus.COMPLETE
po.save()
if not confirm:
form.add_error('confirm', _('Confirm order completion'))
data = {
'form_valid': confirm
def post_save(self, order, form, **kwargs):
order.complete_order()
def get_data(self):
return {
'success': _('Purchase order completed')
}
form = self.get_form()
return self.renderJsonResponse(request, form, data)
class SalesOrderShip(AjaxUpdateView):
""" View for 'shipping' a SalesOrder """
@ -1117,52 +1087,21 @@ class POLineItemCreate(AjaxCreateView):
ajax_form_title = _('Add Line Item')
role_required = 'purchase_order.add'
def post(self, request, *arg, **kwargs):
def validate(self, item, form, **kwargs):
self.request = request
order = form.cleaned_data.get('order', None)
form = self.get_form()
part = form.cleaned_data.get('part', None)
valid = form.is_valid()
if not part:
form.add_error('part', _('Supplier part must be specified'))
# Extract the SupplierPart ID from the form
part_id = form['part'].value()
# Extract the Order ID from the form
order_id = form['order'].value()
try:
order = PurchaseOrder.objects.get(id=order_id)
except (ValueError, PurchaseOrder.DoesNotExist):
order = None
form.add_error('order', _('Invalid Purchase Order'))
valid = False
try:
sp = SupplierPart.objects.get(id=part_id)
if order is not None:
if not sp.supplier == order.supplier:
form.add_error('part', _('Supplier must match for Part and Order'))
valid = False
except (SupplierPart.DoesNotExist, ValueError):
valid = False
form.add_error('part', _('Invalid SupplierPart selection'))
data = {
'form_valid': valid,
}
if valid:
self.object = form.save()
data['pk'] = self.object.pk
data['text'] = str(self.object)
else:
self.object = None
return self.renderJsonResponse(request, form, data,)
if part and order:
if not part.supplier == order.supplier:
form.add_error(
'part',
_('Supplier must match for Part and Order')
)
def get_form(self):
""" Limit choice options based on the selected order, etc