Improve demo seed
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"""
|
||||
Internal Demo Cloning API for Inventory Service
|
||||
Service-to-service endpoint for cloning inventory data
|
||||
Service-to-service endpoint for cloning inventory data with date adjustment
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Header
|
||||
@@ -11,9 +11,15 @@ import uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import Optional
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add shared path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent.parent))
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.models.inventory import Ingredient
|
||||
from app.models.inventory import Ingredient, Stock
|
||||
from shared.utils.demo_dates import adjust_date_for_demo, BASE_REFERENCE_DATE
|
||||
|
||||
logger = structlog.get_logger()
|
||||
router = APIRouter(prefix="/internal/demo", tags=["internal"])
|
||||
@@ -48,7 +54,8 @@ async def clone_demo_data(
|
||||
|
||||
Clones:
|
||||
- Ingredients from template tenant
|
||||
- (Future: recipes, stock data, etc.)
|
||||
- Stock batches with date-adjusted expiration dates
|
||||
- Generates inventory alerts based on stock status
|
||||
|
||||
Args:
|
||||
base_tenant_id: Template tenant UUID to clone from
|
||||
@@ -60,13 +67,15 @@ async def clone_demo_data(
|
||||
Cloning status and record counts
|
||||
"""
|
||||
start_time = datetime.now(timezone.utc)
|
||||
session_created_at = datetime.now(timezone.utc)
|
||||
|
||||
logger.info(
|
||||
"Starting inventory data cloning",
|
||||
"Starting inventory data cloning with date adjustment",
|
||||
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_created_at=session_created_at.isoformat()
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -77,9 +86,13 @@ async def clone_demo_data(
|
||||
# Track cloning statistics
|
||||
stats = {
|
||||
"ingredients": 0,
|
||||
# Add other entities here in future
|
||||
"stock_batches": 0,
|
||||
"alerts_generated": 0
|
||||
}
|
||||
|
||||
# Mapping from base ingredient ID to virtual ingredient ID
|
||||
ingredient_id_mapping = {}
|
||||
|
||||
# Clone Ingredients
|
||||
result = await db.execute(
|
||||
select(Ingredient).where(Ingredient.tenant_id == base_uuid)
|
||||
@@ -94,8 +107,9 @@ async def clone_demo_data(
|
||||
|
||||
for ingredient in base_ingredients:
|
||||
# Create new ingredient with same attributes but new ID and tenant
|
||||
new_ingredient_id = uuid.uuid4()
|
||||
new_ingredient = Ingredient(
|
||||
id=uuid.uuid4(),
|
||||
id=new_ingredient_id,
|
||||
tenant_id=virtual_uuid,
|
||||
name=ingredient.name,
|
||||
sku=ingredient.sku,
|
||||
@@ -116,21 +130,123 @@ async def clone_demo_data(
|
||||
reorder_quantity=ingredient.reorder_quantity,
|
||||
max_stock_level=ingredient.max_stock_level,
|
||||
shelf_life_days=ingredient.shelf_life_days,
|
||||
display_life_hours=ingredient.display_life_hours,
|
||||
best_before_hours=ingredient.best_before_hours,
|
||||
storage_instructions=ingredient.storage_instructions,
|
||||
is_perishable=ingredient.is_perishable,
|
||||
is_active=ingredient.is_active,
|
||||
allergen_info=ingredient.allergen_info
|
||||
allergen_info=ingredient.allergen_info,
|
||||
nutritional_info=ingredient.nutritional_info
|
||||
)
|
||||
db.add(new_ingredient)
|
||||
stats["ingredients"] += 1
|
||||
|
||||
# Store mapping for stock cloning
|
||||
ingredient_id_mapping[ingredient.id] = new_ingredient_id
|
||||
|
||||
await db.flush() # Ensure ingredients are persisted before stock
|
||||
|
||||
# Clone Stock batches with date adjustment
|
||||
result = await db.execute(
|
||||
select(Stock).where(Stock.tenant_id == base_uuid)
|
||||
)
|
||||
base_stocks = result.scalars().all()
|
||||
|
||||
logger.info(
|
||||
"Found stock batches to clone",
|
||||
count=len(base_stocks),
|
||||
base_tenant=str(base_uuid)
|
||||
)
|
||||
|
||||
for stock in base_stocks:
|
||||
# Map ingredient ID
|
||||
new_ingredient_id = ingredient_id_mapping.get(stock.ingredient_id)
|
||||
if not new_ingredient_id:
|
||||
logger.warning(
|
||||
"Stock references non-existent ingredient, skipping",
|
||||
stock_id=str(stock.id),
|
||||
ingredient_id=str(stock.ingredient_id)
|
||||
)
|
||||
continue
|
||||
|
||||
# Adjust dates relative to session creation
|
||||
adjusted_expiration = adjust_date_for_demo(
|
||||
stock.expiration_date,
|
||||
session_created_at,
|
||||
BASE_REFERENCE_DATE
|
||||
)
|
||||
adjusted_received = adjust_date_for_demo(
|
||||
stock.received_date,
|
||||
session_created_at,
|
||||
BASE_REFERENCE_DATE
|
||||
)
|
||||
adjusted_best_before = adjust_date_for_demo(
|
||||
stock.best_before_date,
|
||||
session_created_at,
|
||||
BASE_REFERENCE_DATE
|
||||
)
|
||||
adjusted_created = adjust_date_for_demo(
|
||||
stock.created_at,
|
||||
session_created_at,
|
||||
BASE_REFERENCE_DATE
|
||||
) or session_created_at
|
||||
|
||||
# Create new stock batch
|
||||
new_stock = Stock(
|
||||
id=uuid.uuid4(),
|
||||
tenant_id=virtual_uuid,
|
||||
ingredient_id=new_ingredient_id,
|
||||
supplier_id=stock.supplier_id,
|
||||
batch_number=stock.batch_number,
|
||||
lot_number=stock.lot_number,
|
||||
supplier_batch_ref=stock.supplier_batch_ref,
|
||||
production_stage=stock.production_stage,
|
||||
current_quantity=stock.current_quantity,
|
||||
reserved_quantity=stock.reserved_quantity,
|
||||
available_quantity=stock.available_quantity,
|
||||
received_date=adjusted_received,
|
||||
expiration_date=adjusted_expiration,
|
||||
best_before_date=adjusted_best_before,
|
||||
unit_cost=stock.unit_cost,
|
||||
total_cost=stock.total_cost,
|
||||
storage_location=stock.storage_location,
|
||||
warehouse_zone=stock.warehouse_zone,
|
||||
shelf_position=stock.shelf_position,
|
||||
requires_refrigeration=stock.requires_refrigeration,
|
||||
requires_freezing=stock.requires_freezing,
|
||||
storage_temperature_min=stock.storage_temperature_min,
|
||||
storage_temperature_max=stock.storage_temperature_max,
|
||||
storage_humidity_max=stock.storage_humidity_max,
|
||||
shelf_life_days=stock.shelf_life_days,
|
||||
storage_instructions=stock.storage_instructions,
|
||||
is_available=stock.is_available,
|
||||
is_expired=stock.is_expired,
|
||||
quality_status=stock.quality_status,
|
||||
created_at=adjusted_created,
|
||||
updated_at=session_created_at
|
||||
)
|
||||
db.add(new_stock)
|
||||
stats["stock_batches"] += 1
|
||||
|
||||
# Commit all changes
|
||||
await db.commit()
|
||||
|
||||
# Generate inventory alerts
|
||||
try:
|
||||
from shared.utils.alert_generator import generate_inventory_alerts
|
||||
alerts_count = await generate_inventory_alerts(db, virtual_uuid, session_created_at)
|
||||
stats["alerts_generated"] = alerts_count
|
||||
await db.commit() # Commit alerts
|
||||
logger.info(f"Generated {alerts_count} inventory alerts", virtual_tenant_id=virtual_tenant_id)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to generate alerts: {str(e)}", exc_info=True)
|
||||
stats["alerts_generated"] = 0
|
||||
|
||||
total_records = sum(stats.values())
|
||||
duration_ms = int((datetime.now(timezone.utc) - start_time).total_seconds() * 1000)
|
||||
|
||||
logger.info(
|
||||
"Inventory data cloning completed",
|
||||
"Inventory data cloning completed with date adjustment",
|
||||
virtual_tenant_id=virtual_tenant_id,
|
||||
total_records=total_records,
|
||||
stats=stats,
|
||||
|
||||
@@ -303,6 +303,7 @@ class Stock(Base):
|
||||
'id': str(self.id),
|
||||
'tenant_id': str(self.tenant_id),
|
||||
'ingredient_id': str(self.ingredient_id),
|
||||
'supplier_id': str(self.supplier_id) if self.supplier_id else None,
|
||||
'batch_number': self.batch_number,
|
||||
'lot_number': self.lot_number,
|
||||
'supplier_batch_ref': self.supplier_batch_ref,
|
||||
|
||||
Reference in New Issue
Block a user