refactor: migrate modules from re-exports to canonical implementations
Move actual code implementations into module directories: - orders: 5 services, 4 models, order/invoice schemas - inventory: 3 services, 2 models, 30+ schemas - customers: 3 services, 2 models, customer schemas - messaging: 3 services, 2 models, message/notification schemas - monitoring: background_tasks_service - marketplace: 5+ services including letzshop submodule - dev_tools: code_quality_service, test_runner_service - billing: billing_service - contracts: definition.py Legacy files in app/services/, models/database/, models/schema/ now re-export from canonical module locations for backwards compatibility. Architecture validator passes with 0 errors. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
294
app/modules/inventory/schemas/inventory.py
Normal file
294
app/modules/inventory/schemas/inventory.py
Normal file
@@ -0,0 +1,294 @@
|
||||
# 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 vendor 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
|
||||
vendor_id: int
|
||||
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
|
||||
vendor_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 vendor_id."""
|
||||
|
||||
vendor_id: int = Field(..., description="Target vendor ID")
|
||||
product_id: int = Field(..., description="Product ID in vendor 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 vendor_id."""
|
||||
|
||||
vendor_id: int = Field(..., description="Target vendor ID")
|
||||
product_id: int = Field(..., description="Product ID in vendor 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 vendor info for admin list view."""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
product_id: int
|
||||
vendor_id: int
|
||||
vendor_name: str | None = None
|
||||
vendor_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-vendor inventory list for admin."""
|
||||
|
||||
inventories: list[AdminInventoryItem]
|
||||
total: int
|
||||
skip: int
|
||||
limit: int
|
||||
vendor_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
|
||||
vendors_with_inventory: int
|
||||
unique_locations: int
|
||||
|
||||
|
||||
class AdminLowStockItem(BaseModel):
|
||||
"""Low stock item for admin alerts."""
|
||||
|
||||
id: int
|
||||
product_id: int
|
||||
vendor_id: int
|
||||
vendor_name: str | None = None
|
||||
product_title: str | None = None
|
||||
location: str
|
||||
quantity: int
|
||||
reserved_quantity: int
|
||||
available_quantity: int
|
||||
|
||||
|
||||
class AdminVendorWithInventory(BaseModel):
|
||||
"""Vendor with inventory entries."""
|
||||
|
||||
id: int
|
||||
name: str
|
||||
vendor_code: str
|
||||
|
||||
|
||||
class AdminVendorsWithInventoryResponse(BaseModel):
|
||||
"""Response for vendors with inventory list."""
|
||||
|
||||
vendors: list[AdminVendorWithInventory]
|
||||
|
||||
|
||||
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
|
||||
vendor_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 vendor details for admin views."""
|
||||
|
||||
vendor_name: str | None = None
|
||||
vendor_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]
|
||||
Reference in New Issue
Block a user