feat: Add dedicated dashboard methods to service clients

Created typed, domain-specific methods in service clients instead of
using generic .get() calls with paths. This improves type safety,
discoverability, and maintainability.

Service Client Changes:
- ProcurementServiceClient:
  * get_pending_purchase_orders() - POs awaiting approval
  * get_critical_alerts() - Critical severity alerts
  * get_alerts_summary() - Alert counts by severity

- ProductionServiceClient:
  * get_todays_batches() - Today's production timeline
  * get_production_batches_by_status() - Filter by status

- InventoryServiceClient:
  * get_stock_status() - Dashboard stock metrics
  * get_sustainability_widget() - Sustainability data

Dashboard API Changes:
- Updated all endpoints to use new dedicated methods
- Cleaner, more maintainable code
- Better error handling and logging
- Fixed inventory data type handling (list vs dict)

Note: Alert endpoints return 404 - alert_processor service needs
endpoints: /alerts/summary and /alerts (filtered by severity).
This commit is contained in:
Claude
2025-11-07 22:12:21 +00:00
parent 9722cdb7f7
commit 6cd4ef0f56
4 changed files with 187 additions and 33 deletions

View File

@@ -651,6 +651,54 @@ class InventoryServiceClient(BaseServiceClient):
error=str(e), tenant_id=tenant_id)
return None
# ================================================================
# DASHBOARD METHODS
# ================================================================
async def get_stock_status(
self,
tenant_id: str
) -> Optional[Dict[str, Any]]:
"""
Get inventory stock status for dashboard insights
Args:
tenant_id: Tenant ID
Returns:
Dict with stock counts and status metrics
"""
try:
return await self.get(
"/inventory/dashboard/stock-status",
tenant_id=tenant_id
)
except Exception as e:
logger.error("Error fetching stock status", error=str(e), tenant_id=tenant_id)
return None
async def get_sustainability_widget(
self,
tenant_id: str
) -> Optional[Dict[str, Any]]:
"""
Get sustainability metrics for dashboard
Args:
tenant_id: Tenant ID
Returns:
Dict with sustainability metrics (waste, CO2, etc.)
"""
try:
return await self.get(
"/inventory/sustainability/widget",
tenant_id=tenant_id
)
except Exception as e:
logger.error("Error fetching sustainability widget", error=str(e), tenant_id=tenant_id)
return None
# ================================================================
# UTILITY METHODS
# ================================================================

View File

@@ -573,3 +573,79 @@ class ProcurementServiceClient(BaseServiceClient):
logger.error("Error triggering price forecasting",
error=str(e), tenant_id=tenant_id)
return None
# ================================================================
# DASHBOARD METHODS
# ================================================================
async def get_pending_purchase_orders(
self,
tenant_id: str,
limit: int = 20
) -> Optional[Dict[str, Any]]:
"""
Get purchase orders pending approval for dashboard
Args:
tenant_id: Tenant ID
limit: Maximum number of POs to return
Returns:
Dict with {"items": [...], "total": n}
"""
try:
return await self.get(
"/procurement/purchase-orders",
tenant_id=tenant_id,
params={"status": "pending_approval", "limit": limit}
)
except Exception as e:
logger.error("Error fetching pending purchase orders", error=str(e), tenant_id=tenant_id)
return None
async def get_critical_alerts(
self,
tenant_id: str,
limit: int = 20
) -> Optional[Dict[str, Any]]:
"""
Get critical alerts for dashboard
Args:
tenant_id: Tenant ID
limit: Maximum number of alerts to return
Returns:
Dict with {"alerts": [...], "total": n}
"""
try:
return await self.get(
"/procurement/alert-processor/alerts",
tenant_id=tenant_id,
params={"severity": "critical", "resolved": False, "limit": limit}
)
except Exception as e:
logger.error("Error fetching critical alerts", error=str(e), tenant_id=tenant_id)
return None
async def get_alerts_summary(
self,
tenant_id: str
) -> Optional[Dict[str, Any]]:
"""
Get alerts summary for dashboard health status
Args:
tenant_id: Tenant ID
Returns:
Dict with counts by severity
"""
try:
return await self.get(
"/procurement/alert-processor/alerts/summary",
tenant_id=tenant_id
)
except Exception as e:
logger.error("Error fetching alerts summary", error=str(e), tenant_id=tenant_id)
return None

View File

@@ -445,6 +445,60 @@ class ProductionServiceClient(BaseServiceClient):
error=str(e), tenant_id=tenant_id)
return None
# ================================================================
# DASHBOARD METHODS
# ================================================================
async def get_todays_batches(
self,
tenant_id: str
) -> Optional[Dict[str, Any]]:
"""
Get today's production batches for dashboard timeline
Args:
tenant_id: Tenant ID
Returns:
Dict with {"batches": [...], "summary": {...}}
"""
try:
return await self.get(
"/production/production-batches/today",
tenant_id=tenant_id
)
except Exception as e:
logger.error("Error fetching today's batches", error=str(e), tenant_id=tenant_id)
return None
async def get_production_batches_by_status(
self,
tenant_id: str,
status: str,
limit: int = 100
) -> Optional[Dict[str, Any]]:
"""
Get production batches filtered by status for dashboard
Args:
tenant_id: Tenant ID
status: Batch status (e.g., "ON_HOLD", "IN_PROGRESS")
limit: Maximum number of batches to return
Returns:
Dict with {"items": [...], "total": n}
"""
try:
return await self.get(
"/production/production-batches",
tenant_id=tenant_id,
params={"status": status, "limit": limit}
)
except Exception as e:
logger.error("Error fetching production batches", error=str(e),
status=status, tenant_id=tenant_id)
return None
# ================================================================
# UTILITY METHODS
# ================================================================