158 lines
6.9 KiB
Python
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() |