Improve the frontend 3

This commit is contained in:
Urtzi Alfaro
2025-10-30 21:08:07 +01:00
parent 36217a2729
commit 63f5c6d512
184 changed files with 21512 additions and 7442 deletions

View File

@@ -11,10 +11,11 @@ from shared.database.base import Base
AuditLog = create_audit_log_model(Base)
from .suppliers import (
Supplier, SupplierPriceList, PurchaseOrder, PurchaseOrderItem,
Delivery, DeliveryItem, SupplierQualityReview, SupplierInvoice,
SupplierType, SupplierStatus, PaymentTerms, PurchaseOrderStatus,
DeliveryStatus, QualityRating, DeliveryRating, InvoiceStatus
Supplier, SupplierPriceList, SupplierQualityReview,
SupplierType, SupplierStatus, PaymentTerms, QualityRating,
# Deprecated stubs for backward compatibility
PurchaseOrder, PurchaseOrderItem, Delivery, DeliveryItem, SupplierInvoice,
PurchaseOrderStatus, DeliveryStatus, DeliveryRating, InvoiceStatus
)
from .performance import (
@@ -27,35 +28,37 @@ __all__ = [
# Supplier Models
'Supplier',
'SupplierPriceList',
'PurchaseOrder',
'PurchaseOrderItem',
'Delivery',
'DeliveryItem',
'SupplierQualityReview',
'SupplierInvoice',
# Performance Models
'SupplierPerformanceMetric',
'SupplierAlert',
'SupplierScorecard',
'SupplierBenchmark',
'AlertRule',
# Supplier Enums
'SupplierType',
'SupplierStatus',
'PaymentTerms',
'PurchaseOrderStatus',
'DeliveryStatus',
'QualityRating',
'DeliveryRating',
'InvoiceStatus',
# Performance Enums
'AlertSeverity',
'AlertType',
'AlertStatus',
'PerformanceMetricType',
'PerformancePeriod',
"AuditLog"
"AuditLog",
# Deprecated stubs (backward compatibility only - DO NOT USE)
'PurchaseOrder',
'PurchaseOrderItem',
'Delivery',
'DeliveryItem',
'SupplierInvoice',
'PurchaseOrderStatus',
'DeliveryStatus',
'DeliveryRating',
'InvoiceStatus',
]

View File

@@ -1,7 +1,8 @@
# services/suppliers/app/models/suppliers.py
"""
Supplier & Procurement management models for Suppliers Service
Comprehensive supplier management, purchase orders, deliveries, and vendor relationships
Supplier management models for Suppliers Service
Comprehensive supplier management and vendor relationships
NOTE: Purchase orders, deliveries, and invoices have been moved to Procurement Service
"""
from sqlalchemy import Column, String, DateTime, Float, Integer, Text, Index, Boolean, Numeric, ForeignKey, Enum as SQLEnum
@@ -46,8 +47,23 @@ class PaymentTerms(enum.Enum):
credit_terms = "credit_terms"
class QualityRating(enum.Enum):
"""Quality rating scale for supplier reviews"""
excellent = 5
good = 4
average = 3
poor = 2
very_poor = 1
# ============================================================================
# DEPRECATED ENUMS - Kept for backward compatibility only
# These enums are defined here to prevent import errors, but the actual
# tables and functionality have moved to the Procurement Service
# ============================================================================
class PurchaseOrderStatus(enum.Enum):
"""Purchase order lifecycle status"""
"""DEPRECATED: Moved to Procurement Service"""
draft = "draft"
pending_approval = "pending_approval"
approved = "approved"
@@ -60,7 +76,7 @@ class PurchaseOrderStatus(enum.Enum):
class DeliveryStatus(enum.Enum):
"""Delivery status tracking"""
"""DEPRECATED: Moved to Procurement Service"""
scheduled = "scheduled"
in_transit = "in_transit"
out_for_delivery = "out_for_delivery"
@@ -70,17 +86,8 @@ class DeliveryStatus(enum.Enum):
returned = "returned"
class QualityRating(enum.Enum):
"""Quality rating scale"""
excellent = 5
good = 4
average = 3
poor = 2
very_poor = 1
class DeliveryRating(enum.Enum):
"""Delivery performance rating scale"""
"""DEPRECATED: Moved to Procurement Service"""
excellent = 5
good = 4
average = 3
@@ -89,7 +96,7 @@ class DeliveryRating(enum.Enum):
class InvoiceStatus(enum.Enum):
"""Invoice processing status"""
"""DEPRECATED: Moved to Procurement Service"""
pending = "pending"
approved = "approved"
paid = "paid"
@@ -175,7 +182,6 @@ class Supplier(Base):
# Relationships
price_lists = relationship("SupplierPriceList", back_populates="supplier", cascade="all, delete-orphan")
purchase_orders = relationship("PurchaseOrder", back_populates="supplier")
quality_reviews = relationship("SupplierQualityReview", back_populates="supplier", cascade="all, delete-orphan")
# Indexes
@@ -232,8 +238,7 @@ class SupplierPriceList(Base):
# Relationships
supplier = relationship("Supplier", back_populates="price_lists")
purchase_order_items = relationship("PurchaseOrderItem", back_populates="price_list_item")
# Indexes
__table_args__ = (
Index('ix_price_lists_tenant_supplier', 'tenant_id', 'supplier_id'),
@@ -243,242 +248,21 @@ class SupplierPriceList(Base):
)
class PurchaseOrder(Base):
"""Purchase orders to suppliers"""
__tablename__ = "purchase_orders"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
supplier_id = Column(UUID(as_uuid=True), ForeignKey('suppliers.id'), nullable=False, index=True)
# Order identification
po_number = Column(String(50), nullable=False, index=True) # Human-readable PO number
reference_number = Column(String(100), nullable=True) # Internal reference
# Order status and workflow
status = Column(SQLEnum(PurchaseOrderStatus), nullable=False, default=PurchaseOrderStatus.draft, index=True)
priority = Column(String(20), nullable=False, default="normal") # urgent, high, normal, low
# Order details
order_date = Column(DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc))
required_delivery_date = Column(DateTime(timezone=True), nullable=True)
estimated_delivery_date = Column(DateTime(timezone=True), nullable=True)
# Financial information
subtotal = Column(Numeric(12, 2), nullable=False, default=0.0)
tax_amount = Column(Numeric(12, 2), nullable=False, default=0.0)
shipping_cost = Column(Numeric(10, 2), nullable=False, default=0.0)
discount_amount = Column(Numeric(10, 2), nullable=False, default=0.0)
total_amount = Column(Numeric(12, 2), nullable=False, default=0.0)
currency = Column(String(3), nullable=False, default="EUR")
# Delivery information
delivery_address = Column(Text, nullable=True) # Override default address
delivery_instructions = Column(Text, nullable=True)
delivery_contact = Column(String(200), nullable=True)
delivery_phone = Column(String(30), nullable=True)
# Approval workflow
requires_approval = Column(Boolean, nullable=False, default=False)
approved_by = Column(UUID(as_uuid=True), nullable=True)
approved_at = Column(DateTime(timezone=True), nullable=True)
rejection_reason = Column(Text, nullable=True)
# Communication tracking
sent_to_supplier_at = Column(DateTime(timezone=True), nullable=True)
supplier_confirmation_date = Column(DateTime(timezone=True), nullable=True)
supplier_reference = Column(String(100), nullable=True) # Supplier's order reference
# Additional information
notes = Column(Text, nullable=True)
internal_notes = Column(Text, nullable=True) # Not shared with supplier
terms_and_conditions = Column(Text, nullable=True)
# Audit fields
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
created_by = Column(UUID(as_uuid=True), nullable=False)
updated_by = Column(UUID(as_uuid=True), nullable=False)
# Relationships
supplier = relationship("Supplier", back_populates="purchase_orders")
items = relationship("PurchaseOrderItem", back_populates="purchase_order", cascade="all, delete-orphan")
deliveries = relationship("Delivery", back_populates="purchase_order")
invoices = relationship("SupplierInvoice", back_populates="purchase_order")
# Indexes
__table_args__ = (
Index('ix_purchase_orders_tenant_supplier', 'tenant_id', 'supplier_id'),
Index('ix_purchase_orders_tenant_status', 'tenant_id', 'status'),
Index('ix_purchase_orders_po_number', 'po_number'),
Index('ix_purchase_orders_order_date', 'order_date'),
Index('ix_purchase_orders_delivery_date', 'required_delivery_date'),
)
class PurchaseOrderItem(Base):
"""Individual items within purchase orders"""
__tablename__ = "purchase_order_items"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
purchase_order_id = Column(UUID(as_uuid=True), ForeignKey('purchase_orders.id'), nullable=False, index=True)
price_list_item_id = Column(UUID(as_uuid=True), ForeignKey('supplier_price_lists.id'), nullable=True, index=True)
# Product identification
inventory_product_id = Column(UUID(as_uuid=True), nullable=False, index=True) # Reference to inventory products
product_code = Column(String(100), nullable=True) # Supplier's product code
# Order quantities
ordered_quantity = Column(Integer, nullable=False)
unit_of_measure = Column(String(20), nullable=False)
unit_price = Column(Numeric(10, 4), nullable=False)
line_total = Column(Numeric(12, 2), nullable=False)
# Delivery tracking
received_quantity = Column(Integer, nullable=False, default=0)
remaining_quantity = Column(Integer, nullable=False, default=0)
# Quality and notes
quality_requirements = Column(Text, nullable=True)
item_notes = Column(Text, nullable=True)
# Audit fields
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
# Relationships
purchase_order = relationship("PurchaseOrder", back_populates="items")
price_list_item = relationship("SupplierPriceList", back_populates="purchase_order_items")
delivery_items = relationship("DeliveryItem", back_populates="purchase_order_item")
# Indexes
__table_args__ = (
Index('ix_po_items_tenant_po', 'tenant_id', 'purchase_order_id'),
Index('ix_po_items_inventory_product', 'inventory_product_id'),
)
class Delivery(Base):
"""Delivery tracking for purchase orders"""
__tablename__ = "deliveries"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
purchase_order_id = Column(UUID(as_uuid=True), ForeignKey('purchase_orders.id'), nullable=False, index=True)
supplier_id = Column(UUID(as_uuid=True), ForeignKey('suppliers.id'), nullable=False, index=True)
# Delivery identification
delivery_number = Column(String(50), nullable=False, index=True)
supplier_delivery_note = Column(String(100), nullable=True) # Supplier's delivery reference
# Delivery status and tracking
status = Column(SQLEnum(DeliveryStatus), nullable=False, default=DeliveryStatus.scheduled, index=True)
# Scheduling and timing
scheduled_date = Column(DateTime(timezone=True), nullable=True)
estimated_arrival = Column(DateTime(timezone=True), nullable=True)
actual_arrival = Column(DateTime(timezone=True), nullable=True)
completed_at = Column(DateTime(timezone=True), nullable=True)
# Delivery details
delivery_address = Column(Text, nullable=True)
delivery_contact = Column(String(200), nullable=True)
delivery_phone = Column(String(30), nullable=True)
carrier_name = Column(String(200), nullable=True)
tracking_number = Column(String(100), nullable=True)
# Quality inspection
inspection_passed = Column(Boolean, nullable=True)
inspection_notes = Column(Text, nullable=True)
quality_issues = Column(JSONB, nullable=True) # Documented quality problems
# Received by information
received_by = Column(UUID(as_uuid=True), nullable=True) # User who received the delivery
received_at = Column(DateTime(timezone=True), nullable=True)
# Additional information
notes = Column(Text, nullable=True)
photos = Column(JSONB, nullable=True) # Photo URLs for documentation
# Audit fields
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
created_by = Column(UUID(as_uuid=True), nullable=False)
# Relationships
purchase_order = relationship("PurchaseOrder", back_populates="deliveries")
supplier = relationship("Supplier")
items = relationship("DeliveryItem", back_populates="delivery", cascade="all, delete-orphan")
# Indexes
__table_args__ = (
Index('ix_deliveries_tenant_status', 'tenant_id', 'status'),
Index('ix_deliveries_scheduled_date', 'scheduled_date'),
Index('ix_deliveries_delivery_number', 'delivery_number'),
)
class DeliveryItem(Base):
"""Individual items within deliveries"""
__tablename__ = "delivery_items"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
delivery_id = Column(UUID(as_uuid=True), ForeignKey('deliveries.id'), nullable=False, index=True)
purchase_order_item_id = Column(UUID(as_uuid=True), ForeignKey('purchase_order_items.id'), nullable=False, index=True)
# Product identification
inventory_product_id = Column(UUID(as_uuid=True), nullable=False, index=True)
# Delivery quantities
ordered_quantity = Column(Integer, nullable=False)
delivered_quantity = Column(Integer, nullable=False)
accepted_quantity = Column(Integer, nullable=False)
rejected_quantity = Column(Integer, nullable=False, default=0)
# Quality information
batch_lot_number = Column(String(100), nullable=True)
expiry_date = Column(DateTime(timezone=True), nullable=True)
quality_grade = Column(String(20), nullable=True)
# Issues and notes
quality_issues = Column(Text, nullable=True)
rejection_reason = Column(Text, nullable=True)
item_notes = Column(Text, nullable=True)
# Audit fields
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
# Relationships
delivery = relationship("Delivery", back_populates="items")
purchase_order_item = relationship("PurchaseOrderItem", back_populates="delivery_items")
# Indexes
__table_args__ = (
Index('ix_delivery_items_tenant_delivery', 'tenant_id', 'delivery_id'),
Index('ix_delivery_items_inventory_product', 'inventory_product_id'),
)
class SupplierQualityReview(Base):
"""Quality and performance reviews for suppliers"""
__tablename__ = "supplier_quality_reviews"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
supplier_id = Column(UUID(as_uuid=True), ForeignKey('suppliers.id'), nullable=False, index=True)
purchase_order_id = Column(UUID(as_uuid=True), ForeignKey('purchase_orders.id'), nullable=True, index=True)
delivery_id = Column(UUID(as_uuid=True), ForeignKey('deliveries.id'), nullable=True, index=True)
# Review details
review_date = Column(DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc))
review_type = Column(String(50), nullable=False) # delivery, monthly, annual, incident
review_type = Column(String(50), nullable=False) # monthly, annual, incident
# Ratings (1-5 scale)
quality_rating = Column(SQLEnum(QualityRating), nullable=False)
delivery_rating = Column(SQLEnum(DeliveryRating), nullable=False)
delivery_rating = Column(Integer, nullable=False) # 1-5 scale
communication_rating = Column(Integer, nullable=False) # 1-5
overall_rating = Column(Float, nullable=False) # Calculated average
@@ -512,61 +296,38 @@ class SupplierQualityReview(Base):
Index('ix_quality_reviews_overall_rating', 'overall_rating'),
)
# ============================================================================
# DEPRECATED MODELS - Stub definitions for backward compatibility
# These models are defined here ONLY to prevent import errors
# The actual tables exist in the Procurement Service database, NOT here
# __table__ = None prevents SQLAlchemy from creating these tables
# ============================================================================
class SupplierInvoice(Base):
"""Invoices from suppliers"""
__tablename__ = "supplier_invoices"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
supplier_id = Column(UUID(as_uuid=True), ForeignKey('suppliers.id'), nullable=False, index=True)
purchase_order_id = Column(UUID(as_uuid=True), ForeignKey('purchase_orders.id'), nullable=True, index=True)
# Invoice identification
invoice_number = Column(String(50), nullable=False, index=True)
supplier_invoice_number = Column(String(100), nullable=False)
# Invoice status and dates
status = Column(SQLEnum(InvoiceStatus), nullable=False, default=InvoiceStatus.pending, index=True)
invoice_date = Column(DateTime(timezone=True), nullable=False)
due_date = Column(DateTime(timezone=True), nullable=False)
received_date = Column(DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc))
# Financial information
subtotal = Column(Numeric(12, 2), nullable=False)
tax_amount = Column(Numeric(12, 2), nullable=False, default=0.0)
shipping_cost = Column(Numeric(10, 2), nullable=False, default=0.0)
discount_amount = Column(Numeric(10, 2), nullable=False, default=0.0)
total_amount = Column(Numeric(12, 2), nullable=False)
currency = Column(String(3), nullable=False, default="EUR")
# Payment tracking
paid_amount = Column(Numeric(12, 2), nullable=False, default=0.0)
payment_date = Column(DateTime(timezone=True), nullable=True)
payment_reference = Column(String(100), nullable=True)
# Invoice validation
approved_by = Column(UUID(as_uuid=True), nullable=True)
approved_at = Column(DateTime(timezone=True), nullable=True)
rejection_reason = Column(Text, nullable=True)
# Additional information
notes = Column(Text, nullable=True)
invoice_document_url = Column(String(500), nullable=True) # PDF storage location
# Audit fields
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
updated_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
created_by = Column(UUID(as_uuid=True), nullable=False)
# Relationships
supplier = relationship("Supplier")
purchase_order = relationship("PurchaseOrder", back_populates="invoices")
# Indexes
__table_args__ = (
Index('ix_invoices_tenant_supplier', 'tenant_id', 'supplier_id'),
Index('ix_invoices_tenant_status', 'tenant_id', 'status'),
Index('ix_invoices_due_date', 'due_date'),
Index('ix_invoices_invoice_number', 'invoice_number'),
)
class PurchaseOrder:
"""DEPRECATED STUB: Actual implementation in Procurement Service"""
__table__ = None # Prevent table creation
pass
class PurchaseOrderItem:
"""DEPRECATED STUB: Actual implementation in Procurement Service"""
__table__ = None # Prevent table creation
pass
class Delivery:
"""DEPRECATED STUB: Actual implementation in Procurement Service"""
__table__ = None # Prevent table creation
pass
class DeliveryItem:
"""DEPRECATED STUB: Actual implementation in Procurement Service"""
__table__ = None # Prevent table creation
pass
class SupplierInvoice:
"""DEPRECATED STUB: Actual implementation in Procurement Service"""
__table__ = None # Prevent table creation
pass