Fix new services implementation 1

This commit is contained in:
Urtzi Alfaro
2025-08-13 21:41:00 +02:00
parent 16b8a9d50c
commit 262b3dc9c4
13 changed files with 1702 additions and 1210 deletions

View File

@@ -4,122 +4,83 @@ Inventory Service Client - Inter-service communication
Handles communication with the inventory service to fetch product data
"""
import httpx
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"""
"""Client for communicating with the inventory service via shared client"""
def __init__(self):
self.base_url = settings.INVENTORY_SERVICE_URL
self.timeout = 30.0
self._shared_client = SharedInventoryClient(settings)
async def classify_products_batch(self, product_list: Dict[str, Any], tenant_id: UUID) -> Optional[Dict[str, Any]]:
"""Get product details from inventory service by ID"""
try:
async with httpx.AsyncClient(timeout=self.timeout) as client:
response = await client.post(
f"{self.base_url}/api/v1/tenants/{tenant_id}/inventory/classify-products-batch",
headers=self._get_headers(),
product_list=product_list
)
if response.status_code == 200:
product_data = response.json()
logger.info("Retrieved product from inventory service",
tenant_id=tenant_id)
return product_data
elif response.status_code == 404:
logger.warning("Product not found in inventory service",
tenant_id=tenant_id)
return None
else:
logger.error("Failed to fetch product from inventory service",
status_code=response.status_code,
tenant_id=tenant_id)
return None
except httpx.TimeoutException:
logger.error("Timeout fetching product from inventory service",
tenant_id=tenant_id)
return None
except Exception as e:
logger.error("Error communicating with inventory service",
error=str(e), tenant_id=tenant_id)
return None
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:
async with httpx.AsyncClient(timeout=self.timeout) as client:
response = await client.get(
f"{self.base_url}/api/v1/tenants/{tenant_id}/ingredients/{product_id}",
headers=self._get_headers()
)
if response.status_code == 200:
product_data = response.json()
logger.info("Retrieved product from inventory service",
product_id=product_id, tenant_id=tenant_id)
return product_data
elif response.status_code == 404:
logger.warning("Product not found in inventory service",
product_id=product_id, tenant_id=tenant_id)
return None
else:
logger.error("Failed to fetch product from inventory service",
status_code=response.status_code,
product_id=product_id, tenant_id=tenant_id)
return None
except httpx.TimeoutException:
logger.error("Timeout fetching product from inventory service",
product_id=product_id, tenant_id=tenant_id)
return None
except Exception as e:
logger.error("Error communicating with inventory service",
error=str(e), product_id=product_id, tenant_id=tenant_id)
return None
"""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:
async with httpx.AsyncClient(timeout=self.timeout) as client:
response = await client.get(
f"{self.base_url}/api/v1/tenants/{tenant_id}/ingredients",
params={"sku": sku, "limit": 1},
headers=self._get_headers()
)
# 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
if response.status_code == 200:
data = response.json()
products = data.get("items", [])
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
else:
logger.error("Failed to fetch product by SKU from inventory service",
status_code=response.status_code,
sku=sku, tenant_id=tenant_id)
return None
except httpx.TimeoutException:
logger.error("Timeout fetching product by SKU from inventory service",
sku=sku, tenant_id=tenant_id)
return None
except Exception as e:
logger.error("Error communicating with inventory service for SKU",
logger.error("Error fetching product by SKU",
error=str(e), sku=sku, tenant_id=tenant_id)
return None
@@ -127,38 +88,16 @@ class InventoryServiceClient:
product_type: Optional[str] = None) -> List[Dict[str, Any]]:
"""Search products in inventory service"""
try:
params = {
"search": search_term,
"limit": 50
}
if product_type:
params["product_type"] = product_type
async with httpx.AsyncClient(timeout=self.timeout) as client:
response = await client.get(
f"{self.base_url}/api/v1/tenants/{tenant_id}/ingredients",
params=params,
headers=self._get_headers()
)
if response.status_code == 200:
data = response.json()
products = data.get("items", [])
logger.info("Searched products in inventory service",
search_term=search_term, count=len(products), tenant_id=tenant_id)
return products
else:
logger.error("Failed to search products in inventory service",
status_code=response.status_code,
search_term=search_term, tenant_id=tenant_id)
return []
except httpx.TimeoutException:
logger.error("Timeout searching products in inventory service",
search_term=search_term, tenant_id=tenant_id)
return []
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 in inventory service",
logger.error("Error searching products",
error=str(e), search_term=search_term, tenant_id=tenant_id)
return []
@@ -166,55 +105,18 @@ class InventoryServiceClient:
product_type: Optional[str] = None) -> List[Dict[str, Any]]:
"""Get products by category from inventory service"""
try:
params = {
"limit": 100
}
if product_type == "ingredient":
params["ingredient_category"] = category
elif product_type == "finished_product":
params["product_category"] = category
else:
# Search in both categories if type not specified
params["category"] = category
async with httpx.AsyncClient(timeout=self.timeout) as client:
response = await client.get(
f"{self.base_url}/api/v1/tenants/{tenant_id}/ingredients",
params=params,
headers=self._get_headers()
)
if response.status_code == 200:
data = response.json()
products = data.get("items", [])
logger.info("Retrieved products by category from inventory service",
category=category, count=len(products), tenant_id=tenant_id)
return products
else:
logger.error("Failed to fetch products by category from inventory service",
status_code=response.status_code,
category=category, tenant_id=tenant_id)
return []
except httpx.TimeoutException:
logger.error("Timeout fetching products by category from inventory service",
category=category, tenant_id=tenant_id)
return []
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 from inventory service",
logger.error("Error fetching products by category",
error=str(e), category=category, tenant_id=tenant_id)
return []
# Cache synchronization removed - no longer needed with pure inventory reference approach
def _get_headers(self) -> Dict[str, str]:
"""Get headers for inventory service requests"""
return {
"Content-Type": "application/json",
"X-Service-Name": "sales-service",
# Add authentication headers if needed
}
# Dependency injection
async def get_inventory_client() -> InventoryServiceClient: