demo seed change 2

This commit is contained in:
Urtzi Alfaro
2025-12-14 11:58:14 +01:00
parent ff830a3415
commit a030bd14c8
44 changed files with 3093 additions and 977 deletions

View File

@@ -22,7 +22,9 @@ from app.models.production import (
ProductionStatus, ProductionPriority, ProcessStage,
EquipmentStatus, EquipmentType
)
from shared.utils.demo_dates import adjust_date_for_demo, BASE_REFERENCE_DATE, resolve_time_marker
from shared.utils.demo_dates import (
adjust_date_for_demo, resolve_time_marker, calculate_edge_case_times
)
from app.core.config import settings
@@ -107,11 +109,11 @@ async def clone_demo_data(
"alerts_generated": 0
}
def parse_date_field(date_value, field_name="date"):
def parse_date_field(date_value, session_time, field_name="date"):
"""Parse date field, handling both ISO strings and BASE_TS markers"""
if not date_value:
return None
# Check if it's a BASE_TS marker
if isinstance(date_value, str) and date_value.startswith("BASE_TS"):
try:
@@ -123,13 +125,12 @@ async def clone_demo_data(
error=str(e)
)
return None
# Handle regular ISO date strings
try:
return adjust_date_for_demo(
datetime.fromisoformat(date_value.replace('Z', '+00:00')),
session_time,
BASE_REFERENCE_DATE
session_time
)
except (ValueError, AttributeError) as e:
logger.warning(
@@ -186,31 +187,31 @@ async def clone_demo_data(
detail=f"Invalid UUID format in equipment data: {str(e)}"
)
# Adjust dates relative to session creation time
adjusted_install_date = adjust_date_for_demo(
datetime.fromisoformat(equipment_data['install_date'].replace('Z', '+00:00')),
# Parse date fields (supports BASE_TS markers and ISO timestamps)
adjusted_install_date = parse_date_field(
equipment_data.get('install_date'),
session_time,
BASE_REFERENCE_DATE
"install_date"
)
adjusted_last_maintenance = adjust_date_for_demo(
datetime.fromisoformat(equipment_data['last_maintenance_date'].replace('Z', '+00:00')),
adjusted_last_maintenance = parse_date_field(
equipment_data.get('last_maintenance_date'),
session_time,
BASE_REFERENCE_DATE
"last_maintenance_date"
)
adjusted_next_maintenance = adjust_date_for_demo(
datetime.fromisoformat(equipment_data['next_maintenance_date'].replace('Z', '+00:00')),
adjusted_next_maintenance = parse_date_field(
equipment_data.get('next_maintenance_date'),
session_time,
BASE_REFERENCE_DATE
"next_maintenance_date"
)
adjusted_created_at = adjust_date_for_demo(
datetime.fromisoformat(equipment_data['created_at'].replace('Z', '+00:00')),
adjusted_created_at = parse_date_field(
equipment_data.get('created_at'),
session_time,
BASE_REFERENCE_DATE
"created_at"
)
adjusted_updated_at = adjust_date_for_demo(
datetime.fromisoformat(equipment_data['updated_at'].replace('Z', '+00:00')),
adjusted_updated_at = parse_date_field(
equipment_data.get('updated_at'),
session_time,
BASE_REFERENCE_DATE
"updated_at"
)
new_equipment = Equipment(
@@ -313,13 +314,13 @@ async def clone_demo_data(
batch_id_map[UUID(batch_data['id'])] = transformed_id
# Adjust dates relative to session creation time
adjusted_planned_start = parse_date_field(batch_data.get('planned_start_time'), "planned_start_time")
adjusted_planned_end = parse_date_field(batch_data.get('planned_end_time'), "planned_end_time")
adjusted_actual_start = parse_date_field(batch_data.get('actual_start_time'), "actual_start_time")
adjusted_actual_end = parse_date_field(batch_data.get('actual_end_time'), "actual_end_time")
adjusted_completed = parse_date_field(batch_data.get('completed_at'), "completed_at")
adjusted_created_at = parse_date_field(batch_data.get('created_at'), "created_at") or session_time
adjusted_updated_at = parse_date_field(batch_data.get('updated_at'), "updated_at") or adjusted_created_at
adjusted_planned_start = parse_date_field(batch_data.get('planned_start_time'), session_time, "planned_start_time")
adjusted_planned_end = parse_date_field(batch_data.get('planned_end_time'), session_time, "planned_end_time")
adjusted_actual_start = parse_date_field(batch_data.get('actual_start_time'), session_time, "actual_start_time")
adjusted_actual_end = parse_date_field(batch_data.get('actual_end_time'), session_time, "actual_end_time")
adjusted_completed = parse_date_field(batch_data.get('completed_at'), session_time, "completed_at")
adjusted_created_at = parse_date_field(batch_data.get('created_at'), session_time, "created_at") or session_time
adjusted_updated_at = parse_date_field(batch_data.get('updated_at'), session_time, "updated_at") or adjusted_created_at
# Map status and priority enums
status_value = batch_data.get('status', 'PENDING')
@@ -418,23 +419,23 @@ async def clone_demo_data(
if template_id_value:
template_id_value = template_id_map.get(UUID(template_id_value), UUID(template_id_value))
# Adjust check time relative to session creation time
adjusted_check_time = adjust_date_for_demo(
datetime.fromisoformat(check_data['check_time'].replace('Z', '+00:00')),
# Parse date fields (supports BASE_TS markers and ISO timestamps)
adjusted_check_time = parse_date_field(
check_data.get('check_time'),
session_time,
BASE_REFERENCE_DATE
) if check_data.get('check_time') else None
adjusted_created_at = adjust_date_for_demo(
datetime.fromisoformat(check_data['created_at'].replace('Z', '+00:00')),
session_time,
BASE_REFERENCE_DATE
"check_time"
)
adjusted_updated_at = adjust_date_for_demo(
datetime.fromisoformat(check_data['updated_at'].replace('Z', '+00:00')),
adjusted_created_at = parse_date_field(
check_data.get('created_at'),
session_time,
BASE_REFERENCE_DATE
) if check_data.get('updated_at') else adjusted_created_at
"created_at"
)
adjusted_updated_at = parse_date_field(
check_data.get('updated_at'),
session_time,
"updated_at"
) or adjusted_created_at
new_check = QualityCheck(
id=str(transformed_id),
@@ -485,37 +486,37 @@ async def clone_demo_data(
error=str(e))
continue
# Adjust schedule dates relative to session creation time
adjusted_schedule_date = adjust_date_for_demo(
datetime.fromisoformat(schedule_data['schedule_date'].replace('Z', '+00:00')),
# Parse date fields (supports BASE_TS markers and ISO timestamps)
adjusted_schedule_date = parse_date_field(
schedule_data.get('schedule_date'),
session_time,
BASE_REFERENCE_DATE
) if schedule_data.get('schedule_date') else None
adjusted_shift_start = adjust_date_for_demo(
datetime.fromisoformat(schedule_data['shift_start'].replace('Z', '+00:00')),
session_time,
BASE_REFERENCE_DATE
) if schedule_data.get('shift_start') else None
adjusted_shift_end = adjust_date_for_demo(
datetime.fromisoformat(schedule_data['shift_end'].replace('Z', '+00:00')),
session_time,
BASE_REFERENCE_DATE
) if schedule_data.get('shift_end') else None
adjusted_finalized = adjust_date_for_demo(
datetime.fromisoformat(schedule_data['finalized_at'].replace('Z', '+00:00')),
session_time,
BASE_REFERENCE_DATE
) if schedule_data.get('finalized_at') else None
adjusted_created_at = adjust_date_for_demo(
datetime.fromisoformat(schedule_data['created_at'].replace('Z', '+00:00')),
session_time,
BASE_REFERENCE_DATE
"schedule_date"
)
adjusted_updated_at = adjust_date_for_demo(
datetime.fromisoformat(schedule_data['updated_at'].replace('Z', '+00:00')),
adjusted_shift_start = parse_date_field(
schedule_data.get('shift_start'),
session_time,
BASE_REFERENCE_DATE
) if schedule_data.get('updated_at') else adjusted_created_at
"shift_start"
)
adjusted_shift_end = parse_date_field(
schedule_data.get('shift_end'),
session_time,
"shift_end"
)
adjusted_finalized = parse_date_field(
schedule_data.get('finalized_at'),
session_time,
"finalized_at"
)
adjusted_created_at = parse_date_field(
schedule_data.get('created_at'),
session_time,
"created_at"
)
adjusted_updated_at = parse_date_field(
schedule_data.get('updated_at'),
session_time,
"updated_at"
) or adjusted_created_at
new_schedule = ProductionSchedule(
id=str(transformed_id),
@@ -561,37 +562,37 @@ async def clone_demo_data(
error=str(e))
continue
# Adjust capacity dates relative to session creation time
adjusted_date = adjust_date_for_demo(
datetime.fromisoformat(capacity_data['date'].replace('Z', '+00:00')),
# Parse date fields (supports BASE_TS markers and ISO timestamps)
adjusted_date = parse_date_field(
capacity_data.get('date'),
session_time,
BASE_REFERENCE_DATE
) if capacity_data.get('date') else None
adjusted_start_time = adjust_date_for_demo(
datetime.fromisoformat(capacity_data['start_time'].replace('Z', '+00:00')),
session_time,
BASE_REFERENCE_DATE
) if capacity_data.get('start_time') else None
adjusted_end_time = adjust_date_for_demo(
datetime.fromisoformat(capacity_data['end_time'].replace('Z', '+00:00')),
session_time,
BASE_REFERENCE_DATE
) if capacity_data.get('end_time') else None
adjusted_last_maintenance = adjust_date_for_demo(
datetime.fromisoformat(capacity_data['last_maintenance_date'].replace('Z', '+00:00')),
session_time,
BASE_REFERENCE_DATE
) if capacity_data.get('last_maintenance_date') else None
adjusted_created_at = adjust_date_for_demo(
datetime.fromisoformat(capacity_data['created_at'].replace('Z', '+00:00')),
session_time,
BASE_REFERENCE_DATE
"date"
)
adjusted_updated_at = adjust_date_for_demo(
datetime.fromisoformat(capacity_data['updated_at'].replace('Z', '+00:00')),
adjusted_start_time = parse_date_field(
capacity_data.get('start_time'),
session_time,
BASE_REFERENCE_DATE
) if capacity_data.get('updated_at') else adjusted_created_at
"start_time"
)
adjusted_end_time = parse_date_field(
capacity_data.get('end_time'),
session_time,
"end_time"
)
adjusted_last_maintenance = parse_date_field(
capacity_data.get('last_maintenance_date'),
session_time,
"last_maintenance_date"
)
adjusted_created_at = parse_date_field(
capacity_data.get('created_at'),
session_time,
"created_at"
)
adjusted_updated_at = parse_date_field(
capacity_data.get('updated_at'),
session_time,
"updated_at"
) or adjusted_created_at
new_capacity = ProductionCapacity(
id=str(transformed_id),
@@ -624,6 +625,143 @@ async def clone_demo_data(
db.add(new_capacity)
stats["production_capacity"] += 1
# Add deterministic edge case batches
edge_times = calculate_edge_case_times(session_time)
# Get a sample product_id from existing batches for edge cases
sample_product_id = None
if seed_data.get('batches'):
sample_product_id = seed_data['batches'][0].get('product_id')
if sample_product_id:
# Edge Case 1: Overdue Batch (should have started 2 hours ago)
overdue_batch = ProductionBatch(
id=str(uuid.uuid4()),
tenant_id=virtual_uuid,
batch_number=f"{session_id[:8]}-EDGE-OVERDUE",
product_id=sample_product_id,
product_name="Pan Integral (Edge Case)",
planned_start_time=edge_times["overdue_batch_planned_start"],
planned_end_time=edge_times["overdue_batch_planned_start"] + timedelta(hours=3),
planned_quantity=50.0,
planned_duration_minutes=180,
actual_start_time=None,
actual_end_time=None,
actual_quantity=None,
status=ProductionStatus.PENDING,
priority=ProductionPriority.URGENT,
current_process_stage=None,
production_notes="⚠️ EDGE CASE: Should have started 2 hours ago - triggers yellow alert for delayed production",
created_at=session_time,
updated_at=session_time
)
db.add(overdue_batch)
stats["batches"] += 1
# Edge Case 2: In-Progress Batch (started 1h45m ago)
in_progress_batch = ProductionBatch(
id=str(uuid.uuid4()),
tenant_id=virtual_uuid,
batch_number=f"{session_id[:8]}-EDGE-INPROGRESS",
product_id=sample_product_id,
product_name="Croissant de Mantequilla (Edge Case)",
planned_start_time=edge_times["in_progress_batch_actual_start"],
planned_end_time=edge_times["upcoming_batch_planned_start"],
planned_quantity=100.0,
planned_duration_minutes=195,
actual_start_time=edge_times["in_progress_batch_actual_start"],
actual_end_time=None,
actual_quantity=None,
status=ProductionStatus.IN_PROGRESS,
priority=ProductionPriority.HIGH,
current_process_stage=ProcessStage.BAKING,
production_notes="⚠️ EDGE CASE: Currently in progress - visible in active production dashboard",
created_at=session_time,
updated_at=session_time
)
db.add(in_progress_batch)
stats["batches"] += 1
# Edge Case 3: Upcoming Batch (starts in 1.5 hours)
upcoming_batch = ProductionBatch(
id=str(uuid.uuid4()),
tenant_id=virtual_uuid,
batch_number=f"{session_id[:8]}-EDGE-UPCOMING",
product_id=sample_product_id,
product_name="Baguette Tradicional (Edge Case)",
planned_start_time=edge_times["upcoming_batch_planned_start"],
planned_end_time=edge_times["upcoming_batch_planned_start"] + timedelta(hours=2),
planned_quantity=75.0,
planned_duration_minutes=120,
actual_start_time=None,
actual_end_time=None,
actual_quantity=None,
status=ProductionStatus.PENDING,
priority=ProductionPriority.MEDIUM,
current_process_stage=None,
production_notes="⚠️ EDGE CASE: Starting in 1.5 hours - visible in upcoming production schedule",
created_at=session_time,
updated_at=session_time
)
db.add(upcoming_batch)
stats["batches"] += 1
# Edge Case 4: Evening Batch (starts at 17:00 today)
evening_batch = ProductionBatch(
id=str(uuid.uuid4()),
tenant_id=virtual_uuid,
batch_number=f"{session_id[:8]}-EDGE-EVENING",
product_id=sample_product_id,
product_name="Pan de Molde (Edge Case)",
planned_start_time=edge_times["evening_batch_planned_start"],
planned_end_time=edge_times["evening_batch_planned_start"] + timedelta(hours=2, minutes=30),
planned_quantity=60.0,
planned_duration_minutes=150,
actual_start_time=None,
actual_end_time=None,
actual_quantity=None,
status=ProductionStatus.PENDING,
priority=ProductionPriority.MEDIUM,
current_process_stage=None,
production_notes="⚠️ EDGE CASE: Evening shift production - scheduled for 17:00",
created_at=session_time,
updated_at=session_time
)
db.add(evening_batch)
stats["batches"] += 1
# Edge Case 5: Tomorrow Morning Batch (starts at 05:00 tomorrow)
tomorrow_batch = ProductionBatch(
id=str(uuid.uuid4()),
tenant_id=virtual_uuid,
batch_number=f"{session_id[:8]}-EDGE-TOMORROW",
product_id=sample_product_id,
product_name="Bollería Variada (Edge Case)",
planned_start_time=edge_times["tomorrow_morning_planned_start"],
planned_end_time=edge_times["tomorrow_morning_planned_start"] + timedelta(hours=4),
planned_quantity=120.0,
planned_duration_minutes=240,
actual_start_time=None,
actual_end_time=None,
actual_quantity=None,
status=ProductionStatus.PENDING,
priority=ProductionPriority.MEDIUM,
current_process_stage=None,
production_notes="⚠️ EDGE CASE: Tomorrow morning production - scheduled for 05:00",
created_at=session_time,
updated_at=session_time
)
db.add(tomorrow_batch)
stats["batches"] += 1
logger.info(
"Added deterministic edge case batches",
edge_cases_added=5,
overdue=edge_times["overdue_batch_planned_start"].isoformat(),
in_progress=edge_times["in_progress_batch_actual_start"].isoformat(),
upcoming=edge_times["upcoming_batch_planned_start"].isoformat()
)
# Commit cloned data
await db.commit()