Initial commit - production deployment
This commit is contained in:
4
services/distribution/app/models/__init__.py
Normal file
4
services/distribution/app/models/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# Distribution Service Models
|
||||
from app.models.distribution import * # noqa: F401, F403
|
||||
|
||||
__all__ = []
|
||||
180
services/distribution/app/models/distribution.py
Normal file
180
services/distribution/app/models/distribution.py
Normal file
@@ -0,0 +1,180 @@
|
||||
"""
|
||||
Distribution models for the bakery management platform
|
||||
"""
|
||||
|
||||
import uuid
|
||||
import enum
|
||||
from datetime import datetime, timezone
|
||||
from decimal import Decimal
|
||||
from sqlalchemy import Column, String, DateTime, Float, Integer, Text, Index, Boolean, Numeric, ForeignKey, Enum as SQLEnum
|
||||
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from shared.database.base import Base
|
||||
|
||||
|
||||
class DeliveryRouteStatus(enum.Enum):
|
||||
"""Status of delivery routes"""
|
||||
planned = "planned"
|
||||
in_progress = "in_progress"
|
||||
completed = "completed"
|
||||
cancelled = "cancelled"
|
||||
|
||||
|
||||
class ShipmentStatus(enum.Enum):
|
||||
"""Status of individual shipments"""
|
||||
pending = "pending"
|
||||
packed = "packed"
|
||||
in_transit = "in_transit"
|
||||
delivered = "delivered"
|
||||
failed = "failed"
|
||||
|
||||
|
||||
class DeliveryScheduleFrequency(enum.Enum):
|
||||
"""Frequency of recurring delivery schedules"""
|
||||
daily = "daily"
|
||||
weekly = "weekly"
|
||||
biweekly = "biweekly"
|
||||
monthly = "monthly"
|
||||
|
||||
|
||||
class DeliveryRoute(Base):
|
||||
"""Optimized multi-stop routes for distribution"""
|
||||
__tablename__ = "delivery_routes"
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
|
||||
|
||||
# Route identification
|
||||
route_number = Column(String(50), nullable=False, unique=True, index=True)
|
||||
route_date = Column(DateTime(timezone=True), nullable=False, index=True) # Date when route is executed
|
||||
|
||||
# Vehicle and driver assignment
|
||||
vehicle_id = Column(String(100), nullable=True) # Reference to fleet management
|
||||
driver_id = Column(UUID(as_uuid=True), nullable=True, index=True) # Reference to driver
|
||||
|
||||
# Optimization metadata
|
||||
total_distance_km = Column(Float, nullable=True)
|
||||
estimated_duration_minutes = Column(Integer, nullable=True)
|
||||
|
||||
# VRP Optimization metrics (Phase 2 enhancement)
|
||||
vrp_optimization_savings = Column(JSONB, nullable=True) # {"distance_saved_km": 12.5, "time_saved_minutes": 25, "fuel_saved_liters": 8.2, "co2_saved_kg": 15.4, "cost_saved_eur": 12.50}
|
||||
vrp_algorithm_version = Column(String(50), nullable=True) # Version of VRP algorithm used
|
||||
vrp_optimization_timestamp = Column(DateTime(timezone=True), nullable=True) # When optimization was performed
|
||||
vrp_constraints_satisfied = Column(Boolean, nullable=True) # Whether all constraints were satisfied
|
||||
vrp_objective_value = Column(Float, nullable=True) # Objective function value from optimization
|
||||
|
||||
# Route details
|
||||
route_sequence = Column(JSONB, nullable=True) # Ordered array of stops with timing: [{"stop_number": 1, "location_id": "...", "estimated_arrival": "...", "actual_arrival": "..."}]
|
||||
notes = Column(Text, nullable=True)
|
||||
|
||||
# Status
|
||||
status = Column(SQLEnum(DeliveryRouteStatus), nullable=False, default=DeliveryRouteStatus.planned, index=True)
|
||||
|
||||
# Audit fields
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
created_by = Column(UUID(as_uuid=True), nullable=False)
|
||||
updated_by = Column(UUID(as_uuid=True), nullable=False)
|
||||
|
||||
# Relationships
|
||||
shipments = relationship("Shipment", back_populates="route", cascade="all, delete-orphan")
|
||||
|
||||
# Indexes
|
||||
__table_args__ = (
|
||||
Index('ix_delivery_routes_tenant_date', 'tenant_id', 'route_date'),
|
||||
Index('ix_delivery_routes_status', 'status'),
|
||||
Index('ix_delivery_routes_date_tenant_status', 'route_date', 'tenant_id', 'status'),
|
||||
)
|
||||
|
||||
|
||||
class Shipment(Base):
|
||||
"""Individual deliveries to child tenants"""
|
||||
__tablename__ = "shipments"
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
|
||||
|
||||
# Links to hierarchy and procurement
|
||||
parent_tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True) # Source tenant (central production)
|
||||
child_tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True) # Destination tenant (retail outlet)
|
||||
purchase_order_id = Column(UUID(as_uuid=True), nullable=True, index=True) # Associated internal purchase order
|
||||
delivery_route_id = Column(UUID(as_uuid=True), ForeignKey('delivery_routes.id', ondelete='SET NULL'), nullable=True, index=True) # Assigned route
|
||||
|
||||
# Shipment details
|
||||
shipment_number = Column(String(50), nullable=False, unique=True, index=True)
|
||||
shipment_date = Column(DateTime(timezone=True), nullable=False, index=True)
|
||||
|
||||
# Tracking information
|
||||
current_location_lat = Column(Float, nullable=True)
|
||||
current_location_lng = Column(Float, nullable=True)
|
||||
last_tracked_at = Column(DateTime(timezone=True), nullable=True)
|
||||
status = Column(SQLEnum(ShipmentStatus), nullable=False, default=ShipmentStatus.pending, index=True)
|
||||
actual_delivery_time = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
# Proof of delivery
|
||||
signature = Column(Text, nullable=True) # Digital signature base64 encoded
|
||||
photo_url = Column(String(500), nullable=True) # URL to delivery confirmation photo
|
||||
received_by_name = Column(String(200), nullable=True)
|
||||
delivery_notes = Column(Text, nullable=True)
|
||||
|
||||
# Weight/volume tracking
|
||||
total_weight_kg = Column(Float, nullable=True)
|
||||
total_volume_m3 = Column(Float, nullable=True)
|
||||
|
||||
# Audit fields
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
created_by = Column(UUID(as_uuid=True), nullable=False)
|
||||
updated_by = Column(UUID(as_uuid=True), nullable=False)
|
||||
|
||||
# Relationships
|
||||
route = relationship("DeliveryRoute", back_populates="shipments")
|
||||
|
||||
# Indexes
|
||||
__table_args__ = (
|
||||
Index('ix_shipments_tenant_status', 'tenant_id', 'status'),
|
||||
Index('ix_shipments_parent_child', 'parent_tenant_id', 'child_tenant_id'),
|
||||
Index('ix_shipments_date_tenant', 'shipment_date', 'tenant_id'),
|
||||
)
|
||||
|
||||
|
||||
class DeliverySchedule(Base):
|
||||
"""Recurring delivery patterns"""
|
||||
__tablename__ = "delivery_schedules"
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
|
||||
|
||||
# Schedule identification
|
||||
name = Column(String(200), nullable=False)
|
||||
|
||||
# Delivery pattern
|
||||
delivery_days = Column(String(200), nullable=False) # Format: "Mon,Wed,Fri" or "Mon-Fri"
|
||||
delivery_time = Column(String(20), nullable=False) # Format: "HH:MM" or "HH:MM-HH:MM"
|
||||
frequency = Column(SQLEnum(DeliveryScheduleFrequency), nullable=False, default=DeliveryScheduleFrequency.weekly)
|
||||
|
||||
# Auto-generation settings
|
||||
auto_generate_orders = Column(Boolean, nullable=False, default=False)
|
||||
lead_time_days = Column(Integer, nullable=False, default=1) # How many days in advance to generate
|
||||
|
||||
# Target tenants for this schedule
|
||||
target_parent_tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
|
||||
target_child_tenant_ids = Column(JSONB, nullable=False) # List of child tenant IDs involved in this route
|
||||
|
||||
# Configuration
|
||||
is_active = Column(Boolean, nullable=False, default=True)
|
||||
notes = Column(Text, nullable=True)
|
||||
|
||||
# Audit fields
|
||||
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
|
||||
created_by = Column(UUID(as_uuid=True), nullable=False)
|
||||
updated_by = Column(UUID(as_uuid=True), nullable=False)
|
||||
|
||||
# Indexes
|
||||
__table_args__ = (
|
||||
Index('ix_delivery_schedules_tenant_active', 'tenant_id', 'is_active'),
|
||||
Index('ix_delivery_schedules_parent_tenant', 'target_parent_tenant_id'),
|
||||
)
|
||||
Reference in New Issue
Block a user