Refactor POLineItemCreate form

This commit is contained in:
Oliver 2021-07-03 21:43:22 +10:00
parent c524f754e9
commit 889834b693
6 changed files with 30 additions and 172 deletions

View File

@ -20,7 +20,7 @@ from common.forms import MatchItemForm
import part.models
from stock.models import StockLocation
from .models import PurchaseOrder, PurchaseOrderLineItem
from .models import PurchaseOrder
from .models import SalesOrder, SalesOrderLineItem
from .models import SalesOrderAllocation
@ -96,24 +96,6 @@ class ReceivePurchaseOrderForm(HelperForm):
]
class EditPurchaseOrderLineItemForm(HelperForm):
""" Form for editing a PurchaseOrderLineItem object """
quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5, label=_('Quantity'))
class Meta:
model = PurchaseOrderLineItem
fields = [
'order',
'part',
'quantity',
'reference',
'purchase_price',
'destination',
'notes',
]
class EditSalesOrderLineItemForm(HelperForm):
""" Form for editing a SalesOrderLineItem object """

View File

@ -38,26 +38,34 @@
{% if order.status == PurchaseOrderStatus.PENDING %}
$('#new-po-line').click(function() {
launchModalForm("{% url 'po-line-item-create' %}",
{
reload: true,
data: {
order: {{ order.id }},
constructForm('{% url "api-po-line-list" %}', {
fields: {
order: {
value: {{ order.pk }},
hidden: true,
},
secondary: [
{
field: 'part',
label: '{% trans "New Supplier Part" %}',
title: '{% trans "Create new supplier part" %}',
url: "{% url 'supplier-part-create' %}",
data: {
supplier: {{ order.supplier.id }},
part: {
filters: {
part_detail: true,
supplier_detail: true,
supplier: {{ order.supplier.pk }},
},
},
],
}
);
quantity: {},
reference: {},
purchase_price: {},
purchase_price_currency: {},
destination: {},
notes: {},
},
method: 'POST',
title: '{% trans "Add Line Item" %}',
onSuccess: reloadTable,
});
});
{% endif %}
function reloadTable() {
@ -77,6 +85,7 @@ function setupCallbacks() {
fields: {
part: {
filters: {
part_detail: true,
supplier_detail: true,
supplier: {{ order.supplier.pk }},
}

View File

@ -104,57 +104,6 @@ class POTests(OrderViewTestCase):
order = PurchaseOrder.objects.get(pk=1)
self.assertEqual(order.status, PurchaseOrderStatus.PLACED)
def test_line_item_create(self):
""" Test the form for adding a new LineItem to a PurchaseOrder """
# Record the number of line items in the PurchaseOrder
po = PurchaseOrder.objects.get(pk=1)
n = po.lines.count()
self.assertEqual(po.status, PurchaseOrderStatus.PENDING)
url = reverse('po-line-item-create')
# GET the form (pass the correct info)
response = self.client.get(url, {'order': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
post_data = {
'part': 100,
'quantity': 45,
'reference': 'Test reference field',
'notes': 'Test notes field'
}
# POST with an invalid purchase order
post_data['order'] = 99
response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
data = json.loads(response.content)
self.assertFalse(data['form_valid'])
# POST with a part that does not match the purchase order
post_data['order'] = 1
post_data['part'] = 7
response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
data = json.loads(response.content)
self.assertFalse(data['form_valid'])
# 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'])
# POST the form with valid data
post_data['part'] = 100
response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
data = json.loads(response.content)
self.assertTrue(data['form_valid'])
self.assertEqual(n + 1, PurchaseOrder.objects.get(pk=1).lines.count())
line = PurchaseOrderLineItem.objects.get(order=1, part=100)
self.assertEqual(line.quantity, 45)
class TestPOReceive(OrderViewTestCase):
""" Tests for receiving a purchase order """

View File

@ -1049,90 +1049,6 @@ class OrderParts(AjaxView):
order.add_line_item(supplier_part, quantity, purchase_price=purchase_price)
class POLineItemCreate(AjaxCreateView):
""" AJAX view for creating a new PurchaseOrderLineItem object
"""
model = PurchaseOrderLineItem
context_object_name = 'line'
form_class = order_forms.EditPurchaseOrderLineItemForm
ajax_form_title = _('Add Line Item')
def validate(self, item, form, **kwargs):
order = form.cleaned_data.get('order', None)
part = form.cleaned_data.get('part', None)
if not part:
form.add_error('part', _('Supplier part must be specified'))
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
"""
form = super().get_form()
# Limit the available to orders to ones that are PENDING
query = form.fields['order'].queryset
query = query.filter(status=PurchaseOrderStatus.PENDING)
form.fields['order'].queryset = query
order_id = form['order'].value()
try:
order = PurchaseOrder.objects.get(id=order_id)
query = form.fields['part'].queryset
# Only allow parts from the selected supplier
query = query.filter(supplier=order.supplier.id)
exclude = []
for line in order.lines.all():
if line.part and line.part.id not in exclude:
exclude.append(line.part.id)
# Remove parts that are already in the order
query = query.exclude(id__in=exclude)
form.fields['part'].queryset = query
form.fields['order'].widget = HiddenInput()
except (ValueError, PurchaseOrder.DoesNotExist):
pass
return form
def get_initial(self):
""" Extract initial data for the line item.
- The 'order' will be passed as a query parameter
- Use this to set the 'order' field and limit the options for 'part'
"""
initials = super().get_initial().copy()
order_id = self.request.GET.get('order', None)
if order_id:
try:
order = PurchaseOrder.objects.get(id=order_id)
initials['order'] = order
except (PurchaseOrder.DoesNotExist, ValueError):
pass
return initials
class SOLineItemCreate(AjaxCreateView):
""" Ajax view for creating a new SalesOrderLineItem object """

View File

@ -145,9 +145,11 @@ function renderSupplierPart(name, data, parameters, options) {
var html = `<img src='${image}' class='select2-thumbnail'>`;
html += ` <span><b>${data.supplier_detail.name}</b> - ${data.SKU}</span>`;
html += ` - <i>${data.part_detail.full_name}</i>`;
html += `<span class='float-right'>{% trans "Supplier Part ID" %}: ${data.pk}</span>`;
return html;
}