mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-29 12:06:44 +00:00
POST request now returns extracted data rows (as an array of dicts)
This commit is contained in:
parent
707787d82c
commit
137c9ff2f2
@ -1541,6 +1541,21 @@ class BomExtract(generics.CreateAPIView):
|
|||||||
queryset = Part.objects.none()
|
queryset = Part.objects.none()
|
||||||
serializer_class = part_serializers.BomExtractSerializer
|
serializer_class = part_serializers.BomExtractSerializer
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Custom create function to return the extracted data
|
||||||
|
"""
|
||||||
|
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
self.perform_create(serializer)
|
||||||
|
headers = self.get_success_headers(serializer.data)
|
||||||
|
|
||||||
|
data = serializer.extract_data()
|
||||||
|
|
||||||
|
return Response(data, status=status.HTTP_201_CREATED, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BomDetail(generics.RetrieveUpdateDestroyAPIView):
|
class BomDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||||
""" API endpoint for detail view of a single BomItem object """
|
""" API endpoint for detail view of a single BomItem object """
|
||||||
|
@ -724,6 +724,44 @@ class BomExtractSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# These columns must be present
|
||||||
|
REQUIRED_COLUMNS = [
|
||||||
|
'quantity',
|
||||||
|
]
|
||||||
|
|
||||||
|
# We need at least one column to specify a "part"
|
||||||
|
PART_COLUMNS = [
|
||||||
|
'part',
|
||||||
|
'part_id',
|
||||||
|
'part_name',
|
||||||
|
'part_ipn',
|
||||||
|
]
|
||||||
|
|
||||||
|
# These columns are "optional"
|
||||||
|
OPTIONAL_COLUMNS = [
|
||||||
|
'allow_variants',
|
||||||
|
'inherited',
|
||||||
|
'optional',
|
||||||
|
'overage',
|
||||||
|
'note',
|
||||||
|
'reference',
|
||||||
|
]
|
||||||
|
|
||||||
|
def find_matching_column(self, col_name, columns):
|
||||||
|
|
||||||
|
# Direct match
|
||||||
|
if col_name in columns:
|
||||||
|
return col_name
|
||||||
|
|
||||||
|
col_name = col_name.lower().strip()
|
||||||
|
|
||||||
|
for col in columns:
|
||||||
|
if col.lower().strip() == col_name:
|
||||||
|
return col
|
||||||
|
|
||||||
|
# No match
|
||||||
|
return None
|
||||||
|
|
||||||
bom_file = serializers.FileField(
|
bom_file = serializers.FileField(
|
||||||
label=_("BOM File"),
|
label=_("BOM File"),
|
||||||
help_text=_("Select Bill of Materials file"),
|
help_text=_("Select Bill of Materials file"),
|
||||||
@ -736,6 +774,8 @@ class BomExtractSerializer(serializers.Serializer):
|
|||||||
Perform validation checks on the uploaded BOM file
|
Perform validation checks on the uploaded BOM file
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self.filename = bom_file.name
|
||||||
|
|
||||||
name, ext = os.path.splitext(bom_file.name)
|
name, ext = os.path.splitext(bom_file.name)
|
||||||
|
|
||||||
# Remove the leading . from the extension
|
# Remove the leading . from the extension
|
||||||
@ -765,47 +805,9 @@ class BomExtractSerializer(serializers.Serializer):
|
|||||||
# Convert to a tablib dataset (we expect headers)
|
# Convert to a tablib dataset (we expect headers)
|
||||||
self.dataset = tablib.Dataset().load(data, ext, headers=True)
|
self.dataset = tablib.Dataset().load(data, ext, headers=True)
|
||||||
|
|
||||||
# These columns must be present
|
for header in self.REQUIRED_COLUMNS:
|
||||||
required_columns = [
|
|
||||||
'quantity',
|
|
||||||
]
|
|
||||||
|
|
||||||
# We need at least one column to specify a "part"
|
match = self.find_matching_column(header, self.dataset.headers)
|
||||||
part_columns = [
|
|
||||||
'part',
|
|
||||||
'part_id',
|
|
||||||
'part_name',
|
|
||||||
'part_ipn',
|
|
||||||
]
|
|
||||||
|
|
||||||
# These columns are "optional"
|
|
||||||
optional_columns = [
|
|
||||||
'allow_variants',
|
|
||||||
'inherited',
|
|
||||||
'optional',
|
|
||||||
'overage',
|
|
||||||
'note',
|
|
||||||
'reference',
|
|
||||||
]
|
|
||||||
|
|
||||||
def find_matching_column(col_name, columns):
|
|
||||||
|
|
||||||
# Direct match
|
|
||||||
if col_name in columns:
|
|
||||||
return col_name
|
|
||||||
|
|
||||||
col_name = col_name.lower().strip()
|
|
||||||
|
|
||||||
for col in columns:
|
|
||||||
if col.lower().strip() == col_name:
|
|
||||||
return col
|
|
||||||
|
|
||||||
# No match
|
|
||||||
return None
|
|
||||||
|
|
||||||
for header in required_columns:
|
|
||||||
|
|
||||||
match = find_matching_column(header, self.dataset.headers)
|
|
||||||
|
|
||||||
if match is None:
|
if match is None:
|
||||||
raise serializers.ValidationError(_("Missing required column") + f": '{header}'")
|
raise serializers.ValidationError(_("Missing required column") + f": '{header}'")
|
||||||
@ -814,8 +816,8 @@ class BomExtractSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
part_match = False
|
part_match = False
|
||||||
|
|
||||||
for col in part_columns:
|
for col in self.PART_COLUMNS:
|
||||||
col_match = find_matching_column(col, self.dataset.headers)
|
col_match = self.find_matching_column(col, self.dataset.headers)
|
||||||
|
|
||||||
part_column_matches[col] = col_match
|
part_column_matches[col] = col_match
|
||||||
|
|
||||||
@ -827,6 +829,22 @@ class BomExtractSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
return bom_file
|
return bom_file
|
||||||
|
|
||||||
|
def extract_data(self):
|
||||||
|
"""
|
||||||
|
Read individual rows out of the BOM file
|
||||||
|
"""
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
|
||||||
|
for row in self.dataset.dict:
|
||||||
|
rows.append(row)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'rows': rows,
|
||||||
|
'headers': self.dataset.headers,
|
||||||
|
'filename': self.filename,
|
||||||
|
}
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = [
|
fields = [
|
||||||
'bom_file',
|
'bom_file',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user