New alert service

This commit is contained in:
Urtzi Alfaro
2025-12-05 20:07:01 +01:00
parent 1fe3a73549
commit 667e6e0404
393 changed files with 26002 additions and 61033 deletions

View File

@@ -42,6 +42,7 @@ from shared.schemas.reasoning_types import (
create_po_reasoning_supplier_contract
)
from shared.utils.demo_dates import BASE_REFERENCE_DATE
from shared.messaging import RabbitMQClient
# Configure logging
logger = structlog.get_logger()
@@ -350,9 +351,52 @@ async def create_purchase_order(
contract_quantity=float(total_amount)
)
except Exception as e:
logger.warning(f"Failed to generate reasoning_data: {e}")
logger.error(f"Failed to generate reasoning_data, falling back to basic reasoning: {e}")
logger.exception(e)
pass
# Fallback: Always generate basic reasoning_data to ensure it exists
try:
# Get product names from items_data as fallback
items_list = items_data or []
product_names = [item.get('name', item.get('product_name', f"Product {i+1}")) for i, item in enumerate(items_list)]
if not product_names:
product_names = ["Demo Product"]
# Create basic low stock reasoning as fallback
reasoning_data = create_po_reasoning_low_stock(
supplier_name=supplier.name,
product_names=product_names,
current_stock=25.0, # Default simulated current stock
required_stock=100.0, # Default required stock
days_until_stockout=3, # Default days until stockout
threshold_percentage=20,
affected_products=product_names[:2] # First 2 products affected
)
logger.info("Successfully generated fallback reasoning_data")
except Exception as fallback_error:
logger.error(f"Fallback reasoning generation also failed: {fallback_error}")
# Ultimate fallback: Create minimal valid reasoning data structure
reasoning_data = {
"type": "low_stock_detection",
"parameters": {
"supplier_name": supplier.name,
"product_names": ["Demo Product"],
"product_count": 1,
"current_stock": 10.0,
"required_stock": 50.0,
"days_until_stockout": 2
},
"consequence": {
"type": "stockout_risk",
"severity": "medium",
"impact_days": 2
},
"metadata": {
"trigger_source": "demo_fallback",
"ai_assisted": False
}
}
logger.info("Used ultimate fallback reasoning_data structure")
# Create PO
po = PurchaseOrder(
@@ -639,18 +683,123 @@ async def seed_purchase_orders_for_tenant(db: AsyncSession, tenant_id: uuid.UUID
po12.notes = "📦 ARRIVING SOON: Delivery expected in 8 hours - Prepare for stock receipt"
pos_created.append(po12)
# 13. DELIVERY TODAY MORNING - Scheduled for 10 AM today
delivery_today_morning = BASE_REFERENCE_DATE.replace(hour=10, minute=0, second=0, microsecond=0)
po13 = await create_purchase_order(
db, tenant_id, supplier_high_trust,
PurchaseOrderStatus.sent_to_supplier,
Decimal("625.00"),
created_offset_days=-3,
items_data=[
{"name": "Harina de Trigo T55", "quantity": 500, "unit_price": 0.85, "uom": "kg"},
{"name": "Levadura Fresca", "quantity": 25, "unit_price": 8.00, "uom": "kg"}
]
)
po13.expected_delivery_date = delivery_today_morning
po13.required_delivery_date = delivery_today_morning
po13.notes = "📦 Delivery scheduled for 10 AM - Essential ingredients for morning production"
pos_created.append(po13)
# 14. DELIVERY TODAY AFTERNOON - Scheduled for 3 PM today
delivery_today_afternoon = BASE_REFERENCE_DATE.replace(hour=15, minute=0, second=0, microsecond=0)
po14 = await create_purchase_order(
db, tenant_id, supplier_medium_trust,
PurchaseOrderStatus.confirmed,
Decimal("380.50"),
created_offset_days=-2,
items_data=[
{"name": "Papel Kraft Bolsas", "quantity": 5000, "unit_price": 0.05, "uom": "unit"},
{"name": "Cajas Pastelería", "quantity": 500, "unit_price": 0.26, "uom": "unit"}
]
)
po14.expected_delivery_date = delivery_today_afternoon
po14.required_delivery_date = delivery_today_afternoon
po14.notes = "📦 Packaging delivery expected at 3 PM"
pos_created.append(po14)
# 15. DELIVERY TOMORROW EARLY - Scheduled for 8 AM tomorrow (high priority)
delivery_tomorrow_early = BASE_REFERENCE_DATE + timedelta(days=1, hours=8)
po15 = await create_purchase_order(
db, tenant_id, supplier_high_trust,
PurchaseOrderStatus.approved,
Decimal("445.00"),
created_offset_days=-1,
items_data=[
{"name": "Harina Integral", "quantity": 300, "unit_price": 0.95, "uom": "kg"},
{"name": "Sal Marina", "quantity": 50, "unit_price": 1.60, "uom": "kg"}
]
)
po15.expected_delivery_date = delivery_tomorrow_early
po15.required_delivery_date = delivery_tomorrow_early
po15.priority = "high"
po15.notes = "🔔 Critical delivery for weekend production - Confirm with supplier"
pos_created.append(po15)
# 16. DELIVERY TOMORROW LATE - Scheduled for 5 PM tomorrow
delivery_tomorrow_late = BASE_REFERENCE_DATE + timedelta(days=1, hours=17)
po16 = await create_purchase_order(
db, tenant_id, supplier_low_trust,
PurchaseOrderStatus.sent_to_supplier,
Decimal("890.00"),
created_offset_days=-2,
items_data=[
{"name": "Chocolate Negro 70%", "quantity": 80, "unit_price": 8.50, "uom": "kg"},
{"name": "Cacao en Polvo", "quantity": 30, "unit_price": 7.00, "uom": "kg"}
]
)
po16.expected_delivery_date = delivery_tomorrow_late
po16.required_delivery_date = delivery_tomorrow_late
po16.notes = "📦 Specialty ingredients for chocolate products"
pos_created.append(po16)
# 17. DELIVERY DAY AFTER - Scheduled for 11 AM in 2 days
delivery_day_after = BASE_REFERENCE_DATE + timedelta(days=2, hours=11)
po17 = await create_purchase_order(
db, tenant_id, supplier_medium_trust,
PurchaseOrderStatus.confirmed,
Decimal("520.00"),
created_offset_days=-1,
items_data=[
{"name": "Nata 35% MG", "quantity": 100, "unit_price": 3.80, "uom": "l"},
{"name": "Queso Crema", "quantity": 40, "unit_price": 3.50, "uom": "kg"}
]
)
po17.expected_delivery_date = delivery_day_after
po17.required_delivery_date = delivery_day_after
po17.notes = "📦 Dairy delivery for mid-week production"
pos_created.append(po17)
# 18. DELIVERY THIS WEEK - Scheduled for 2 PM in 4 days
delivery_this_week = BASE_REFERENCE_DATE + timedelta(days=4, hours=14)
po18 = await create_purchase_order(
db, tenant_id, supplier_low_trust,
PurchaseOrderStatus.approved,
Decimal("675.50"),
created_offset_days=-1,
items_data=[
{"name": "Miel de Azahar", "quantity": 50, "unit_price": 8.90, "uom": "kg"},
{"name": "Almendras Marcona", "quantity": 40, "unit_price": 9.50, "uom": "kg"},
{"name": "Nueces", "quantity": 30, "unit_price": 7.20, "uom": "kg"}
]
)
po18.expected_delivery_date = delivery_this_week
po18.required_delivery_date = delivery_this_week
po18.notes = "📦 Specialty items for artisan products"
pos_created.append(po18)
await db.commit()
logger.info(
f"Successfully created {len(pos_created)} purchase orders for tenant",
tenant_id=str(tenant_id),
pending_approval=4, # Updated count (includes escalated PO)
approved=2,
approved=3, # PO #15, #18 + 1 regular
completed=2,
sent_to_supplier=2, # Overdue + arriving soon
sent_to_supplier=4, # PO #11, #12, #13, #16
confirmed=3, # PO #14, #17 + 1 regular
cancelled=1,
disputed=1,
dashboard_showcase=3 # New POs specifically for dashboard alerts
delivery_showcase=9 # POs #11-18 with delivery tracking
)
return pos_created