2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 19:46:46 +00:00
Oliver 52b01b09bf
Refactor existing barcode API endpoints (#5937)
* Refactor existing barcode API endpoints

- Expose fields using proper DRF serializers
- API endpoints are now self documenting
- Validation is handled by serializer models
- Serializers and endpoints are extensible
- Extended existing unit tests

* Catch errors if db not yet loaded

* Tweak unit tests
2023-11-20 12:51:49 +11:00

108 lines
3.3 KiB
Python

"""DRF serializers for barcode scanning API"""
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
import order.models
import stock.models
from InvenTree.status_codes import PurchaseOrderStatus
from plugin.builtin.barcodes.inventree_barcode import \
InvenTreeInternalBarcodePlugin
class BarcodeSerializer(serializers.Serializer):
"""Generic serializer for receiving barcode data"""
MAX_BARCODE_LENGTH = 4095
barcode = serializers.CharField(
required=True, help_text=_('Scanned barcode data'),
max_length=MAX_BARCODE_LENGTH,
)
class BarcodeAssignMixin(serializers.Serializer):
"""Serializer for linking and unlinking barcode to an internal class"""
def __init__(self, *args, **kwargs):
"""Generate serializer fields for each supported model type"""
super().__init__(*args, **kwargs)
for model in InvenTreeInternalBarcodePlugin.get_supported_barcode_models():
self.fields[model.barcode_model_type()] = serializers.PrimaryKeyRelatedField(
queryset=model.objects.all(),
required=False, allow_null=True,
label=model._meta.verbose_name,
)
@staticmethod
def get_model_fields():
"""Return a list of model fields"""
fields = [
model.barcode_model_type() for model in InvenTreeInternalBarcodePlugin.get_supported_barcode_models()
]
return fields
class BarcodeAssignSerializer(BarcodeAssignMixin, BarcodeSerializer):
"""Serializer class for linking a barcode to an internal model"""
class Meta:
"""Meta class for BarcodeAssignSerializer"""
fields = [
'barcode',
*BarcodeAssignMixin.get_model_fields()
]
class BarcodeUnassignSerializer(BarcodeAssignMixin):
"""Serializer class for unlinking a barcode from an internal model"""
class Meta:
"""Meta class for BarcodeUnlinkSerializer"""
fields = BarcodeAssignMixin.get_model_fields()
class BarcodePOReceiveSerializer(BarcodeSerializer):
"""Serializer for receiving items against a purchase order.
The following additional fields may be specified:
- purchase_order: PurchaseOrder object to receive items against
- location: Location to receive items into
"""
purchase_order = serializers.PrimaryKeyRelatedField(
queryset=order.models.PurchaseOrder.objects.all(),
required=False,
help_text=_('PurchaseOrder to receive items against'),
)
def validate_purchase_order(self, order: order.models.PurchaseOrder):
"""Validate the provided order"""
if order.status != PurchaseOrderStatus.PLACED.value:
raise ValidationError(_("Purchase order has not been placed"))
return order
location = serializers.PrimaryKeyRelatedField(
queryset=stock.models.StockLocation.objects.all(),
required=False,
help_text=_('Location to receive items into'),
)
def validate_location(self, location: stock.models.StockLocation):
"""Validate the provided location"""
if location.structural:
raise ValidationError(_("Cannot select a structural location"))
return location