mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Refactor POLineItemCreate form
This commit is contained in:
parent
c524f754e9
commit
889834b693
@ -20,7 +20,7 @@ from common.forms import MatchItemForm
|
|||||||
import part.models
|
import part.models
|
||||||
|
|
||||||
from stock.models import StockLocation
|
from stock.models import StockLocation
|
||||||
from .models import PurchaseOrder, PurchaseOrderLineItem
|
from .models import PurchaseOrder
|
||||||
from .models import SalesOrder, SalesOrderLineItem
|
from .models import SalesOrder, SalesOrderLineItem
|
||||||
from .models import SalesOrderAllocation
|
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):
|
class EditSalesOrderLineItemForm(HelperForm):
|
||||||
""" Form for editing a SalesOrderLineItem object """
|
""" Form for editing a SalesOrderLineItem object """
|
||||||
|
|
||||||
|
@ -350,7 +350,7 @@ class SOLineItemSerializer(InvenTreeModelSerializer):
|
|||||||
max_digits=19,
|
max_digits=19,
|
||||||
decimal_places=4,
|
decimal_places=4,
|
||||||
allow_null=True
|
allow_null=True
|
||||||
)
|
)
|
||||||
|
|
||||||
sale_price_string = serializers.CharField(source='sale_price', read_only=True)
|
sale_price_string = serializers.CharField(source='sale_price', read_only=True)
|
||||||
|
|
||||||
|
@ -38,26 +38,34 @@
|
|||||||
|
|
||||||
{% if order.status == PurchaseOrderStatus.PENDING %}
|
{% if order.status == PurchaseOrderStatus.PENDING %}
|
||||||
$('#new-po-line').click(function() {
|
$('#new-po-line').click(function() {
|
||||||
launchModalForm("{% url 'po-line-item-create' %}",
|
|
||||||
{
|
|
||||||
reload: true,
|
constructForm('{% url "api-po-line-list" %}', {
|
||||||
data: {
|
fields: {
|
||||||
order: {{ order.id }},
|
order: {
|
||||||
|
value: {{ order.pk }},
|
||||||
|
hidden: true,
|
||||||
},
|
},
|
||||||
secondary: [
|
part: {
|
||||||
{
|
filters: {
|
||||||
field: 'part',
|
part_detail: true,
|
||||||
label: '{% trans "New Supplier Part" %}',
|
supplier_detail: true,
|
||||||
title: '{% trans "Create new supplier part" %}',
|
supplier: {{ order.supplier.pk }},
|
||||||
url: "{% url 'supplier-part-create' %}",
|
|
||||||
data: {
|
|
||||||
supplier: {{ order.supplier.id }},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
}
|
quantity: {},
|
||||||
);
|
reference: {},
|
||||||
|
purchase_price: {},
|
||||||
|
purchase_price_currency: {},
|
||||||
|
destination: {},
|
||||||
|
notes: {},
|
||||||
|
},
|
||||||
|
method: 'POST',
|
||||||
|
title: '{% trans "Add Line Item" %}',
|
||||||
|
onSuccess: reloadTable,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
function reloadTable() {
|
function reloadTable() {
|
||||||
@ -77,6 +85,7 @@ function setupCallbacks() {
|
|||||||
fields: {
|
fields: {
|
||||||
part: {
|
part: {
|
||||||
filters: {
|
filters: {
|
||||||
|
part_detail: true,
|
||||||
supplier_detail: true,
|
supplier_detail: true,
|
||||||
supplier: {{ order.supplier.pk }},
|
supplier: {{ order.supplier.pk }},
|
||||||
}
|
}
|
||||||
|
@ -104,57 +104,6 @@ class POTests(OrderViewTestCase):
|
|||||||
order = PurchaseOrder.objects.get(pk=1)
|
order = PurchaseOrder.objects.get(pk=1)
|
||||||
self.assertEqual(order.status, PurchaseOrderStatus.PLACED)
|
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):
|
class TestPOReceive(OrderViewTestCase):
|
||||||
""" Tests for receiving a purchase order """
|
""" Tests for receiving a purchase order """
|
||||||
|
@ -1049,90 +1049,6 @@ class OrderParts(AjaxView):
|
|||||||
order.add_line_item(supplier_part, quantity, purchase_price=purchase_price)
|
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):
|
class SOLineItemCreate(AjaxCreateView):
|
||||||
""" Ajax view for creating a new SalesOrderLineItem object """
|
""" Ajax view for creating a new SalesOrderLineItem object """
|
||||||
|
|
||||||
|
@ -145,9 +145,11 @@ function renderSupplierPart(name, data, parameters, options) {
|
|||||||
var html = `<img src='${image}' class='select2-thumbnail'>`;
|
var html = `<img src='${image}' class='select2-thumbnail'>`;
|
||||||
|
|
||||||
html += ` <span><b>${data.supplier_detail.name}</b> - ${data.SKU}</span>`;
|
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>`;
|
html += `<span class='float-right'>{% trans "Supplier Part ID" %}: ${data.pk}</span>`;
|
||||||
|
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user