Fix forecasting clone endpoint for demo sessions
Fixed two critical issues preventing forecast data from being cloned: 1. **Missing batch_name field**: The fixture uses `batch_id` but the PredictionBatch model requires `batch_name` (NOT NULL constraint). Added field mapping to handle batch_id -> batch_name conversion. 2. **UUID type mismatch**: The fixture's `product_id` is a string but the Forecast model expects `inventory_product_id` as UUID type. Added conversion from string to UUID. 3. **Field mappings added**: - batch_id -> batch_name - total_forecasts -> total_products - created_at -> requested_at (fallback) - Calculated completed_products from status These fixes enable the forecasting service to successfully clone all 28 forecasts from the fixture file, unlocking demand forecasting AI insights in demo sessions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -244,7 +244,12 @@ async def clone_demo_data(
|
|||||||
|
|
||||||
# Create forecast
|
# Create forecast
|
||||||
# Map product_id to inventory_product_id if needed
|
# Map product_id to inventory_product_id if needed
|
||||||
inventory_product_id = forecast_data.get('inventory_product_id') or forecast_data.get('product_id')
|
inventory_product_id_str = forecast_data.get('inventory_product_id') or forecast_data.get('product_id')
|
||||||
|
# Convert to UUID if it's a string
|
||||||
|
if isinstance(inventory_product_id_str, str):
|
||||||
|
inventory_product_id = uuid.UUID(inventory_product_id_str)
|
||||||
|
else:
|
||||||
|
inventory_product_id = inventory_product_id_str
|
||||||
|
|
||||||
# Map predicted_quantity to predicted_demand if needed
|
# Map predicted_quantity to predicted_demand if needed
|
||||||
predicted_demand = forecast_data.get('predicted_demand') or forecast_data.get('predicted_quantity')
|
predicted_demand = forecast_data.get('predicted_demand') or forecast_data.get('predicted_quantity')
|
||||||
@@ -317,43 +322,31 @@ async def clone_demo_data(
|
|||||||
detail=f"Invalid UUID format in batch data: {str(e)}"
|
detail=f"Invalid UUID format in batch data: {str(e)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Transform dates using proper parse_date_field function
|
|
||||||
for date_field in ['requested_at', 'completed_at']:
|
|
||||||
if date_field in batch_data:
|
|
||||||
try:
|
|
||||||
parsed_date = parse_date_field(
|
|
||||||
batch_data[date_field],
|
|
||||||
session_time,
|
|
||||||
date_field
|
|
||||||
)
|
|
||||||
if parsed_date:
|
|
||||||
batch_data[date_field] = parsed_date
|
|
||||||
else:
|
|
||||||
# If parsing fails, use session_time as fallback
|
|
||||||
batch_data[date_field] = session_time
|
|
||||||
logger.warning("Using fallback date for failed parsing",
|
|
||||||
date_field=date_field,
|
|
||||||
original_value=batch_data[date_field])
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning("Failed to parse date, using fallback",
|
|
||||||
date_field=date_field,
|
|
||||||
date_value=batch_data[date_field],
|
|
||||||
error=str(e))
|
|
||||||
batch_data[date_field] = session_time
|
|
||||||
|
|
||||||
# Create prediction batch
|
# Create prediction batch
|
||||||
|
# Handle field mapping: batch_id -> batch_name, total_forecasts -> total_products
|
||||||
|
batch_name = batch_data.get('batch_name') or batch_data.get('batch_id') or f"Batch-{transformed_id}"
|
||||||
|
total_products = batch_data.get('total_products') or batch_data.get('total_forecasts') or 0
|
||||||
|
completed_products = batch_data.get('completed_products') or (total_products if batch_data.get('status') == 'COMPLETED' else 0)
|
||||||
|
|
||||||
|
# Parse dates (handle created_at or prediction_date for requested_at)
|
||||||
|
requested_at_raw = batch_data.get('requested_at') or batch_data.get('created_at') or batch_data.get('prediction_date')
|
||||||
|
requested_at = parse_date_field(requested_at_raw, session_time, 'requested_at') if requested_at_raw else session_time
|
||||||
|
|
||||||
|
completed_at_raw = batch_data.get('completed_at')
|
||||||
|
completed_at = parse_date_field(completed_at_raw, session_time, 'completed_at') if completed_at_raw else None
|
||||||
|
|
||||||
new_batch = PredictionBatch(
|
new_batch = PredictionBatch(
|
||||||
id=transformed_id,
|
id=transformed_id,
|
||||||
tenant_id=virtual_uuid,
|
tenant_id=virtual_uuid,
|
||||||
batch_name=batch_data.get('batch_name'),
|
batch_name=batch_name,
|
||||||
requested_at=batch_data.get('requested_at'),
|
requested_at=requested_at,
|
||||||
completed_at=batch_data.get('completed_at'),
|
completed_at=completed_at,
|
||||||
status=batch_data.get('status'),
|
status=batch_data.get('status', 'completed'),
|
||||||
total_products=batch_data.get('total_products'),
|
total_products=total_products,
|
||||||
completed_products=batch_data.get('completed_products'),
|
completed_products=completed_products,
|
||||||
failed_products=batch_data.get('failed_products'),
|
failed_products=batch_data.get('failed_products', 0),
|
||||||
forecast_days=batch_data.get('forecast_days'),
|
forecast_days=batch_data.get('forecast_days', 7),
|
||||||
business_type=batch_data.get('business_type'),
|
business_type=batch_data.get('business_type', 'individual'),
|
||||||
error_message=batch_data.get('error_message'),
|
error_message=batch_data.get('error_message'),
|
||||||
processing_time_ms=batch_data.get('processing_time_ms'),
|
processing_time_ms=batch_data.get('processing_time_ms'),
|
||||||
cancelled_by=batch_data.get('cancelled_by')
|
cancelled_by=batch_data.get('cancelled_by')
|
||||||
|
|||||||
Reference in New Issue
Block a user