mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-18 02:36:31 +00:00
Stock serialize tweaks (#10017)
* Better item extraction * Improve query efficiency * Further queryset improvements * Return correct data format * Test with hugh number of serials * Improve serialization UX * Revert changes to unit tests
This commit is contained in:
@@ -659,7 +659,8 @@ class BuildOutputCreate(BuildOrderContextMixin, CreateAPI):
|
|||||||
# Create the build output(s)
|
# Create the build output(s)
|
||||||
outputs = serializer.save()
|
outputs = serializer.save()
|
||||||
|
|
||||||
response = stock.serializers.StockItemSerializer(outputs, many=True)
|
queryset = stock.serializers.StockItemSerializer.annotate_queryset(outputs)
|
||||||
|
response = stock.serializers.StockItemSerializer(queryset, many=True)
|
||||||
|
|
||||||
# Return the created outputs
|
# Return the created outputs
|
||||||
return Response(response.data, status=status.HTTP_201_CREATED)
|
return Response(response.data, status=status.HTTP_201_CREATED)
|
||||||
|
@@ -1009,7 +1009,8 @@ class Build(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
outputs = [output]
|
# Ensure we return a QuerySet object here, too
|
||||||
|
outputs = stock.models.StockItem.objects.filter(pk=output.pk)
|
||||||
|
|
||||||
if self.status == BuildStatus.PENDING:
|
if self.status == BuildStatus.PENDING:
|
||||||
self.status = BuildStatus.PRODUCTION.value
|
self.status = BuildStatus.PRODUCTION.value
|
||||||
|
@@ -129,8 +129,10 @@ class StockItemSerialize(StockItemContextMixin, CreateAPI):
|
|||||||
# Perform the actual serialization step
|
# Perform the actual serialization step
|
||||||
items = serializer.save()
|
items = serializer.save()
|
||||||
|
|
||||||
|
queryset = StockSerializers.StockItemSerializer.annotate_queryset(items)
|
||||||
|
|
||||||
response = StockSerializers.StockItemSerializer(
|
response = StockSerializers.StockItemSerializer(
|
||||||
items, many=True, context=self.get_serializer_context()
|
queryset, many=True, context=self.get_serializer_context()
|
||||||
)
|
)
|
||||||
|
|
||||||
return Response(response.data, status=status.HTTP_201_CREATED)
|
return Response(response.data, status=status.HTTP_201_CREATED)
|
||||||
@@ -1151,8 +1153,11 @@ class StockList(DataExportViewMixin, StockApiMixin, ListCreateDestroyAPIView):
|
|||||||
|
|
||||||
StockItemTracking.objects.bulk_create(tracking)
|
StockItemTracking.objects.bulk_create(tracking)
|
||||||
|
|
||||||
|
# Annotate the stock items with part information
|
||||||
|
queryset = StockSerializers.StockItemSerializer.annotate_queryset(items)
|
||||||
|
|
||||||
response = StockSerializers.StockItemSerializer(
|
response = StockSerializers.StockItemSerializer(
|
||||||
items, many=True, context=self.get_serializer_context()
|
queryset, many=True, context=self.get_serializer_context()
|
||||||
)
|
)
|
||||||
|
|
||||||
response_data = response.data
|
response_data = response.data
|
||||||
|
@@ -696,7 +696,10 @@ class SerializeStockItemSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
def validate_quantity(self, quantity):
|
def validate_quantity(self, quantity):
|
||||||
"""Validate that the quantity value is correct."""
|
"""Validate that the quantity value is correct."""
|
||||||
item = self.context['item']
|
item = self.context.get('item')
|
||||||
|
|
||||||
|
if not item:
|
||||||
|
raise ValidationError(_('No stock item provided'))
|
||||||
|
|
||||||
if quantity < 0:
|
if quantity < 0:
|
||||||
raise ValidationError(_('Quantity must be greater than zero'))
|
raise ValidationError(_('Quantity must be greater than zero'))
|
||||||
@@ -736,7 +739,10 @@ class SerializeStockItemSerializer(serializers.Serializer):
|
|||||||
"""Check that the supplied serial numbers are valid."""
|
"""Check that the supplied serial numbers are valid."""
|
||||||
data = super().validate(data)
|
data = super().validate(data)
|
||||||
|
|
||||||
item = self.context['item']
|
item = self.context.get('item')
|
||||||
|
|
||||||
|
if not item:
|
||||||
|
raise ValidationError(_('No stock item provided'))
|
||||||
|
|
||||||
if not item.part.trackable:
|
if not item.part.trackable:
|
||||||
raise ValidationError(_('Serial numbers cannot be assigned to this part'))
|
raise ValidationError(_('Serial numbers cannot be assigned to this part'))
|
||||||
@@ -771,7 +777,11 @@ class SerializeStockItemSerializer(serializers.Serializer):
|
|||||||
Returns:
|
Returns:
|
||||||
A list of StockItem objects that were created as a result of the serialization.
|
A list of StockItem objects that were created as a result of the serialization.
|
||||||
"""
|
"""
|
||||||
item = self.context['item']
|
item = self.context.get('item')
|
||||||
|
|
||||||
|
if not item:
|
||||||
|
raise ValidationError(_('No stock item provided'))
|
||||||
|
|
||||||
request = self.context.get('request')
|
request = self.context.get('request')
|
||||||
user = request.user if request else None
|
user = request.user if request else None
|
||||||
|
|
||||||
@@ -905,7 +915,10 @@ class UninstallStockItemSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Uninstall stock item."""
|
"""Uninstall stock item."""
|
||||||
item = self.context['item']
|
item = self.context.get('item')
|
||||||
|
|
||||||
|
if not item:
|
||||||
|
raise ValidationError(_('No stock item provided'))
|
||||||
|
|
||||||
data = self.validated_data
|
data = self.validated_data
|
||||||
request = self.context['request']
|
request = self.context['request']
|
||||||
@@ -1035,7 +1048,11 @@ class ReturnStockItemSerializer(serializers.Serializer):
|
|||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Save the serializer to return the item into stock."""
|
"""Save the serializer to return the item into stock."""
|
||||||
item = self.context['item']
|
item = self.context.get('item')
|
||||||
|
|
||||||
|
if not item:
|
||||||
|
raise ValidationError(_('No stock item provided'))
|
||||||
|
|
||||||
request = self.context['request']
|
request = self.context['request']
|
||||||
|
|
||||||
data = self.validated_data
|
data = self.validated_data
|
||||||
|
@@ -66,6 +66,15 @@ export function useInstance<T = any>({
|
|||||||
JSON.stringify(pathParams),
|
JSON.stringify(pathParams),
|
||||||
disabled
|
disabled
|
||||||
],
|
],
|
||||||
|
retry: (failureCount, error: any) => {
|
||||||
|
// If it's a 404, don't retry
|
||||||
|
if (error.response?.status == 404) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, retry up to 3 times
|
||||||
|
return failureCount < 3;
|
||||||
|
},
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
@@ -744,12 +744,14 @@ export default function StockDetail() {
|
|||||||
quantity: stockitem.quantity,
|
quantity: stockitem.quantity,
|
||||||
destination: stockitem.location ?? stockitem.part_detail?.default_location
|
destination: stockitem.location ?? stockitem.part_detail?.default_location
|
||||||
},
|
},
|
||||||
onFormSuccess: () => {
|
onFormSuccess: (response: any) => {
|
||||||
const partId = stockitem.part;
|
if (response.length >= stockitem.quantity) {
|
||||||
refreshInstancePromise().catch(() => {
|
// Entire item was serialized
|
||||||
// Part may have been deleted - redirect to the part detail page
|
// Navigate to the first result
|
||||||
navigate(getDetailUrl(ModelType.part, partId));
|
navigate(getDetailUrl(ModelType.stockitem, response[0].pk));
|
||||||
});
|
} else {
|
||||||
|
refreshInstance();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
successMessage: t`Stock item serialized`
|
successMessage: t`Stock item serialized`
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user