Add more services
This commit is contained in:
284
services/orders/app/repositories/base_repository.py
Normal file
284
services/orders/app/repositories/base_repository.py
Normal file
@@ -0,0 +1,284 @@
|
||||
# ================================================================
|
||||
# services/orders/app/repositories/base_repository.py
|
||||
# ================================================================
|
||||
"""
|
||||
Base repository class for Orders Service
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Generic, List, Optional, Type, TypeVar, Union
|
||||
from uuid import UUID
|
||||
from sqlalchemy import select, update, delete, func, and_, or_
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload, joinedload
|
||||
import structlog
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
ModelType = TypeVar("ModelType", bound=Base)
|
||||
CreateSchemaType = TypeVar("CreateSchemaType")
|
||||
UpdateSchemaType = TypeVar("UpdateSchemaType")
|
||||
|
||||
|
||||
class BaseRepository(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
|
||||
"""Base repository with common CRUD operations"""
|
||||
|
||||
def __init__(self, model: Type[ModelType]):
|
||||
self.model = model
|
||||
|
||||
async def get(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
id: UUID,
|
||||
tenant_id: Optional[UUID] = None
|
||||
) -> Optional[ModelType]:
|
||||
"""Get a single record by ID with optional tenant filtering"""
|
||||
try:
|
||||
query = select(self.model).where(self.model.id == id)
|
||||
|
||||
# Add tenant filtering if tenant_id is provided and model has tenant_id field
|
||||
if tenant_id and hasattr(self.model, 'tenant_id'):
|
||||
query = query.where(self.model.tenant_id == tenant_id)
|
||||
|
||||
result = await db.execute(query)
|
||||
return result.scalar_one_or_none()
|
||||
except Exception as e:
|
||||
logger.error("Error getting record", model=self.model.__name__, id=str(id), error=str(e))
|
||||
raise
|
||||
|
||||
async def get_by_field(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
field_name: str,
|
||||
field_value: Any,
|
||||
tenant_id: Optional[UUID] = None
|
||||
) -> Optional[ModelType]:
|
||||
"""Get a single record by field value"""
|
||||
try:
|
||||
field = getattr(self.model, field_name)
|
||||
query = select(self.model).where(field == field_value)
|
||||
|
||||
if tenant_id and hasattr(self.model, 'tenant_id'):
|
||||
query = query.where(self.model.tenant_id == tenant_id)
|
||||
|
||||
result = await db.execute(query)
|
||||
return result.scalar_one_or_none()
|
||||
except Exception as e:
|
||||
logger.error("Error getting record by field",
|
||||
model=self.model.__name__,
|
||||
field_name=field_name,
|
||||
field_value=str(field_value),
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def get_multi(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
tenant_id: Optional[UUID] = None,
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
filters: Optional[Dict[str, Any]] = None,
|
||||
order_by: Optional[str] = None,
|
||||
order_desc: bool = False
|
||||
) -> List[ModelType]:
|
||||
"""Get multiple records with filtering, pagination, and sorting"""
|
||||
try:
|
||||
query = select(self.model)
|
||||
|
||||
# Add tenant filtering
|
||||
if tenant_id and hasattr(self.model, 'tenant_id'):
|
||||
query = query.where(self.model.tenant_id == tenant_id)
|
||||
|
||||
# Add additional filters
|
||||
if filters:
|
||||
for field_name, field_value in filters.items():
|
||||
if hasattr(self.model, field_name):
|
||||
field = getattr(self.model, field_name)
|
||||
if isinstance(field_value, list):
|
||||
query = query.where(field.in_(field_value))
|
||||
else:
|
||||
query = query.where(field == field_value)
|
||||
|
||||
# Add ordering
|
||||
if order_by and hasattr(self.model, order_by):
|
||||
order_field = getattr(self.model, order_by)
|
||||
if order_desc:
|
||||
query = query.order_by(order_field.desc())
|
||||
else:
|
||||
query = query.order_by(order_field)
|
||||
|
||||
# Add pagination
|
||||
query = query.offset(skip).limit(limit)
|
||||
|
||||
result = await db.execute(query)
|
||||
return result.scalars().all()
|
||||
except Exception as e:
|
||||
logger.error("Error getting multiple records",
|
||||
model=self.model.__name__,
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def count(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
tenant_id: Optional[UUID] = None,
|
||||
filters: Optional[Dict[str, Any]] = None
|
||||
) -> int:
|
||||
"""Count records with optional filtering"""
|
||||
try:
|
||||
query = select(func.count()).select_from(self.model)
|
||||
|
||||
# Add tenant filtering
|
||||
if tenant_id and hasattr(self.model, 'tenant_id'):
|
||||
query = query.where(self.model.tenant_id == tenant_id)
|
||||
|
||||
# Add additional filters
|
||||
if filters:
|
||||
for field_name, field_value in filters.items():
|
||||
if hasattr(self.model, field_name):
|
||||
field = getattr(self.model, field_name)
|
||||
if isinstance(field_value, list):
|
||||
query = query.where(field.in_(field_value))
|
||||
else:
|
||||
query = query.where(field == field_value)
|
||||
|
||||
result = await db.execute(query)
|
||||
return result.scalar()
|
||||
except Exception as e:
|
||||
logger.error("Error counting records",
|
||||
model=self.model.__name__,
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def create(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
*,
|
||||
obj_in: CreateSchemaType,
|
||||
created_by: Optional[UUID] = None
|
||||
) -> ModelType:
|
||||
"""Create a new record"""
|
||||
try:
|
||||
# Convert schema to dict
|
||||
if hasattr(obj_in, 'dict'):
|
||||
obj_data = obj_in.dict()
|
||||
else:
|
||||
obj_data = obj_in
|
||||
|
||||
# Add created_by if the model supports it
|
||||
if created_by and hasattr(self.model, 'created_by'):
|
||||
obj_data['created_by'] = created_by
|
||||
|
||||
# Create model instance
|
||||
db_obj = self.model(**obj_data)
|
||||
|
||||
# Add to session and flush to get ID
|
||||
db.add(db_obj)
|
||||
await db.flush()
|
||||
await db.refresh(db_obj)
|
||||
|
||||
logger.info("Record created",
|
||||
model=self.model.__name__,
|
||||
id=str(db_obj.id))
|
||||
|
||||
return db_obj
|
||||
except Exception as e:
|
||||
logger.error("Error creating record",
|
||||
model=self.model.__name__,
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def update(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
*,
|
||||
db_obj: ModelType,
|
||||
obj_in: Union[UpdateSchemaType, Dict[str, Any]],
|
||||
updated_by: Optional[UUID] = None
|
||||
) -> ModelType:
|
||||
"""Update an existing record"""
|
||||
try:
|
||||
# Convert schema to dict
|
||||
if hasattr(obj_in, 'dict'):
|
||||
update_data = obj_in.dict(exclude_unset=True)
|
||||
else:
|
||||
update_data = obj_in
|
||||
|
||||
# Add updated_by if the model supports it
|
||||
if updated_by and hasattr(self.model, 'updated_by'):
|
||||
update_data['updated_by'] = updated_by
|
||||
|
||||
# Update fields
|
||||
for field, value in update_data.items():
|
||||
if hasattr(db_obj, field):
|
||||
setattr(db_obj, field, value)
|
||||
|
||||
# Flush changes
|
||||
await db.flush()
|
||||
await db.refresh(db_obj)
|
||||
|
||||
logger.info("Record updated",
|
||||
model=self.model.__name__,
|
||||
id=str(db_obj.id))
|
||||
|
||||
return db_obj
|
||||
except Exception as e:
|
||||
logger.error("Error updating record",
|
||||
model=self.model.__name__,
|
||||
id=str(db_obj.id),
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def delete(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
*,
|
||||
id: UUID,
|
||||
tenant_id: Optional[UUID] = None
|
||||
) -> Optional[ModelType]:
|
||||
"""Delete a record by ID"""
|
||||
try:
|
||||
# First get the record
|
||||
db_obj = await self.get(db, id=id, tenant_id=tenant_id)
|
||||
if not db_obj:
|
||||
return None
|
||||
|
||||
# Delete the record
|
||||
await db.delete(db_obj)
|
||||
await db.flush()
|
||||
|
||||
logger.info("Record deleted",
|
||||
model=self.model.__name__,
|
||||
id=str(id))
|
||||
|
||||
return db_obj
|
||||
except Exception as e:
|
||||
logger.error("Error deleting record",
|
||||
model=self.model.__name__,
|
||||
id=str(id),
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def exists(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
id: UUID,
|
||||
tenant_id: Optional[UUID] = None
|
||||
) -> bool:
|
||||
"""Check if a record exists"""
|
||||
try:
|
||||
query = select(func.count()).select_from(self.model).where(self.model.id == id)
|
||||
|
||||
if tenant_id and hasattr(self.model, 'tenant_id'):
|
||||
query = query.where(self.model.tenant_id == tenant_id)
|
||||
|
||||
result = await db.execute(query)
|
||||
count = result.scalar()
|
||||
return count > 0
|
||||
except Exception as e:
|
||||
logger.error("Error checking record existence",
|
||||
model=self.model.__name__,
|
||||
id=str(id),
|
||||
error=str(e))
|
||||
raise
|
||||
464
services/orders/app/repositories/order_repository.py
Normal file
464
services/orders/app/repositories/order_repository.py
Normal file
@@ -0,0 +1,464 @@
|
||||
# ================================================================
|
||||
# services/orders/app/repositories/order_repository.py
|
||||
# ================================================================
|
||||
"""
|
||||
Order-related repositories for Orders Service
|
||||
"""
|
||||
|
||||
from datetime import datetime, date
|
||||
from decimal import Decimal
|
||||
from typing import List, Optional, Dict, Any
|
||||
from uuid import UUID
|
||||
from sqlalchemy import select, func, and_, or_, case, extract
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload, joinedload
|
||||
import structlog
|
||||
|
||||
from app.models.customer import Customer
|
||||
from app.models.order import CustomerOrder, OrderItem, OrderStatusHistory
|
||||
from app.schemas.order_schemas import OrderCreate, OrderUpdate, OrderItemCreate, OrderItemUpdate
|
||||
from app.repositories.base_repository import BaseRepository
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
|
||||
class CustomerRepository(BaseRepository[Customer, dict, dict]):
|
||||
"""Repository for customer operations"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(Customer)
|
||||
|
||||
async def get_by_customer_code(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
customer_code: str,
|
||||
tenant_id: UUID
|
||||
) -> Optional[Customer]:
|
||||
"""Get customer by customer code within tenant"""
|
||||
try:
|
||||
query = select(Customer).where(
|
||||
and_(
|
||||
Customer.customer_code == customer_code,
|
||||
Customer.tenant_id == tenant_id
|
||||
)
|
||||
)
|
||||
result = await db.execute(query)
|
||||
return result.scalar_one_or_none()
|
||||
except Exception as e:
|
||||
logger.error("Error getting customer by code",
|
||||
customer_code=customer_code,
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def get_active_customers(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
tenant_id: UUID,
|
||||
skip: int = 0,
|
||||
limit: int = 100
|
||||
) -> List[Customer]:
|
||||
"""Get active customers for a tenant"""
|
||||
try:
|
||||
query = select(Customer).where(
|
||||
and_(
|
||||
Customer.tenant_id == tenant_id,
|
||||
Customer.is_active == True
|
||||
)
|
||||
).order_by(Customer.name).offset(skip).limit(limit)
|
||||
|
||||
result = await db.execute(query)
|
||||
return result.scalars().all()
|
||||
except Exception as e:
|
||||
logger.error("Error getting active customers", error=str(e))
|
||||
raise
|
||||
|
||||
async def update_customer_metrics(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
customer_id: UUID,
|
||||
order_value: Decimal,
|
||||
order_date: datetime
|
||||
):
|
||||
"""Update customer metrics after order creation"""
|
||||
try:
|
||||
customer = await self.get(db, customer_id)
|
||||
if customer:
|
||||
customer.total_orders += 1
|
||||
customer.total_spent += order_value
|
||||
customer.average_order_value = customer.total_spent / customer.total_orders
|
||||
customer.last_order_date = order_date
|
||||
|
||||
await db.flush()
|
||||
logger.info("Customer metrics updated",
|
||||
customer_id=str(customer_id),
|
||||
new_total_spent=str(customer.total_spent))
|
||||
except Exception as e:
|
||||
logger.error("Error updating customer metrics",
|
||||
customer_id=str(customer_id),
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
|
||||
class OrderRepository(BaseRepository[CustomerOrder, OrderCreate, OrderUpdate]):
|
||||
"""Repository for customer order operations"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(CustomerOrder)
|
||||
|
||||
async def get_with_items(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
order_id: UUID,
|
||||
tenant_id: UUID
|
||||
) -> Optional[CustomerOrder]:
|
||||
"""Get order with all its items and customer info"""
|
||||
try:
|
||||
query = select(CustomerOrder).options(
|
||||
selectinload(CustomerOrder.items),
|
||||
selectinload(CustomerOrder.customer),
|
||||
selectinload(CustomerOrder.status_history)
|
||||
).where(
|
||||
and_(
|
||||
CustomerOrder.id == order_id,
|
||||
CustomerOrder.tenant_id == tenant_id
|
||||
)
|
||||
)
|
||||
result = await db.execute(query)
|
||||
return result.scalar_one_or_none()
|
||||
except Exception as e:
|
||||
logger.error("Error getting order with items",
|
||||
order_id=str(order_id),
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def get_by_order_number(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
order_number: str,
|
||||
tenant_id: UUID
|
||||
) -> Optional[CustomerOrder]:
|
||||
"""Get order by order number within tenant"""
|
||||
try:
|
||||
query = select(CustomerOrder).where(
|
||||
and_(
|
||||
CustomerOrder.order_number == order_number,
|
||||
CustomerOrder.tenant_id == tenant_id
|
||||
)
|
||||
)
|
||||
result = await db.execute(query)
|
||||
return result.scalar_one_or_none()
|
||||
except Exception as e:
|
||||
logger.error("Error getting order by number",
|
||||
order_number=order_number,
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def get_orders_by_status(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
tenant_id: UUID,
|
||||
status: str,
|
||||
skip: int = 0,
|
||||
limit: int = 100
|
||||
) -> List[CustomerOrder]:
|
||||
"""Get orders by status"""
|
||||
try:
|
||||
query = select(CustomerOrder).options(
|
||||
selectinload(CustomerOrder.customer)
|
||||
).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
CustomerOrder.status == status
|
||||
)
|
||||
).order_by(CustomerOrder.order_date.desc()).offset(skip).limit(limit)
|
||||
|
||||
result = await db.execute(query)
|
||||
return result.scalars().all()
|
||||
except Exception as e:
|
||||
logger.error("Error getting orders by status",
|
||||
status=status,
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def get_orders_by_date_range(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
tenant_id: UUID,
|
||||
start_date: date,
|
||||
end_date: date,
|
||||
skip: int = 0,
|
||||
limit: int = 100
|
||||
) -> List[CustomerOrder]:
|
||||
"""Get orders within date range"""
|
||||
try:
|
||||
query = select(CustomerOrder).options(
|
||||
selectinload(CustomerOrder.customer),
|
||||
selectinload(CustomerOrder.items)
|
||||
).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
func.date(CustomerOrder.order_date) >= start_date,
|
||||
func.date(CustomerOrder.order_date) <= end_date
|
||||
)
|
||||
).order_by(CustomerOrder.order_date.desc()).offset(skip).limit(limit)
|
||||
|
||||
result = await db.execute(query)
|
||||
return result.scalars().all()
|
||||
except Exception as e:
|
||||
logger.error("Error getting orders by date range",
|
||||
start_date=str(start_date),
|
||||
end_date=str(end_date),
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def get_pending_orders_by_delivery_date(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
tenant_id: UUID,
|
||||
delivery_date: date
|
||||
) -> List[CustomerOrder]:
|
||||
"""Get pending orders for a specific delivery date"""
|
||||
try:
|
||||
query = select(CustomerOrder).options(
|
||||
selectinload(CustomerOrder.items),
|
||||
selectinload(CustomerOrder.customer)
|
||||
).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
CustomerOrder.status.in_(["pending", "confirmed", "in_production"]),
|
||||
func.date(CustomerOrder.requested_delivery_date) == delivery_date
|
||||
)
|
||||
).order_by(CustomerOrder.priority.desc(), CustomerOrder.order_date)
|
||||
|
||||
result = await db.execute(query)
|
||||
return result.scalars().all()
|
||||
except Exception as e:
|
||||
logger.error("Error getting pending orders by delivery date",
|
||||
delivery_date=str(delivery_date),
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
async def get_dashboard_metrics(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
tenant_id: UUID
|
||||
) -> Dict[str, Any]:
|
||||
"""Get dashboard metrics for orders"""
|
||||
try:
|
||||
# Today's metrics
|
||||
today = datetime.now().date()
|
||||
week_start = today - timedelta(days=today.weekday())
|
||||
month_start = today.replace(day=1)
|
||||
|
||||
# Order counts by period
|
||||
orders_today = await db.execute(
|
||||
select(func.count()).select_from(CustomerOrder).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
func.date(CustomerOrder.order_date) == today
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
orders_week = await db.execute(
|
||||
select(func.count()).select_from(CustomerOrder).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
func.date(CustomerOrder.order_date) >= week_start
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
orders_month = await db.execute(
|
||||
select(func.count()).select_from(CustomerOrder).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
func.date(CustomerOrder.order_date) >= month_start
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Revenue by period
|
||||
revenue_today = await db.execute(
|
||||
select(func.coalesce(func.sum(CustomerOrder.total_amount), 0)).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
func.date(CustomerOrder.order_date) == today,
|
||||
CustomerOrder.status != "cancelled"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
revenue_week = await db.execute(
|
||||
select(func.coalesce(func.sum(CustomerOrder.total_amount), 0)).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
func.date(CustomerOrder.order_date) >= week_start,
|
||||
CustomerOrder.status != "cancelled"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
revenue_month = await db.execute(
|
||||
select(func.coalesce(func.sum(CustomerOrder.total_amount), 0)).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
func.date(CustomerOrder.order_date) >= month_start,
|
||||
CustomerOrder.status != "cancelled"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# Status breakdown
|
||||
status_counts = await db.execute(
|
||||
select(CustomerOrder.status, func.count()).select_from(CustomerOrder).where(
|
||||
CustomerOrder.tenant_id == tenant_id
|
||||
).group_by(CustomerOrder.status)
|
||||
)
|
||||
|
||||
status_breakdown = {status: count for status, count in status_counts.fetchall()}
|
||||
|
||||
# Average order value
|
||||
avg_order_value = await db.execute(
|
||||
select(func.coalesce(func.avg(CustomerOrder.total_amount), 0)).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
CustomerOrder.status != "cancelled"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return {
|
||||
"total_orders_today": orders_today.scalar(),
|
||||
"total_orders_this_week": orders_week.scalar(),
|
||||
"total_orders_this_month": orders_month.scalar(),
|
||||
"revenue_today": revenue_today.scalar(),
|
||||
"revenue_this_week": revenue_week.scalar(),
|
||||
"revenue_this_month": revenue_month.scalar(),
|
||||
"status_breakdown": status_breakdown,
|
||||
"average_order_value": avg_order_value.scalar()
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error("Error getting dashboard metrics", error=str(e))
|
||||
raise
|
||||
|
||||
async def detect_business_model(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
tenant_id: UUID,
|
||||
lookback_days: int = 30
|
||||
) -> Optional[str]:
|
||||
"""Detect business model based on order patterns"""
|
||||
try:
|
||||
cutoff_date = datetime.now().date() - timedelta(days=lookback_days)
|
||||
|
||||
# Analyze order patterns
|
||||
query = select(
|
||||
func.count().label("total_orders"),
|
||||
func.avg(CustomerOrder.total_amount).label("avg_order_value"),
|
||||
func.count(func.distinct(CustomerOrder.customer_id)).label("unique_customers"),
|
||||
func.sum(
|
||||
case(
|
||||
[(CustomerOrder.order_type == "rush", 1)],
|
||||
else_=0
|
||||
)
|
||||
).label("rush_orders"),
|
||||
func.sum(
|
||||
case(
|
||||
[(CustomerOrder.sales_channel == "wholesale", 1)],
|
||||
else_=0
|
||||
)
|
||||
).label("wholesale_orders")
|
||||
).where(
|
||||
and_(
|
||||
CustomerOrder.tenant_id == tenant_id,
|
||||
func.date(CustomerOrder.order_date) >= cutoff_date
|
||||
)
|
||||
)
|
||||
|
||||
result = await db.execute(query)
|
||||
metrics = result.fetchone()
|
||||
|
||||
if not metrics or metrics.total_orders == 0:
|
||||
return None
|
||||
|
||||
# Business model detection logic
|
||||
orders_per_customer = metrics.total_orders / metrics.unique_customers
|
||||
wholesale_ratio = metrics.wholesale_orders / metrics.total_orders
|
||||
rush_ratio = metrics.rush_orders / metrics.total_orders
|
||||
|
||||
if wholesale_ratio > 0.6 or orders_per_customer > 20:
|
||||
return "central_bakery"
|
||||
else:
|
||||
return "individual_bakery"
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Error detecting business model", error=str(e))
|
||||
return None
|
||||
|
||||
|
||||
class OrderItemRepository(BaseRepository[OrderItem, OrderItemCreate, OrderItemUpdate]):
|
||||
"""Repository for order item operations"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(OrderItem)
|
||||
|
||||
async def get_items_by_order(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
order_id: UUID
|
||||
) -> List[OrderItem]:
|
||||
"""Get all items for an order"""
|
||||
try:
|
||||
query = select(OrderItem).where(OrderItem.order_id == order_id)
|
||||
result = await db.execute(query)
|
||||
return result.scalars().all()
|
||||
except Exception as e:
|
||||
logger.error("Error getting order items",
|
||||
order_id=str(order_id),
|
||||
error=str(e))
|
||||
raise
|
||||
|
||||
|
||||
class OrderStatusHistoryRepository(BaseRepository[OrderStatusHistory, dict, dict]):
|
||||
"""Repository for order status history operations"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(OrderStatusHistory)
|
||||
|
||||
async def create_status_change(
|
||||
self,
|
||||
db: AsyncSession,
|
||||
order_id: UUID,
|
||||
from_status: Optional[str],
|
||||
to_status: str,
|
||||
change_reason: Optional[str] = None,
|
||||
changed_by: Optional[UUID] = None,
|
||||
event_data: Optional[Dict[str, Any]] = None
|
||||
) -> OrderStatusHistory:
|
||||
"""Create a status change record"""
|
||||
try:
|
||||
status_history = OrderStatusHistory(
|
||||
order_id=order_id,
|
||||
from_status=from_status,
|
||||
to_status=to_status,
|
||||
change_reason=change_reason,
|
||||
changed_by=changed_by,
|
||||
event_data=event_data
|
||||
)
|
||||
|
||||
db.add(status_history)
|
||||
await db.flush()
|
||||
await db.refresh(status_history)
|
||||
|
||||
logger.info("Status change recorded",
|
||||
order_id=str(order_id),
|
||||
from_status=from_status,
|
||||
to_status=to_status)
|
||||
|
||||
return status_history
|
||||
except Exception as e:
|
||||
logger.error("Error creating status change",
|
||||
order_id=str(order_id),
|
||||
error=str(e))
|
||||
raise
|
||||
Reference in New Issue
Block a user