722 lines
24 KiB
Python
722 lines
24 KiB
Python
# services/suppliers/app/schemas/suppliers.py
|
|
"""
|
|
Pydantic schemas for supplier-related API requests and responses
|
|
"""
|
|
|
|
from pydantic import BaseModel, Field, EmailStr
|
|
from typing import List, Optional, Dict, Any, Union
|
|
from uuid import UUID
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
|
|
from app.models.suppliers import (
|
|
SupplierType, SupplierStatus, PaymentTerms,
|
|
QualityRating
|
|
)
|
|
|
|
# NOTE: PO, Delivery, and Invoice schemas remain for backward compatibility
|
|
# but the actual tables and functionality have moved to Procurement Service
|
|
# TODO: These schemas should be removed once all clients migrate to Procurement Service
|
|
|
|
|
|
# ============================================================================
|
|
# SUPPLIER SCHEMAS
|
|
# ============================================================================
|
|
|
|
class SupplierCreate(BaseModel):
|
|
"""Schema for creating suppliers"""
|
|
name: str = Field(..., min_length=1, max_length=255)
|
|
supplier_code: Optional[str] = Field(None, max_length=50)
|
|
tax_id: Optional[str] = Field(None, max_length=50)
|
|
registration_number: Optional[str] = Field(None, max_length=100)
|
|
supplier_type: SupplierType
|
|
contact_person: Optional[str] = Field(None, max_length=200)
|
|
email: Optional[EmailStr] = None
|
|
phone: Optional[str] = Field(None, max_length=30)
|
|
mobile: Optional[str] = Field(None, max_length=30)
|
|
website: Optional[str] = Field(None, max_length=255)
|
|
|
|
# Address
|
|
address_line1: Optional[str] = Field(None, max_length=255)
|
|
address_line2: Optional[str] = Field(None, max_length=255)
|
|
city: Optional[str] = Field(None, max_length=100)
|
|
state_province: Optional[str] = Field(None, max_length=100)
|
|
postal_code: Optional[str] = Field(None, max_length=20)
|
|
country: Optional[str] = Field(None, max_length=100)
|
|
|
|
# Business terms
|
|
payment_terms: PaymentTerms = PaymentTerms.net_30
|
|
credit_limit: Optional[Decimal] = Field(None, ge=0)
|
|
currency: str = Field(default="EUR", max_length=3)
|
|
standard_lead_time: int = Field(default=3, ge=0, le=365)
|
|
minimum_order_amount: Optional[Decimal] = Field(None, ge=0)
|
|
delivery_area: Optional[str] = Field(None, max_length=255)
|
|
|
|
# Additional information
|
|
notes: Optional[str] = None
|
|
certifications: Optional[Union[Dict[str, Any], List[str]]] = None
|
|
business_hours: Optional[Dict[str, Any]] = None
|
|
specializations: Optional[Dict[str, Any]] = None
|
|
|
|
|
|
class SupplierUpdate(BaseModel):
|
|
"""Schema for updating suppliers"""
|
|
name: Optional[str] = Field(None, min_length=1, max_length=255)
|
|
supplier_code: Optional[str] = Field(None, max_length=50)
|
|
tax_id: Optional[str] = Field(None, max_length=50)
|
|
registration_number: Optional[str] = Field(None, max_length=100)
|
|
supplier_type: Optional[SupplierType] = None
|
|
status: Optional[SupplierStatus] = None
|
|
contact_person: Optional[str] = Field(None, max_length=200)
|
|
email: Optional[EmailStr] = None
|
|
phone: Optional[str] = Field(None, max_length=30)
|
|
mobile: Optional[str] = Field(None, max_length=30)
|
|
website: Optional[str] = Field(None, max_length=255)
|
|
|
|
# Address
|
|
address_line1: Optional[str] = Field(None, max_length=255)
|
|
address_line2: Optional[str] = Field(None, max_length=255)
|
|
city: Optional[str] = Field(None, max_length=100)
|
|
state_province: Optional[str] = Field(None, max_length=100)
|
|
postal_code: Optional[str] = Field(None, max_length=20)
|
|
country: Optional[str] = Field(None, max_length=100)
|
|
|
|
# Business terms
|
|
payment_terms: Optional[PaymentTerms] = None
|
|
credit_limit: Optional[Decimal] = Field(None, ge=0)
|
|
currency: Optional[str] = Field(None, max_length=3)
|
|
standard_lead_time: Optional[int] = Field(None, ge=0, le=365)
|
|
minimum_order_amount: Optional[Decimal] = Field(None, ge=0)
|
|
delivery_area: Optional[str] = Field(None, max_length=255)
|
|
|
|
# Additional information
|
|
notes: Optional[str] = None
|
|
certifications: Optional[Union[Dict[str, Any], List[str]]] = None
|
|
business_hours: Optional[Dict[str, Any]] = None
|
|
specializations: Optional[Dict[str, Any]] = None
|
|
|
|
|
|
class SupplierApproval(BaseModel):
|
|
"""Schema for supplier approval/rejection"""
|
|
action: str = Field(..., pattern="^(approve|reject)$")
|
|
notes: Optional[str] = None
|
|
|
|
|
|
class SupplierResponse(BaseModel):
|
|
"""Schema for supplier responses"""
|
|
id: UUID
|
|
tenant_id: UUID
|
|
name: str
|
|
supplier_code: Optional[str] = None
|
|
tax_id: Optional[str] = None
|
|
registration_number: Optional[str] = None
|
|
supplier_type: SupplierType
|
|
status: SupplierStatus
|
|
contact_person: Optional[str] = None
|
|
email: Optional[str] = None
|
|
phone: Optional[str] = None
|
|
mobile: Optional[str] = None
|
|
website: Optional[str] = None
|
|
|
|
# Address
|
|
address_line1: Optional[str] = None
|
|
address_line2: Optional[str] = None
|
|
city: Optional[str] = None
|
|
state_province: Optional[str] = None
|
|
postal_code: Optional[str] = None
|
|
country: Optional[str] = None
|
|
|
|
# Business terms
|
|
payment_terms: PaymentTerms
|
|
credit_limit: Optional[Decimal] = None
|
|
currency: str
|
|
standard_lead_time: int
|
|
minimum_order_amount: Optional[Decimal] = None
|
|
delivery_area: Optional[str] = None
|
|
|
|
# Performance metrics
|
|
quality_rating: Optional[float] = None
|
|
delivery_rating: Optional[float] = None
|
|
total_orders: int
|
|
total_amount: Decimal
|
|
|
|
# Approval info
|
|
approved_by: Optional[UUID] = None
|
|
approved_at: Optional[datetime] = None
|
|
rejection_reason: Optional[str] = None
|
|
|
|
# Additional information
|
|
notes: Optional[str] = None
|
|
certifications: Optional[Union[Dict[str, Any], List[str]]] = None
|
|
business_hours: Optional[Dict[str, Any]] = None
|
|
specializations: Optional[Dict[str, Any]] = None
|
|
|
|
# Audit fields
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
created_by: UUID
|
|
updated_by: UUID
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class SupplierSummary(BaseModel):
|
|
"""Schema for supplier summary (list view)"""
|
|
id: UUID
|
|
name: str
|
|
supplier_code: Optional[str] = None
|
|
supplier_type: SupplierType
|
|
status: SupplierStatus
|
|
contact_person: Optional[str] = None
|
|
email: Optional[str] = None
|
|
phone: Optional[str] = None
|
|
city: Optional[str] = None
|
|
country: Optional[str] = None
|
|
|
|
# Business terms - Added for list view
|
|
payment_terms: PaymentTerms
|
|
standard_lead_time: int
|
|
minimum_order_amount: Optional[Decimal] = None
|
|
|
|
# Performance metrics
|
|
quality_rating: Optional[float] = None
|
|
delivery_rating: Optional[float] = None
|
|
total_orders: int
|
|
total_amount: Decimal
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class SupplierDeletionSummary(BaseModel):
|
|
"""Schema for supplier deletion summary"""
|
|
supplier_name: str
|
|
deleted_price_lists: int = 0
|
|
deleted_quality_reviews: int = 0
|
|
deleted_performance_metrics: int = 0
|
|
deleted_alerts: int = 0
|
|
deleted_scorecards: int = 0
|
|
deletion_timestamp: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============================================================================
|
|
# PURCHASE ORDER SCHEMAS
|
|
# ============================================================================
|
|
|
|
class PurchaseOrderItemCreate(BaseModel):
|
|
"""Schema for creating purchase order items"""
|
|
inventory_product_id: UUID
|
|
product_code: Optional[str] = Field(None, max_length=100)
|
|
ordered_quantity: int = Field(..., gt=0)
|
|
unit_of_measure: str = Field(..., max_length=20)
|
|
unit_price: Decimal = Field(..., gt=0)
|
|
quality_requirements: Optional[str] = None
|
|
item_notes: Optional[str] = None
|
|
|
|
|
|
class PurchaseOrderItemUpdate(BaseModel):
|
|
"""Schema for updating purchase order items"""
|
|
ordered_quantity: Optional[int] = Field(None, gt=0)
|
|
unit_price: Optional[Decimal] = Field(None, gt=0)
|
|
quality_requirements: Optional[str] = None
|
|
item_notes: Optional[str] = None
|
|
|
|
|
|
class PurchaseOrderItemResponse(BaseModel):
|
|
"""Schema for purchase order item responses"""
|
|
id: UUID
|
|
tenant_id: UUID
|
|
purchase_order_id: UUID
|
|
price_list_item_id: Optional[UUID] = None
|
|
inventory_product_id: UUID
|
|
product_code: Optional[str] = None
|
|
ordered_quantity: int
|
|
unit_of_measure: str
|
|
unit_price: Decimal
|
|
line_total: Decimal
|
|
received_quantity: int
|
|
remaining_quantity: int
|
|
quality_requirements: Optional[str] = None
|
|
item_notes: Optional[str] = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class PurchaseOrderCreate(BaseModel):
|
|
"""Schema for creating purchase orders"""
|
|
supplier_id: UUID
|
|
reference_number: Optional[str] = Field(None, max_length=100)
|
|
priority: str = Field(default="normal", max_length=20)
|
|
required_delivery_date: Optional[datetime] = None
|
|
|
|
# Delivery information
|
|
delivery_address: Optional[str] = None
|
|
delivery_instructions: Optional[str] = None
|
|
delivery_contact: Optional[str] = Field(None, max_length=200)
|
|
delivery_phone: Optional[str] = Field(None, max_length=30)
|
|
|
|
# Financial information
|
|
tax_amount: Decimal = Field(default=0, ge=0)
|
|
shipping_cost: Decimal = Field(default=0, ge=0)
|
|
discount_amount: Decimal = Field(default=0, ge=0)
|
|
|
|
# Additional information
|
|
notes: Optional[str] = None
|
|
internal_notes: Optional[str] = None
|
|
terms_and_conditions: Optional[str] = None
|
|
|
|
# Items
|
|
items: List[PurchaseOrderItemCreate] = Field(..., min_items=1)
|
|
|
|
|
|
class PurchaseOrderUpdate(BaseModel):
|
|
"""Schema for updating purchase orders"""
|
|
reference_number: Optional[str] = Field(None, max_length=100)
|
|
priority: Optional[str] = Field(None, max_length=20)
|
|
required_delivery_date: Optional[datetime] = None
|
|
estimated_delivery_date: Optional[datetime] = None
|
|
|
|
# Delivery information
|
|
delivery_address: Optional[str] = None
|
|
delivery_instructions: Optional[str] = None
|
|
delivery_contact: Optional[str] = Field(None, max_length=200)
|
|
delivery_phone: Optional[str] = Field(None, max_length=30)
|
|
|
|
# Financial information
|
|
tax_amount: Optional[Decimal] = Field(None, ge=0)
|
|
shipping_cost: Optional[Decimal] = Field(None, ge=0)
|
|
discount_amount: Optional[Decimal] = Field(None, ge=0)
|
|
|
|
# Additional information
|
|
notes: Optional[str] = None
|
|
internal_notes: Optional[str] = None
|
|
terms_and_conditions: Optional[str] = None
|
|
|
|
# Supplier communication
|
|
supplier_reference: Optional[str] = Field(None, max_length=100)
|
|
|
|
|
|
class PurchaseOrderStatusUpdate(BaseModel):
|
|
"""Schema for updating purchase order status"""
|
|
status: str # PurchaseOrderStatus - moved to Procurement Service
|
|
notes: Optional[str] = None
|
|
|
|
|
|
class PurchaseOrderApproval(BaseModel):
|
|
"""Schema for purchase order approval/rejection"""
|
|
action: str = Field(..., pattern="^(approve|reject)$")
|
|
notes: Optional[str] = None
|
|
|
|
|
|
class PurchaseOrderResponse(BaseModel):
|
|
"""Schema for purchase order responses"""
|
|
id: UUID
|
|
tenant_id: UUID
|
|
supplier_id: UUID
|
|
po_number: str
|
|
reference_number: Optional[str] = None
|
|
status: str # PurchaseOrderStatus
|
|
priority: str
|
|
order_date: datetime
|
|
required_delivery_date: Optional[datetime] = None
|
|
estimated_delivery_date: Optional[datetime] = None
|
|
|
|
# Financial information
|
|
subtotal: Decimal
|
|
tax_amount: Decimal
|
|
shipping_cost: Decimal
|
|
discount_amount: Decimal
|
|
total_amount: Decimal
|
|
currency: str
|
|
|
|
# Delivery information
|
|
delivery_address: Optional[str] = None
|
|
delivery_instructions: Optional[str] = None
|
|
delivery_contact: Optional[str] = None
|
|
delivery_phone: Optional[str] = None
|
|
|
|
# Approval workflow
|
|
requires_approval: bool
|
|
approved_by: Optional[UUID] = None
|
|
approved_at: Optional[datetime] = None
|
|
rejection_reason: Optional[str] = None
|
|
|
|
# Communication tracking
|
|
sent_to_supplier_at: Optional[datetime] = None
|
|
supplier_confirmation_date: Optional[datetime] = None
|
|
supplier_reference: Optional[str] = None
|
|
|
|
# Additional information
|
|
notes: Optional[str] = None
|
|
internal_notes: Optional[str] = None
|
|
terms_and_conditions: Optional[str] = None
|
|
|
|
# Audit fields
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
created_by: UUID
|
|
updated_by: UUID
|
|
|
|
# Related data (populated separately)
|
|
supplier: Optional[SupplierSummary] = None
|
|
items: Optional[List[PurchaseOrderItemResponse]] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class PurchaseOrderSummary(BaseModel):
|
|
"""Schema for purchase order summary (list view)"""
|
|
id: UUID
|
|
po_number: str
|
|
supplier_id: UUID
|
|
supplier_name: Optional[str] = None
|
|
status: str # PurchaseOrderStatus
|
|
priority: str
|
|
order_date: datetime
|
|
required_delivery_date: Optional[datetime] = None
|
|
total_amount: Decimal
|
|
currency: str
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============================================================================
|
|
# DELIVERY SCHEMAS
|
|
# ============================================================================
|
|
|
|
class DeliveryItemCreate(BaseModel):
|
|
"""Schema for creating delivery items"""
|
|
purchase_order_item_id: UUID
|
|
inventory_product_id: UUID
|
|
ordered_quantity: int = Field(..., gt=0)
|
|
delivered_quantity: int = Field(..., ge=0)
|
|
accepted_quantity: int = Field(..., ge=0)
|
|
rejected_quantity: int = Field(default=0, ge=0)
|
|
|
|
# Quality information
|
|
batch_lot_number: Optional[str] = Field(None, max_length=100)
|
|
expiry_date: Optional[datetime] = None
|
|
quality_grade: Optional[str] = Field(None, max_length=20)
|
|
|
|
# Issues and notes
|
|
quality_issues: Optional[str] = None
|
|
rejection_reason: Optional[str] = None
|
|
item_notes: Optional[str] = None
|
|
|
|
|
|
class DeliveryItemResponse(BaseModel):
|
|
"""Schema for delivery item responses"""
|
|
id: UUID
|
|
tenant_id: UUID
|
|
delivery_id: UUID
|
|
purchase_order_item_id: UUID
|
|
inventory_product_id: UUID
|
|
ordered_quantity: int
|
|
delivered_quantity: int
|
|
accepted_quantity: int
|
|
rejected_quantity: int
|
|
batch_lot_number: Optional[str] = None
|
|
expiry_date: Optional[datetime] = None
|
|
quality_grade: Optional[str] = None
|
|
quality_issues: Optional[str] = None
|
|
rejection_reason: Optional[str] = None
|
|
item_notes: Optional[str] = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class DeliveryCreate(BaseModel):
|
|
"""Schema for creating deliveries"""
|
|
purchase_order_id: UUID
|
|
supplier_id: UUID
|
|
supplier_delivery_note: Optional[str] = Field(None, max_length=100)
|
|
scheduled_date: Optional[datetime] = None
|
|
estimated_arrival: Optional[datetime] = None
|
|
|
|
# Delivery details
|
|
delivery_address: Optional[str] = None
|
|
delivery_contact: Optional[str] = Field(None, max_length=200)
|
|
delivery_phone: Optional[str] = Field(None, max_length=30)
|
|
carrier_name: Optional[str] = Field(None, max_length=200)
|
|
tracking_number: Optional[str] = Field(None, max_length=100)
|
|
|
|
# Additional information
|
|
notes: Optional[str] = None
|
|
|
|
# Items
|
|
items: List[DeliveryItemCreate] = Field(..., min_items=1)
|
|
|
|
|
|
class DeliveryUpdate(BaseModel):
|
|
"""Schema for updating deliveries"""
|
|
supplier_delivery_note: Optional[str] = Field(None, max_length=100)
|
|
scheduled_date: Optional[datetime] = None
|
|
estimated_arrival: Optional[datetime] = None
|
|
actual_arrival: Optional[datetime] = None
|
|
|
|
# Delivery details
|
|
delivery_address: Optional[str] = None
|
|
delivery_contact: Optional[str] = Field(None, max_length=200)
|
|
delivery_phone: Optional[str] = Field(None, max_length=30)
|
|
carrier_name: Optional[str] = Field(None, max_length=200)
|
|
tracking_number: Optional[str] = Field(None, max_length=100)
|
|
|
|
# Quality inspection
|
|
inspection_passed: Optional[bool] = None
|
|
inspection_notes: Optional[str] = None
|
|
quality_issues: Optional[Dict[str, Any]] = None
|
|
|
|
# Additional information
|
|
notes: Optional[str] = None
|
|
|
|
|
|
class DeliveryStatusUpdate(BaseModel):
|
|
"""Schema for updating delivery status"""
|
|
status: str # DeliveryStatus
|
|
notes: Optional[str] = None
|
|
update_timestamps: bool = Field(default=True)
|
|
|
|
|
|
class DeliveryReceiptConfirmation(BaseModel):
|
|
"""Schema for confirming delivery receipt"""
|
|
inspection_passed: bool = True
|
|
inspection_notes: Optional[str] = None
|
|
quality_issues: Optional[Dict[str, Any]] = None
|
|
notes: Optional[str] = None
|
|
|
|
|
|
class DeliveryResponse(BaseModel):
|
|
"""Schema for delivery responses"""
|
|
id: UUID
|
|
tenant_id: UUID
|
|
purchase_order_id: UUID
|
|
supplier_id: UUID
|
|
delivery_number: str
|
|
supplier_delivery_note: Optional[str] = None
|
|
status: str # DeliveryStatus
|
|
|
|
# Timing
|
|
scheduled_date: Optional[datetime] = None
|
|
estimated_arrival: Optional[datetime] = None
|
|
actual_arrival: Optional[datetime] = None
|
|
completed_at: Optional[datetime] = None
|
|
|
|
# Delivery details
|
|
delivery_address: Optional[str] = None
|
|
delivery_contact: Optional[str] = None
|
|
delivery_phone: Optional[str] = None
|
|
carrier_name: Optional[str] = None
|
|
tracking_number: Optional[str] = None
|
|
|
|
# Quality inspection
|
|
inspection_passed: Optional[bool] = None
|
|
inspection_notes: Optional[str] = None
|
|
quality_issues: Optional[Dict[str, Any]] = None
|
|
|
|
# Receipt information
|
|
received_by: Optional[UUID] = None
|
|
received_at: Optional[datetime] = None
|
|
|
|
# Additional information
|
|
notes: Optional[str] = None
|
|
photos: Optional[Dict[str, Any]] = None
|
|
|
|
# Audit fields
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
created_by: UUID
|
|
|
|
# Related data
|
|
supplier: Optional[SupplierSummary] = None
|
|
purchase_order: Optional[PurchaseOrderSummary] = None
|
|
items: Optional[List[DeliveryItemResponse]] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class DeliverySummary(BaseModel):
|
|
"""Schema for delivery summary (list view)"""
|
|
id: UUID
|
|
delivery_number: str
|
|
supplier_id: UUID
|
|
supplier_name: Optional[str] = None
|
|
purchase_order_id: UUID
|
|
po_number: Optional[str] = None
|
|
status: str # DeliveryStatus
|
|
scheduled_date: Optional[datetime] = None
|
|
actual_arrival: Optional[datetime] = None
|
|
inspection_passed: Optional[bool] = None
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============================================================================
|
|
# SEARCH AND FILTER SCHEMAS
|
|
# ============================================================================
|
|
|
|
class SupplierSearchParams(BaseModel):
|
|
"""Search parameters for suppliers"""
|
|
search_term: Optional[str] = Field(None, max_length=100)
|
|
supplier_type: Optional[SupplierType] = None
|
|
status: Optional[SupplierStatus] = None
|
|
limit: int = Field(default=50, ge=1, le=1000)
|
|
offset: int = Field(default=0, ge=0)
|
|
|
|
|
|
class PurchaseOrderSearchParams(BaseModel):
|
|
"""Search parameters for purchase orders"""
|
|
supplier_id: Optional[UUID] = None
|
|
status: Optional[str] = None # PurchaseOrderStatus
|
|
priority: Optional[str] = None
|
|
date_from: Optional[datetime] = None
|
|
date_to: Optional[datetime] = None
|
|
search_term: Optional[str] = Field(None, max_length=100)
|
|
limit: int = Field(default=50, ge=1, le=1000)
|
|
offset: int = Field(default=0, ge=0)
|
|
|
|
|
|
class DeliverySearchParams(BaseModel):
|
|
"""Search parameters for deliveries"""
|
|
supplier_id: Optional[UUID] = None
|
|
status: Optional[str] = None # DeliveryStatus
|
|
date_from: Optional[datetime] = None
|
|
date_to: Optional[datetime] = None
|
|
search_term: Optional[str] = Field(None, max_length=100)
|
|
limit: int = Field(default=50, ge=1, le=1000)
|
|
offset: int = Field(default=0, ge=0)
|
|
|
|
|
|
# ============================================================================
|
|
# SUPPLIER PRICE LIST SCHEMAS
|
|
# ============================================================================
|
|
|
|
class SupplierPriceListCreate(BaseModel):
|
|
"""Schema for creating supplier price list items"""
|
|
inventory_product_id: UUID
|
|
product_code: Optional[str] = Field(None, max_length=100)
|
|
unit_price: Decimal = Field(..., gt=0)
|
|
unit_of_measure: str = Field(..., max_length=20)
|
|
minimum_order_quantity: Optional[int] = Field(None, ge=1)
|
|
price_per_unit: Decimal = Field(..., gt=0)
|
|
tier_pricing: Optional[Dict[str, Any]] = None # [{quantity: 100, price: 2.50}, ...]
|
|
effective_date: Optional[datetime] = Field(default_factory=lambda: datetime.now())
|
|
expiry_date: Optional[datetime] = None
|
|
is_active: bool = True
|
|
brand: Optional[str] = Field(None, max_length=100)
|
|
packaging_size: Optional[str] = Field(None, max_length=50)
|
|
origin_country: Optional[str] = Field(None, max_length=100)
|
|
shelf_life_days: Optional[int] = None
|
|
storage_requirements: Optional[str] = None
|
|
quality_specs: Optional[Dict[str, Any]] = None
|
|
allergens: Optional[Dict[str, Any]] = None
|
|
|
|
|
|
class SupplierPriceListUpdate(BaseModel):
|
|
"""Schema for updating supplier price list items"""
|
|
unit_price: Optional[Decimal] = Field(None, gt=0)
|
|
unit_of_measure: Optional[str] = Field(None, max_length=20)
|
|
minimum_order_quantity: Optional[int] = Field(None, ge=1)
|
|
tier_pricing: Optional[Dict[str, Any]] = None
|
|
effective_date: Optional[datetime] = None
|
|
expiry_date: Optional[datetime] = None
|
|
is_active: Optional[bool] = None
|
|
brand: Optional[str] = Field(None, max_length=100)
|
|
packaging_size: Optional[str] = Field(None, max_length=50)
|
|
origin_country: Optional[str] = Field(None, max_length=100)
|
|
shelf_life_days: Optional[int] = None
|
|
storage_requirements: Optional[str] = None
|
|
quality_specs: Optional[Dict[str, Any]] = None
|
|
allergens: Optional[Dict[str, Any]] = None
|
|
|
|
|
|
class SupplierPriceListResponse(BaseModel):
|
|
"""Schema for supplier price list responses"""
|
|
id: UUID
|
|
tenant_id: UUID
|
|
supplier_id: UUID
|
|
inventory_product_id: UUID
|
|
product_code: Optional[str] = None
|
|
unit_price: Decimal
|
|
unit_of_measure: str
|
|
minimum_order_quantity: Optional[int] = None
|
|
price_per_unit: Decimal
|
|
tier_pricing: Optional[Dict[str, Any]] = None
|
|
effective_date: datetime
|
|
expiry_date: Optional[datetime] = None
|
|
is_active: bool
|
|
brand: Optional[str] = None
|
|
packaging_size: Optional[str] = None
|
|
origin_country: Optional[str] = None
|
|
shelf_life_days: Optional[int] = None
|
|
storage_requirements: Optional[str] = None
|
|
quality_specs: Optional[Dict[str, Any]] = None
|
|
allergens: Optional[Dict[str, Any]] = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
created_by: UUID
|
|
updated_by: UUID
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ============================================================================
|
|
# STATISTICS AND REPORTING SCHEMAS
|
|
# ============================================================================
|
|
|
|
class SupplierStatistics(BaseModel):
|
|
"""Schema for supplier statistics"""
|
|
total_suppliers: int
|
|
active_suppliers: int
|
|
pending_suppliers: int
|
|
avg_quality_rating: float
|
|
avg_delivery_rating: float
|
|
total_spend: float
|
|
|
|
|
|
class PurchaseOrderStatistics(BaseModel):
|
|
"""Schema for purchase order statistics"""
|
|
total_orders: int
|
|
status_counts: Dict[str, int]
|
|
this_month_orders: int
|
|
this_month_spend: float
|
|
avg_order_value: float
|
|
overdue_count: int
|
|
pending_approval: int
|
|
|
|
|
|
class DeliveryPerformanceStats(BaseModel):
|
|
"""Schema for delivery performance statistics"""
|
|
total_deliveries: int
|
|
on_time_deliveries: int
|
|
late_deliveries: int
|
|
failed_deliveries: int
|
|
on_time_percentage: float
|
|
avg_delay_hours: float
|
|
quality_pass_rate: float
|
|
|
|
|
|
class DeliverySummaryStats(BaseModel):
|
|
"""Schema for delivery summary statistics"""
|
|
todays_deliveries: int
|
|
this_week_deliveries: int
|
|
overdue_deliveries: int
|
|
in_transit_deliveries: int
|