Create new services: inventory, recipes, suppliers
This commit is contained in:
222
services/sales/app/services/inventory_client.py
Normal file
222
services/sales/app/services/inventory_client.py
Normal file
@@ -0,0 +1,222 @@
|
||||
# services/sales/app/services/inventory_client.py
|
||||
"""
|
||||
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 app.core.config import settings
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
class InventoryServiceClient:
|
||||
"""Client for communicating with the inventory service"""
|
||||
|
||||
def __init__(self):
|
||||
self.base_url = settings.INVENTORY_SERVICE_URL
|
||||
self.timeout = 30.0
|
||||
|
||||
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 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
|
||||
|
||||
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()
|
||||
)
|
||||
|
||||
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",
|
||||
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:
|
||||
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 []
|
||||
except Exception as e:
|
||||
logger.error("Error searching products in inventory service",
|
||||
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:
|
||||
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 []
|
||||
except Exception as e:
|
||||
logger.error("Error fetching products by category from inventory service",
|
||||
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:
|
||||
"""Get inventory service client instance"""
|
||||
return InventoryServiceClient()
|
||||
Reference in New Issue
Block a user