mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Oopsy forgot to merge PurchaseOrderUpload view
This commit is contained in:
parent
88000200b3
commit
9b69980a6c
@ -25,7 +25,7 @@ from .models import SalesOrder, SalesOrderLineItem, SalesOrderAttachment
|
|||||||
from .models import SalesOrderAllocation
|
from .models import SalesOrderAllocation
|
||||||
from .admin import POLineItemResource
|
from .admin import POLineItemResource
|
||||||
from build.models import Build
|
from build.models import Build
|
||||||
from company.models import Company, SupplierPart
|
from company.models import Company, SupplierPart # ManufacturerPart
|
||||||
from stock.models import StockItem, StockLocation
|
from stock.models import StockItem, StockLocation
|
||||||
from part.models import Part
|
from part.models import Part
|
||||||
|
|
||||||
@ -569,6 +569,165 @@ class SalesOrderShip(AjaxUpdateView):
|
|||||||
return self.renderJsonResponse(request, form, data, context)
|
return self.renderJsonResponse(request, form, data, context)
|
||||||
|
|
||||||
|
|
||||||
|
class PurchaseOrderUpload(FileManagementFormView):
|
||||||
|
''' PurchaseOrder: Upload file, match to fields and parts (using multi-Step form) '''
|
||||||
|
|
||||||
|
name = 'order'
|
||||||
|
form_steps_template = [
|
||||||
|
'order/order_wizard/po_upload.html',
|
||||||
|
'order/order_wizard/match_fields.html',
|
||||||
|
'order/order_wizard/match_parts.html',
|
||||||
|
]
|
||||||
|
form_steps_description = [
|
||||||
|
_("Upload File"),
|
||||||
|
_("Match Fields"),
|
||||||
|
_("Match Supplier Parts"),
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_order(self):
|
||||||
|
""" Get order or return 404 """
|
||||||
|
|
||||||
|
return get_object_or_404(PurchaseOrder, pk=self.kwargs['pk'])
|
||||||
|
|
||||||
|
def get_context_data(self, form, **kwargs):
|
||||||
|
context = super().get_context_data(form=form, **kwargs)
|
||||||
|
|
||||||
|
order = self.get_order()
|
||||||
|
|
||||||
|
context.update({'order': order})
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_field_selection(self):
|
||||||
|
""" Once data columns have been selected, attempt to pre-select the proper data from the database.
|
||||||
|
This function is called once the field selection has been validated.
|
||||||
|
The pre-fill data are then passed through to the SupplierPart selection form.
|
||||||
|
"""
|
||||||
|
|
||||||
|
order = self.get_order()
|
||||||
|
|
||||||
|
self.allowed_items = SupplierPart.objects.filter(supplier=order.supplier).prefetch_related('manufacturer_part')
|
||||||
|
|
||||||
|
# Fields prefixed with "Part_" can be used to do "smart matching" against Part objects in the database
|
||||||
|
q_idx = self.get_column_index('Quantity')
|
||||||
|
s_idx = self.get_column_index('Supplier_SKU')
|
||||||
|
m_idx = self.get_column_index('Manufacturer_MPN')
|
||||||
|
# p_idx = self.get_column_index('Unit_Price')
|
||||||
|
# e_idx = self.get_column_index('Extended_Price')
|
||||||
|
|
||||||
|
for row in self.rows:
|
||||||
|
|
||||||
|
# Initially use a quantity of zero
|
||||||
|
quantity = Decimal(0)
|
||||||
|
|
||||||
|
# Initially we do not have a part to reference
|
||||||
|
exact_match_part = None
|
||||||
|
|
||||||
|
# Check if there is a column corresponding to "quantity"
|
||||||
|
if q_idx >= 0:
|
||||||
|
q_val = row['data'][q_idx]['cell']
|
||||||
|
|
||||||
|
if q_val:
|
||||||
|
# Delete commas
|
||||||
|
q_val = q_val.replace(',', '')
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Attempt to extract a valid quantity from the field
|
||||||
|
quantity = Decimal(q_val)
|
||||||
|
except (ValueError, InvalidOperation):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Store the 'quantity' value
|
||||||
|
row['quantity'] = quantity
|
||||||
|
|
||||||
|
# Check if there is a column corresponding to "Supplier SKU"
|
||||||
|
if s_idx >= 0:
|
||||||
|
sku = row['data'][s_idx]['cell']
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Attempt SupplierPart lookup based on SKU value
|
||||||
|
exact_match_part = self.allowed_items.get(SKU__contains=sku)
|
||||||
|
except (ValueError, SupplierPart.DoesNotExist, SupplierPart.MultipleObjectsReturned):
|
||||||
|
exact_match_part = None
|
||||||
|
|
||||||
|
# Check if there is a column corresponding to "Manufacturer MPN"
|
||||||
|
if m_idx >= 0:
|
||||||
|
mpn = row['data'][m_idx]['cell']
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Attempt SupplierPart lookup based on MPN value
|
||||||
|
exact_match_part = self.allowed_items.get(manufacturer_part__MPN__contains=mpn)
|
||||||
|
except (ValueError, SupplierPart.DoesNotExist, SupplierPart.MultipleObjectsReturned):
|
||||||
|
exact_match_part = None
|
||||||
|
|
||||||
|
# Supply list of part options for each row, sorted by how closely they match the part name
|
||||||
|
row['item_options'] = self.allowed_items
|
||||||
|
|
||||||
|
# Unless found, the 'part_match' is blank
|
||||||
|
row['item_match'] = None
|
||||||
|
|
||||||
|
if exact_match_part:
|
||||||
|
# If there is an exact match based on SKU or MPN, use that
|
||||||
|
row['item_match'] = exact_match_part
|
||||||
|
|
||||||
|
def done(self, form_list, **kwargs):
|
||||||
|
""" Once all the data is in, process it to add SupplierPart items to the order """
|
||||||
|
|
||||||
|
order = self.get_order()
|
||||||
|
|
||||||
|
items = {}
|
||||||
|
|
||||||
|
for form_key, form_value in self.get_all_cleaned_data().items():
|
||||||
|
# Split key from row value
|
||||||
|
try:
|
||||||
|
(field, idx) = form_key.split('-')
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if field == self.key_item_select:
|
||||||
|
if idx not in items:
|
||||||
|
# Insert into items
|
||||||
|
items.update({
|
||||||
|
idx: {
|
||||||
|
'field': form_value,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
# Update items
|
||||||
|
items[idx]['field'] = form_value
|
||||||
|
|
||||||
|
if field == self.key_quantity_select:
|
||||||
|
if idx not in items:
|
||||||
|
# Insert into items
|
||||||
|
items.update({
|
||||||
|
idx: {
|
||||||
|
'quantity': form_value,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
# Update items
|
||||||
|
items[idx]['quantity'] = form_value
|
||||||
|
|
||||||
|
# Create PurchaseOrderLineItem instances
|
||||||
|
for purchase_order_item in items.values():
|
||||||
|
try:
|
||||||
|
supplier_part = SupplierPart.objects.get(pk=int(purchase_order_item['field']))
|
||||||
|
except (ValueError, SupplierPart.DoesNotExist):
|
||||||
|
continue
|
||||||
|
purchase_order_line_item = PurchaseOrderLineItem(
|
||||||
|
order=order,
|
||||||
|
part=supplier_part,
|
||||||
|
quantity=purchase_order_item['quantity'],
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
purchase_order_line_item.save()
|
||||||
|
except IntegrityError:
|
||||||
|
# PurchaseOrderLineItem already exists
|
||||||
|
pass
|
||||||
|
|
||||||
|
return HttpResponseRedirect(reverse('po-detail', kwargs={'pk': self.kwargs['pk']}))
|
||||||
|
|
||||||
|
|
||||||
class PurchaseOrderExport(AjaxView):
|
class PurchaseOrderExport(AjaxView):
|
||||||
""" File download for a purchase order
|
""" File download for a purchase order
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user