Files
bakery-ia/services/sales/app/services/inventory_client.py
2025-10-15 21:09:42 +02:00

158 lines
6.9 KiB
Python

# services/sales/app/services/inventory_client.py
"""
Inventory Service Client - Inter-service communication
Handles communication with the inventory service to fetch product data
"""
import structlog
from typing import Dict, Any, List, Optional
from uuid import UUID
from shared.clients.inventory_client import InventoryServiceClient as SharedInventoryClient
from app.core.config import settings
logger = structlog.get_logger()
class InventoryServiceClient:
"""Client for communicating with the inventory service via shared client"""
def __init__(self):
self._shared_client = SharedInventoryClient(settings)
async def classify_products_batch(self, product_list: List[Dict[str, Any]], tenant_id: UUID) -> Optional[Dict[str, Any]]:
"""Classify multiple products for inventory creation"""
try:
# Convert product_list to expected format for shared client
products = []
for item in product_list:
if isinstance(item, str):
# If it's just a product name
products.append({"product_name": item})
elif isinstance(item, dict):
# If it's already a dict, ensure required fields
product_data = {
"product_name": item.get("product_name", item.get("name", str(item))),
"sales_volume": item.get("sales_volume", item.get("total_quantity"))
}
products.append(product_data)
result = await self._shared_client.classify_products_batch(products, str(tenant_id))
if result:
logger.info("Classified products batch",
count=len(products), tenant_id=tenant_id)
return result
except Exception as e:
logger.error("Error in batch product classification",
error=str(e), tenant_id=tenant_id)
return None
async def get_product_by_id(self, product_id: UUID, tenant_id: UUID) -> Optional[Dict[str, Any]]:
"""Get product details from inventory service by ID"""
try:
result = await self._shared_client.get_ingredient_by_id(product_id, str(tenant_id))
if result:
logger.info("Retrieved product from inventory service",
product_id=product_id, tenant_id=tenant_id)
return result
except Exception as e:
logger.error("Error fetching product by ID",
error=str(e), product_id=product_id, tenant_id=tenant_id)
return None
async def get_product_by_sku(self, sku: str, tenant_id: UUID) -> Optional[Dict[str, Any]]:
"""Get product details from inventory service by SKU"""
try:
# Search for product by SKU using shared client
products = await self._shared_client.search_ingredients(
str(tenant_id), search=sku, limit=1
)
if products:
product_data = products[0]
logger.info("Retrieved product by SKU from inventory service",
sku=sku, tenant_id=tenant_id)
return product_data
else:
logger.warning("Product not found by SKU in inventory service",
sku=sku, tenant_id=tenant_id)
return None
except Exception as e:
logger.error("Error fetching product by SKU",
error=str(e), sku=sku, tenant_id=tenant_id)
return None
async def search_products(self, search_term: str, tenant_id: UUID,
product_type: Optional[str] = None) -> List[Dict[str, Any]]:
"""Search products in inventory service"""
try:
products = await self._shared_client.search_ingredients(
str(tenant_id), search=search_term, limit=50
)
logger.info("Searched products in inventory service",
search_term=search_term, count=len(products), tenant_id=tenant_id)
return products
except Exception as e:
logger.error("Error searching products",
error=str(e), search_term=search_term, tenant_id=tenant_id)
return []
async def get_products_by_category(self, category: str, tenant_id: UUID,
product_type: Optional[str] = None) -> List[Dict[str, Any]]:
"""Get products by category from inventory service"""
try:
products = await self._shared_client.search_ingredients(
str(tenant_id), category=category, limit=100
)
logger.info("Retrieved products by category from inventory service",
category=category, count=len(products), tenant_id=tenant_id)
return products
except Exception as e:
logger.error("Error fetching products by category",
error=str(e), category=category, tenant_id=tenant_id)
return []
async def create_ingredient(self, ingredient_data: Dict[str, Any], tenant_id: str) -> Optional[Dict[str, Any]]:
"""Create a new ingredient/product in inventory service"""
try:
result = await self._shared_client.create_ingredient(ingredient_data, tenant_id)
if result:
logger.info("Created ingredient in inventory service",
ingredient_name=ingredient_data.get('name'), tenant_id=tenant_id)
return result
except Exception as e:
logger.error("Error creating ingredient",
error=str(e), ingredient_data=ingredient_data, tenant_id=tenant_id)
return None
async def resolve_or_create_products_batch(
self,
products: List[Dict[str, Any]],
tenant_id: str
) -> Optional[Dict[str, Any]]:
"""Resolve or create multiple products in a single batch operation"""
try:
result = await self._shared_client.resolve_or_create_products_batch(products, tenant_id)
if result:
logger.info("Batch product resolution complete",
created=result.get('created_count', 0),
resolved=result.get('resolved_count', 0),
tenant_id=tenant_id)
return result
except Exception as e:
logger.error("Error in batch product resolution",
error=str(e), products_count=len(products), tenant_id=tenant_id)
return None
# Dependency injection
async def get_inventory_client() -> InventoryServiceClient:
"""Get inventory service client instance"""
return InventoryServiceClient()