210 lines
8.3 KiB
Python
210 lines
8.3 KiB
Python
from rest_framework import serializers
|
|
from ..models import (
|
|
InventoryItem, InventoryStock, InventoryLocation,
|
|
PurchaseOrder, PurchaseOrderItem, Supplier
|
|
)
|
|
|
|
|
|
class BaseSerializer(serializers.ModelSerializer):
|
|
"""Base serializer with common functionality"""
|
|
|
|
class Meta:
|
|
fields = ['id']
|
|
read_only_fields = ['created_at', 'updated_at']
|
|
|
|
|
|
class SupplierSerializer(serializers.ModelSerializer):
|
|
"""Serializer for Supplier model"""
|
|
|
|
class Meta:
|
|
model = Supplier
|
|
fields = [
|
|
'supplier_id', 'name', 'contact_person', 'email', 'phone',
|
|
'address', 'city', 'state', 'zip_code', 'country',
|
|
'tax_id', 'payment_terms', 'credit_limit', 'is_active',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['supplier_id', 'created_at', 'updated_at']
|
|
|
|
|
|
class InventoryLocationSerializer(serializers.ModelSerializer):
|
|
"""Serializer for InventoryLocation model"""
|
|
|
|
class Meta:
|
|
model = InventoryLocation
|
|
fields = [
|
|
'location_id', 'name', 'description', 'location_type',
|
|
'building', 'floor', 'room', 'zone', 'capacity',
|
|
'temperature_controlled', 'security_level', 'is_active',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['location_id', 'created_at', 'updated_at']
|
|
|
|
|
|
class InventoryItemSerializer(serializers.ModelSerializer):
|
|
"""Serializer for InventoryItem model"""
|
|
category_display = serializers.CharField(source='get_category_display', read_only=True)
|
|
unit_display = serializers.CharField(source='get_unit_display', read_only=True)
|
|
|
|
class Meta:
|
|
model = InventoryItem
|
|
fields = [
|
|
'item_id', 'name', 'description', 'category', 'category_display',
|
|
'sku', 'barcode', 'manufacturer', 'model_number',
|
|
'unit', 'unit_display', 'unit_cost', 'reorder_level',
|
|
'reorder_quantity', 'max_stock_level', 'is_active',
|
|
'requires_expiry_tracking', 'requires_lot_tracking',
|
|
'is_controlled_substance', 'storage_requirements',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['item_id', 'created_at', 'updated_at']
|
|
|
|
|
|
class InventoryStockSerializer(serializers.ModelSerializer):
|
|
"""Serializer for InventoryStock model"""
|
|
item_name = serializers.CharField(source='item.name', read_only=True)
|
|
location_name = serializers.CharField(source='location.name', read_only=True)
|
|
is_low_stock = serializers.BooleanField(read_only=True)
|
|
is_expired = serializers.BooleanField(read_only=True)
|
|
days_until_expiry = serializers.IntegerField(read_only=True)
|
|
|
|
class Meta:
|
|
model = InventoryStock
|
|
fields = [
|
|
'stock_id', 'item', 'item_name', 'location', 'location_name',
|
|
'quantity_on_hand', 'quantity_allocated', 'quantity_available',
|
|
'lot_number', 'expiration_date', 'unit_cost', 'total_cost',
|
|
'last_counted', 'is_low_stock', 'is_expired', 'days_until_expiry',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = [
|
|
'stock_id', 'quantity_available', 'total_cost', 'is_low_stock',
|
|
'is_expired', 'days_until_expiry', 'created_at', 'updated_at'
|
|
]
|
|
|
|
|
|
class PurchaseOrderSerializer(serializers.ModelSerializer):
|
|
"""Serializer for PurchaseOrder model"""
|
|
supplier_name = serializers.CharField(source='supplier.name', read_only=True)
|
|
status_display = serializers.CharField(source='get_status_display', read_only=True)
|
|
created_by_name = serializers.CharField(source='created_by.get_full_name', read_only=True)
|
|
|
|
class Meta:
|
|
model = PurchaseOrder
|
|
fields = [
|
|
'order_id', 'order_number', 'supplier', 'supplier_name',
|
|
'order_date', 'expected_delivery_date', 'actual_delivery_date',
|
|
'status', 'status_display', 'total_amount', 'tax_amount',
|
|
'shipping_cost', 'grand_total', 'notes', 'created_by',
|
|
'created_by_name', 'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = [
|
|
'order_id', 'order_number', 'total_amount', 'grand_total',
|
|
'created_at', 'updated_at'
|
|
]
|
|
|
|
|
|
class PurchaseOrderItemSerializer(serializers.ModelSerializer):
|
|
"""Serializer for PurchaseOrderItem model"""
|
|
item_name = serializers.CharField(source='item.name', read_only=True)
|
|
item_sku = serializers.CharField(source='item.sku', read_only=True)
|
|
line_total = serializers.DecimalField(max_digits=12, decimal_places=2, read_only=True)
|
|
|
|
class Meta:
|
|
model = PurchaseOrderItem
|
|
fields = [
|
|
'item_id', 'purchase_order', 'item', 'item_name', 'item_sku',
|
|
'quantity_ordered', 'quantity_received', 'unit_cost',
|
|
'line_total', 'notes', 'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['item_id', 'line_total', 'created_at', 'updated_at']
|
|
|
|
|
|
class InventoryStatsSerializer(serializers.Serializer):
|
|
"""Serializer for inventory statistics"""
|
|
total_items = serializers.IntegerField()
|
|
low_stock_items = serializers.IntegerField()
|
|
expired_items = serializers.IntegerField()
|
|
expiring_soon = serializers.IntegerField()
|
|
total_value = serializers.DecimalField(max_digits=15, decimal_places=2)
|
|
pending_orders = serializers.IntegerField()
|
|
received_today = serializers.IntegerField()
|
|
category_breakdown = serializers.DictField()
|
|
location_utilization = serializers.DictField()
|
|
|
|
|
|
class StockAdjustmentSerializer(serializers.Serializer):
|
|
"""Serializer for stock adjustments"""
|
|
stock_id = serializers.IntegerField()
|
|
adjustment_type = serializers.ChoiceField(choices=['ADD', 'SUBTRACT', 'SET'])
|
|
quantity = serializers.IntegerField()
|
|
reason = serializers.CharField()
|
|
notes = serializers.CharField(required=False, allow_blank=True)
|
|
|
|
def validate_quantity(self, value):
|
|
"""Validate adjustment quantity"""
|
|
if value <= 0:
|
|
raise serializers.ValidationError("Quantity must be greater than 0.")
|
|
return value
|
|
|
|
|
|
class StockTransferSerializer(serializers.Serializer):
|
|
"""Serializer for stock transfers"""
|
|
from_stock_id = serializers.IntegerField()
|
|
to_location_id = serializers.IntegerField()
|
|
quantity = serializers.IntegerField()
|
|
reason = serializers.CharField()
|
|
notes = serializers.CharField(required=False, allow_blank=True)
|
|
|
|
def validate_quantity(self, value):
|
|
"""Validate transfer quantity"""
|
|
if value <= 0:
|
|
raise serializers.ValidationError("Quantity must be greater than 0.")
|
|
return value
|
|
|
|
|
|
class PurchaseOrderCreateSerializer(serializers.Serializer):
|
|
"""Serializer for creating purchase orders"""
|
|
supplier_id = serializers.IntegerField()
|
|
expected_delivery_date = serializers.DateField()
|
|
items = serializers.ListField(
|
|
child=serializers.DictField(),
|
|
min_length=1
|
|
)
|
|
notes = serializers.CharField(required=False, allow_blank=True)
|
|
|
|
def validate_items(self, value):
|
|
"""Validate purchase order items"""
|
|
for item in value:
|
|
if 'item_id' not in item or 'quantity' not in item or 'unit_cost' not in item:
|
|
raise serializers.ValidationError(
|
|
"Each item must have item_id, quantity, and unit_cost."
|
|
)
|
|
if item['quantity'] <= 0:
|
|
raise serializers.ValidationError("Item quantity must be greater than 0.")
|
|
if item['unit_cost'] < 0:
|
|
raise serializers.ValidationError("Unit cost cannot be negative.")
|
|
return value
|
|
|
|
|
|
class ReceiveOrderSerializer(serializers.Serializer):
|
|
"""Serializer for receiving purchase orders"""
|
|
order_id = serializers.IntegerField()
|
|
items = serializers.ListField(
|
|
child=serializers.DictField(),
|
|
min_length=1
|
|
)
|
|
notes = serializers.CharField(required=False, allow_blank=True)
|
|
|
|
def validate_items(self, value):
|
|
"""Validate received items"""
|
|
for item in value:
|
|
if 'item_id' not in item or 'quantity_received' not in item:
|
|
raise serializers.ValidationError(
|
|
"Each item must have item_id and quantity_received."
|
|
)
|
|
if item['quantity_received'] < 0:
|
|
raise serializers.ValidationError("Quantity received cannot be negative.")
|
|
return value
|
|
|