252 lines
11 KiB
Python
252 lines
11 KiB
Python
# shared/clients/orders_client.py
|
|
"""
|
|
Orders Service Client for Inter-Service Communication
|
|
Provides access to orders and procurement planning from other services
|
|
"""
|
|
|
|
import structlog
|
|
from typing import Dict, Any, Optional, List
|
|
from uuid import UUID
|
|
from shared.clients.base_service_client import BaseServiceClient
|
|
from shared.config.base import BaseServiceSettings
|
|
|
|
logger = structlog.get_logger()
|
|
|
|
|
|
class OrdersServiceClient(BaseServiceClient):
|
|
"""Client for communicating with the Orders Service"""
|
|
|
|
def __init__(self, config: BaseServiceSettings):
|
|
super().__init__("orders", config)
|
|
|
|
def get_service_base_path(self) -> str:
|
|
return "/api/v1"
|
|
|
|
# ================================================================
|
|
# PROCUREMENT PLANNING
|
|
# ================================================================
|
|
|
|
async def get_demand_requirements(self, tenant_id: str, date: str) -> Optional[Dict[str, Any]]:
|
|
"""Get demand requirements for production planning"""
|
|
try:
|
|
params = {"date": date}
|
|
result = await self.get("orders/demand-requirements", tenant_id=tenant_id, params=params)
|
|
if result:
|
|
logger.info("Retrieved demand requirements from orders service",
|
|
date=date, tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error getting demand requirements",
|
|
error=str(e), date=date, tenant_id=tenant_id)
|
|
return None
|
|
|
|
async def get_procurement_requirements(self, tenant_id: str, horizon: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
"""Get procurement requirements for purchasing planning"""
|
|
try:
|
|
params = {}
|
|
if horizon:
|
|
params["horizon"] = horizon
|
|
|
|
result = await self.get("orders/procurement-requirements", tenant_id=tenant_id, params=params)
|
|
if result:
|
|
logger.info("Retrieved procurement requirements from orders service",
|
|
horizon=horizon, tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error getting procurement requirements",
|
|
error=str(e), tenant_id=tenant_id)
|
|
return None
|
|
|
|
async def get_weekly_ingredient_needs(self, tenant_id: str) -> Optional[Dict[str, Any]]:
|
|
"""Get weekly ingredient ordering needs for dashboard"""
|
|
try:
|
|
result = await self.get("orders/dashboard/weekly-ingredient-needs", tenant_id=tenant_id)
|
|
if result:
|
|
logger.info("Retrieved weekly ingredient needs from orders service",
|
|
tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error getting weekly ingredient needs",
|
|
error=str(e), tenant_id=tenant_id)
|
|
return None
|
|
|
|
# ================================================================
|
|
# CUSTOMER ORDERS
|
|
# ================================================================
|
|
|
|
async def get_customer_orders(self, tenant_id: str, params: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]:
|
|
"""Get customer orders with optional filtering"""
|
|
try:
|
|
result = await self.get("orders/list", tenant_id=tenant_id, params=params)
|
|
if result:
|
|
orders_count = len(result.get('orders', [])) if isinstance(result, dict) else len(result) if isinstance(result, list) else 0
|
|
logger.info("Retrieved customer orders from orders service",
|
|
orders_count=orders_count, tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error getting customer orders",
|
|
error=str(e), tenant_id=tenant_id)
|
|
return None
|
|
|
|
async def create_customer_order(self, tenant_id: str, order_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
"""Create a new customer order"""
|
|
try:
|
|
result = await self.post("orders/list", data=order_data, tenant_id=tenant_id)
|
|
if result:
|
|
logger.info("Created customer order",
|
|
order_id=result.get('id'), tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error creating customer order",
|
|
error=str(e), tenant_id=tenant_id)
|
|
return None
|
|
|
|
async def update_customer_order(self, tenant_id: str, order_id: str, order_data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
"""Update an existing customer order"""
|
|
try:
|
|
result = await self.put(f"orders/list/{order_id}", data=order_data, tenant_id=tenant_id)
|
|
if result:
|
|
logger.info("Updated customer order",
|
|
order_id=order_id, tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error updating customer order",
|
|
error=str(e), order_id=order_id, tenant_id=tenant_id)
|
|
return None
|
|
|
|
# ================================================================
|
|
# CENTRAL BAKERY ORDERS
|
|
# ================================================================
|
|
|
|
async def get_daily_finalized_orders(self, tenant_id: str, date: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
"""Get daily finalized orders for central bakery"""
|
|
try:
|
|
params = {}
|
|
if date:
|
|
params["date"] = date
|
|
|
|
result = await self.get("orders/daily-finalized", tenant_id=tenant_id, params=params)
|
|
if result:
|
|
logger.info("Retrieved daily finalized orders from orders service",
|
|
date=date, tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error getting daily finalized orders",
|
|
error=str(e), tenant_id=tenant_id)
|
|
return None
|
|
|
|
async def get_weekly_order_summaries(self, tenant_id: str) -> Optional[Dict[str, Any]]:
|
|
"""Get weekly order summaries for central bakery dashboard"""
|
|
try:
|
|
result = await self.get("orders/dashboard/weekly-summaries", tenant_id=tenant_id)
|
|
if result:
|
|
logger.info("Retrieved weekly order summaries from orders service",
|
|
tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error getting weekly order summaries",
|
|
error=str(e), tenant_id=tenant_id)
|
|
return None
|
|
|
|
# ================================================================
|
|
# DASHBOARD AND ANALYTICS
|
|
# ================================================================
|
|
|
|
async def get_dashboard_summary(self, tenant_id: str) -> Optional[Dict[str, Any]]:
|
|
"""Get orders dashboard summary data"""
|
|
try:
|
|
result = await self.get("orders/dashboard/summary", tenant_id=tenant_id)
|
|
if result:
|
|
logger.info("Retrieved orders dashboard summary",
|
|
tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error getting orders dashboard summary",
|
|
error=str(e), tenant_id=tenant_id)
|
|
return None
|
|
|
|
async def get_order_trends(self, tenant_id: str, start_date: str, end_date: str) -> Optional[Dict[str, Any]]:
|
|
"""Get order trends analysis"""
|
|
try:
|
|
params = {
|
|
"start_date": start_date,
|
|
"end_date": end_date
|
|
}
|
|
result = await self.get("orders/analytics/trends", tenant_id=tenant_id, params=params)
|
|
if result:
|
|
logger.info("Retrieved order trends from orders service",
|
|
start_date=start_date, end_date=end_date, tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error getting order trends",
|
|
error=str(e), tenant_id=tenant_id)
|
|
return None
|
|
|
|
# ================================================================
|
|
# ALERTS AND NOTIFICATIONS
|
|
# ================================================================
|
|
|
|
async def get_central_bakery_alerts(self, tenant_id: str) -> Optional[List[Dict[str, Any]]]:
|
|
"""Get central bakery specific alerts"""
|
|
try:
|
|
result = await self.get("orders/alerts", tenant_id=tenant_id)
|
|
alerts = result.get('alerts', []) if result else []
|
|
logger.info("Retrieved central bakery alerts from orders service",
|
|
alerts_count=len(alerts), tenant_id=tenant_id)
|
|
return alerts
|
|
except Exception as e:
|
|
logger.error("Error getting central bakery alerts",
|
|
error=str(e), tenant_id=tenant_id)
|
|
return []
|
|
|
|
async def acknowledge_alert(self, tenant_id: str, alert_id: str) -> Optional[Dict[str, Any]]:
|
|
"""Acknowledge an order-related alert"""
|
|
try:
|
|
result = await self.post(f"orders/alerts/{alert_id}/acknowledge", data={}, tenant_id=tenant_id)
|
|
if result:
|
|
logger.info("Acknowledged order alert",
|
|
alert_id=alert_id, tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error acknowledging order alert",
|
|
error=str(e), alert_id=alert_id, tenant_id=tenant_id)
|
|
return None
|
|
|
|
# ================================================================
|
|
# UTILITY METHODS
|
|
# ================================================================
|
|
|
|
async def download_orders_pdf(self, tenant_id: str, order_ids: List[str], format_type: str = "supplier_communication") -> Optional[bytes]:
|
|
"""Download orders as PDF for supplier communication"""
|
|
try:
|
|
data = {
|
|
"order_ids": order_ids,
|
|
"format": format_type,
|
|
"include_delivery_schedule": True
|
|
}
|
|
# Note: This would need special handling for binary data
|
|
result = await self.post("orders/operations/download-pdf", data=data, tenant_id=tenant_id)
|
|
if result:
|
|
logger.info("Generated orders PDF",
|
|
orders_count=len(order_ids), tenant_id=tenant_id)
|
|
return result
|
|
except Exception as e:
|
|
logger.error("Error generating orders PDF",
|
|
error=str(e), tenant_id=tenant_id)
|
|
return None
|
|
|
|
async def health_check(self) -> bool:
|
|
"""Check if orders service is healthy"""
|
|
try:
|
|
result = await self.get("../health") # Health endpoint is not tenant-scoped
|
|
return result is not None
|
|
except Exception as e:
|
|
logger.error("Orders service health check failed", error=str(e))
|
|
return False
|
|
|
|
|
|
# Factory function for dependency injection
|
|
def create_orders_client(config: BaseServiceSettings) -> OrdersServiceClient:
|
|
"""Create orders service client instance"""
|
|
return OrdersServiceClient(config)
|