Files
orion/app/modules/inventory/schemas/inventory.py
Samir Boulahtit aad18c27ab
Some checks failed
CI / ruff (push) Successful in 11s
CI / validate (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / pytest (push) Has started running
refactor: remove all backward compatibility code across 70 files
Clean up 28 backward compatibility instances identified in the codebase.
The app is not live, so all shims are replaced with the target architecture:

- Remove legacy Inventory.location column (use bin_location exclusively)
- Remove dashboard _extract_metric_value helper (use flat metrics dict)
- Remove legacy stat field duplicates (total_stores, total_imports, etc.)
- Remove 13 re-export shims and class aliases across modules
- Remove module-enabling JSON fallback (use PlatformModule junction table)
- Remove menu_to_legacy_format() conversion (return dataclasses directly)
- Remove title/description from MarketplaceProductBase schema
- Clean billing convenience method docstrings
- Clean test fixtures and backward-compat comments
- Add PlatformModule seeding to init_production.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 13:20:29 +01:00

295 lines
7.4 KiB
Python

# app/modules/inventory/schemas/inventory.py
from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field
class InventoryBase(BaseModel):
product_id: int = Field(..., description="Product ID in store catalog")
location: str = Field(..., description="Storage location")
class InventoryCreate(InventoryBase):
"""Set exact inventory quantity (replaces existing)."""
quantity: int = Field(..., description="Exact inventory quantity", ge=0)
class InventoryAdjust(InventoryBase):
"""Add or remove inventory quantity."""
quantity: int = Field(
..., description="Quantity to add (positive) or remove (negative)"
)
class InventoryUpdate(BaseModel):
"""Update inventory fields."""
quantity: int | None = Field(None, ge=0)
reserved_quantity: int | None = Field(None, ge=0)
location: str | None = None
class InventoryReserve(BaseModel):
"""Reserve inventory for orders."""
product_id: int
location: str
quantity: int = Field(..., gt=0)
class InventoryResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
product_id: int
store_id: int
bin_location: str
quantity: int
reserved_quantity: int
gtin: str | None
created_at: datetime
updated_at: datetime
@property
def available_quantity(self):
return max(0, self.quantity - self.reserved_quantity)
class InventoryLocationResponse(BaseModel):
location: str
quantity: int
reserved_quantity: int
available_quantity: int
class ProductInventorySummary(BaseModel):
"""Inventory summary for a product."""
product_id: int
store_id: int
product_sku: str | None
product_title: str
total_quantity: int
total_reserved: int
total_available: int
locations: list[InventoryLocationResponse]
class InventoryListResponse(BaseModel):
inventories: list[InventoryResponse]
total: int
skip: int
limit: int
class InventoryMessageResponse(BaseModel):
"""Simple message response for inventory operations."""
message: str
class InventorySummaryResponse(BaseModel):
"""Inventory summary response for marketplace product service."""
gtin: str
total_quantity: int
locations: list[InventoryLocationResponse]
# ============================================================================
# Admin Inventory Schemas
# ============================================================================
class AdminInventoryCreate(BaseModel):
"""Admin version of inventory create - requires explicit store_id."""
store_id: int = Field(..., description="Target store ID")
product_id: int = Field(..., description="Product ID in store catalog")
location: str = Field(..., description="Storage location")
quantity: int = Field(..., description="Exact inventory quantity", ge=0)
class AdminInventoryAdjust(BaseModel):
"""Admin version of inventory adjust - requires explicit store_id."""
store_id: int = Field(..., description="Target store ID")
product_id: int = Field(..., description="Product ID in store catalog")
location: str = Field(..., description="Storage location")
quantity: int = Field(
..., description="Quantity to add (positive) or remove (negative)"
)
reason: str | None = Field(None, description="Reason for adjustment")
class AdminInventoryItem(BaseModel):
"""Inventory item with store info for admin list view."""
model_config = ConfigDict(from_attributes=True)
id: int
product_id: int
store_id: int
store_name: str | None = None
store_code: str | None = None
product_title: str | None = None
product_sku: str | None = None
location: str
quantity: int
reserved_quantity: int
available_quantity: int
gtin: str | None = None
created_at: datetime
updated_at: datetime
class AdminInventoryListResponse(BaseModel):
"""Cross-store inventory list for admin."""
inventories: list[AdminInventoryItem]
total: int
skip: int
limit: int
store_filter: int | None = None
location_filter: str | None = None
class AdminInventoryStats(BaseModel):
"""Inventory statistics for admin dashboard."""
total_entries: int
total_quantity: int
total_reserved: int
total_available: int
low_stock_count: int
stores_with_inventory: int
unique_locations: int
class AdminLowStockItem(BaseModel):
"""Low stock item for admin alerts."""
id: int
product_id: int
store_id: int
store_name: str | None = None
product_title: str | None = None
location: str
quantity: int
reserved_quantity: int
available_quantity: int
class AdminStoreWithInventory(BaseModel):
"""Store with inventory entries."""
id: int
name: str
store_code: str
class AdminStoresWithInventoryResponse(BaseModel):
"""Response for stores with inventory list."""
stores: list[AdminStoreWithInventory]
class AdminInventoryLocationsResponse(BaseModel):
"""Response for unique inventory locations."""
locations: list[str]
# ============================================================================
# Inventory Transaction Schemas
# ============================================================================
class InventoryTransactionResponse(BaseModel):
"""Single inventory transaction record."""
model_config = ConfigDict(from_attributes=True)
id: int
store_id: int
product_id: int
inventory_id: int | None = None
transaction_type: str
quantity_change: int
quantity_after: int
reserved_after: int
location: str | None = None
warehouse: str | None = None
order_id: int | None = None
order_number: str | None = None
reason: str | None = None
created_by: str | None = None
created_at: datetime
class InventoryTransactionWithProduct(InventoryTransactionResponse):
"""Transaction with product details for list views."""
product_title: str | None = None
product_sku: str | None = None
class InventoryTransactionListResponse(BaseModel):
"""Paginated list of inventory transactions."""
transactions: list[InventoryTransactionWithProduct]
total: int
skip: int
limit: int
class ProductTransactionHistoryResponse(BaseModel):
"""Transaction history for a specific product."""
product_id: int
product_title: str | None = None
product_sku: str | None = None
current_quantity: int
current_reserved: int
transactions: list[InventoryTransactionResponse]
total: int
class OrderTransactionHistoryResponse(BaseModel):
"""Transaction history for a specific order."""
order_id: int
order_number: str
transactions: list[InventoryTransactionWithProduct]
# ============================================================================
# Admin Inventory Transaction Schemas
# ============================================================================
class AdminInventoryTransactionItem(InventoryTransactionWithProduct):
"""Transaction with store details for admin views."""
store_name: str | None = None
store_code: str | None = None
class AdminInventoryTransactionListResponse(BaseModel):
"""Paginated list of transactions for admin."""
transactions: list[AdminInventoryTransactionItem]
total: int
skip: int
limit: int
class AdminTransactionStatsResponse(BaseModel):
"""Transaction statistics for admin dashboard."""
total_transactions: int
transactions_today: int
by_type: dict[str, int]