Add whatsapp feature

This commit is contained in:
Urtzi Alfaro
2025-11-13 16:01:08 +01:00
parent d7df2b0853
commit 9bc048d360
74 changed files with 9765 additions and 533 deletions

View File

@@ -6,6 +6,7 @@ Pydantic schemas for inventory API requests and responses
from typing import Optional, List, Dict, Any
from datetime import datetime
from decimal import Decimal
from uuid import UUID
from pydantic import BaseModel, Field, validator
from typing import Generic, TypeVar
from enum import Enum
@@ -162,10 +163,11 @@ class IngredientResponse(InventoryBaseSchema):
if v is None:
return None
if isinstance(v, list):
# If it's an empty list or a list, convert to empty dict
return {} if len(v) == 0 else None
# If it's an empty list, return None; if it's a non-empty list, convert to dict format
return {"allergens": v} if v else None
if isinstance(v, dict):
return v
# For any other type including invalid ones, return None
return None
@@ -209,7 +211,21 @@ class StockCreate(InventoryBaseSchema):
shelf_life_days: Optional[int] = Field(None, gt=0, description="Batch-specific shelf life in days")
storage_instructions: Optional[str] = Field(None, description="Batch-specific storage instructions")
@validator('supplier_id', pre=True)
@validator('ingredient_id')
def validate_ingredient_id(cls, v):
"""Validate ingredient_id is a valid UUID"""
if not v:
raise ValueError("ingredient_id is required")
if isinstance(v, str):
try:
# Validate it's a proper UUID
UUID(v)
return v
except (ValueError, AttributeError) as e:
raise ValueError(f"ingredient_id must be a valid UUID string, got: {v}")
return str(v)
@validator('supplier_id')
def validate_supplier_id(cls, v):
"""Convert empty string to None for optional UUID field"""
if v == '' or (isinstance(v, str) and v.strip() == ''):
@@ -268,7 +284,7 @@ class StockUpdate(InventoryBaseSchema):
shelf_life_days: Optional[int] = Field(None, gt=0, description="Batch-specific shelf life in days")
storage_instructions: Optional[str] = Field(None, description="Batch-specific storage instructions")
@validator('supplier_id', pre=True)
@validator('supplier_id')
def validate_supplier_id(cls, v):
"""Convert empty string to None for optional UUID field"""
if v == '' or (isinstance(v, str) and v.strip() == ''):
@@ -334,15 +350,29 @@ class StockMovementCreate(InventoryBaseSchema):
stock_id: Optional[str] = Field(None, description="Stock ID")
movement_type: StockMovementType = Field(..., description="Movement type")
quantity: float = Field(..., description="Quantity moved")
unit_cost: Optional[Decimal] = Field(None, ge=0, description="Unit cost")
reference_number: Optional[str] = Field(None, max_length=100, description="Reference number")
supplier_id: Optional[str] = Field(None, description="Supplier ID")
notes: Optional[str] = Field(None, description="Movement notes")
reason_code: Optional[str] = Field(None, max_length=50, description="Reason code")
movement_date: Optional[datetime] = Field(None, description="Movement date")
@validator('ingredient_id')
def validate_ingredient_id(cls, v):
"""Validate ingredient_id is a valid UUID"""
if not v:
raise ValueError("ingredient_id is required")
if isinstance(v, str):
try:
# Validate it's a proper UUID
UUID(v)
return v
except (ValueError, AttributeError) as e:
raise ValueError(f"ingredient_id must be a valid UUID string, got: {v}")
return str(v)
class StockMovementResponse(InventoryBaseSchema):
"""Schema for stock movement API responses"""
@@ -392,6 +422,20 @@ class ProductTransformationCreate(InventoryBaseSchema):
# Source stock selection (optional - if not provided, uses FIFO)
source_stock_ids: Optional[List[str]] = Field(None, description="Specific source stock IDs to transform")
@validator('source_ingredient_id', 'target_ingredient_id')
def validate_ingredient_ids(cls, v):
"""Validate ingredient IDs are valid UUIDs"""
if not v:
raise ValueError("ingredient_id is required")
if isinstance(v, str):
try:
# Validate it's a proper UUID
UUID(v)
return v
except (ValueError, AttributeError) as e:
raise ValueError(f"ingredient_id must be a valid UUID string, got: {v}")
return str(v)
class ProductTransformationResponse(InventoryBaseSchema):
"""Schema for product transformation responses"""

View File

@@ -154,7 +154,7 @@ async def seed_ingredients_for_tenant(
shelf_life_days=ing_data.get("shelf_life_days"),
is_perishable=ing_data.get("is_perishable", False),
is_active=True,
allergen_info=ing_data.get("allergen_info", []),
allergen_info=ing_data.get("allergen_info") if ing_data.get("allergen_info") else None,
# NEW: Local production support (Sprint 5)
produced_locally=ing_data.get("produced_locally", False),
recipe_id=uuid.UUID(ing_data["recipe_id"]) if ing_data.get("recipe_id") else None,