demo seed change 2
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user