New alert system and panel de control page

This commit is contained in:
Urtzi Alfaro
2025-11-27 15:52:40 +01:00
parent 1a2f4602f3
commit e902419b6e
178 changed files with 20982 additions and 6944 deletions

View File

@@ -11,6 +11,11 @@ import uuid
from datetime import datetime, timezone, timedelta
from typing import Optional
import os
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from shared.utils.demo_dates import adjust_date_for_demo, BASE_REFERENCE_DATE
from app.core.database import get_db
from app.models.recipes import (
@@ -43,6 +48,7 @@ async def clone_demo_data(
virtual_tenant_id: str,
demo_account_type: str,
session_id: Optional[str] = None,
session_created_at: Optional[str] = None,
db: AsyncSession = Depends(get_db),
_: bool = Depends(verify_internal_api_key)
):
@@ -60,18 +66,35 @@ async def clone_demo_data(
virtual_tenant_id: Target virtual tenant UUID
demo_account_type: Type of demo account
session_id: Originating session ID for tracing
session_created_at: ISO timestamp when demo session was created (for date adjustment)
Returns:
Cloning status and record counts
"""
start_time = datetime.now(timezone.utc)
# Parse session_created_at or fallback to now
if session_created_at:
try:
session_time = datetime.fromisoformat(session_created_at.replace('Z', '+00:00'))
except (ValueError, AttributeError) as e:
logger.warning(
"Invalid session_created_at format, using current time",
session_created_at=session_created_at,
error=str(e)
)
session_time = datetime.now(timezone.utc)
else:
logger.warning("session_created_at not provided, using current time")
session_time = datetime.now(timezone.utc)
logger.info(
"Starting recipes data cloning",
base_tenant_id=base_tenant_id,
virtual_tenant_id=virtual_tenant_id,
demo_account_type=demo_account_type,
session_id=session_id
session_id=session_id,
session_time=session_time.isoformat()
)
try:
@@ -147,8 +170,8 @@ async def clone_demo_data(
season_start_month=recipe.season_start_month,
season_end_month=recipe.season_end_month,
is_signature_item=recipe.is_signature_item,
created_at=datetime.now(timezone.utc),
updated_at=datetime.now(timezone.utc),
created_at=session_time,
updated_at=session_time,
created_by=recipe.created_by,
updated_by=recipe.updated_by
)
@@ -208,14 +231,6 @@ async def clone_demo_data(
base_tenant=str(base_uuid)
)
# Calculate date offset to make production recent
if base_batches:
max_date = max(batch.production_date for batch in base_batches)
today = datetime.now(timezone.utc)
date_offset = today - max_date
else:
date_offset = timedelta(days=0)
batch_id_map = {}
for batch in base_batches:
@@ -225,16 +240,43 @@ async def clone_demo_data(
# Get the new recipe ID
new_recipe_id = recipe_id_map.get(batch.recipe_id, batch.recipe_id)
# Adjust all date fields using the shared utility
adjusted_production_date = adjust_date_for_demo(
batch.production_date,
session_time,
BASE_REFERENCE_DATE
) if batch.production_date else None
adjusted_planned_start = adjust_date_for_demo(
batch.planned_start_time,
session_time,
BASE_REFERENCE_DATE
) if batch.planned_start_time else None
adjusted_actual_start = adjust_date_for_demo(
batch.actual_start_time,
session_time,
BASE_REFERENCE_DATE
) if batch.actual_start_time else None
adjusted_planned_end = adjust_date_for_demo(
batch.planned_end_time,
session_time,
BASE_REFERENCE_DATE
) if batch.planned_end_time else None
adjusted_actual_end = adjust_date_for_demo(
batch.actual_end_time,
session_time,
BASE_REFERENCE_DATE
) if batch.actual_end_time else None
new_batch = ProductionBatch(
id=new_batch_id,
tenant_id=virtual_uuid,
recipe_id=new_recipe_id,
batch_number=f"BATCH-{uuid.uuid4().hex[:8].upper()}", # New batch number
production_date=batch.production_date + date_offset,
planned_start_time=batch.planned_start_time + date_offset if batch.planned_start_time else None,
actual_start_time=batch.actual_start_time + date_offset if batch.actual_start_time else None,
planned_end_time=batch.planned_end_time + date_offset if batch.planned_end_time else None,
actual_end_time=batch.actual_end_time + date_offset if batch.actual_end_time else None,
production_date=adjusted_production_date,
planned_start_time=adjusted_planned_start,
actual_start_time=adjusted_actual_start,
planned_end_time=adjusted_planned_end,
actual_end_time=adjusted_actual_end,
planned_quantity=batch.planned_quantity,
actual_quantity=batch.actual_quantity,
yield_percentage=batch.yield_percentage,
@@ -263,8 +305,8 @@ async def clone_demo_data(
customer_order_reference=batch.customer_order_reference,
pre_order_quantity=batch.pre_order_quantity,
shelf_quantity=batch.shelf_quantity,
created_at=datetime.now(timezone.utc),
updated_at=datetime.now(timezone.utc),
created_at=session_time,
updated_at=session_time,
created_by=batch.created_by,
completed_by=batch.completed_by
)
@@ -290,6 +332,12 @@ async def clone_demo_data(
consumption.recipe_ingredient_id
)
adjusted_consumption_time = adjust_date_for_demo(
consumption.consumption_time,
session_time,
BASE_REFERENCE_DATE
) if consumption.consumption_time else None
new_consumption = ProductionIngredientConsumption(
id=uuid.uuid4(),
tenant_id=virtual_uuid,
@@ -304,7 +352,7 @@ async def clone_demo_data(
variance_percentage=consumption.variance_percentage,
unit_cost=consumption.unit_cost,
total_cost=consumption.total_cost,
consumption_time=consumption.consumption_time + date_offset,
consumption_time=adjusted_consumption_time,
consumption_notes=consumption.consumption_notes,
staff_member=consumption.staff_member,
ingredient_condition=consumption.ingredient_condition,