Fix new services implementation 3

This commit is contained in:
Urtzi Alfaro
2025-08-14 16:47:34 +02:00
parent 0951547e92
commit 03737430ee
51 changed files with 657 additions and 982 deletions

View File

@@ -464,47 +464,47 @@ async def get_orders_by_supplier(
raise HTTPException(status_code=500, detail="Failed to retrieve orders by supplier")
@router.get("/ingredients/{ingredient_id}/history")
async def get_ingredient_purchase_history(
ingredient_id: UUID = Path(..., description="Ingredient ID"),
@router.get("/inventory-products/{inventory_product_id}/history")
async def get_inventory_product_purchase_history(
inventory_product_id: UUID = Path(..., description="Inventory Product ID"),
days_back: int = Query(90, ge=1, le=365, description="Number of days to look back"),
current_user: UserInfo = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get purchase history for a specific ingredient"""
"""Get purchase history for a specific inventory product"""
require_permissions(current_user, ["purchase_orders:read"])
try:
service = PurchaseOrderService(db)
history = await service.get_ingredient_purchase_history(
history = await service.get_inventory_product_purchase_history(
tenant_id=current_user.tenant_id,
ingredient_id=ingredient_id,
inventory_product_id=inventory_product_id,
days_back=days_back
)
return history
except Exception as e:
logger.error("Error getting ingredient purchase history", ingredient_id=str(ingredient_id), error=str(e))
raise HTTPException(status_code=500, detail="Failed to retrieve ingredient purchase history")
logger.error("Error getting inventory product purchase history", inventory_product_id=str(inventory_product_id), error=str(e))
raise HTTPException(status_code=500, detail="Failed to retrieve inventory product purchase history")
@router.get("/ingredients/top-purchased")
async def get_top_purchased_ingredients(
@router.get("/inventory-products/top-purchased")
async def get_top_purchased_inventory_products(
days_back: int = Query(30, ge=1, le=365, description="Number of days to look back"),
limit: int = Query(10, ge=1, le=50, description="Number of top ingredients to return"),
limit: int = Query(10, ge=1, le=50, description="Number of top inventory products to return"),
current_user: UserInfo = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Get most purchased ingredients by value"""
"""Get most purchased inventory products by value"""
require_permissions(current_user, ["purchase_orders:read"])
try:
service = PurchaseOrderService(db)
ingredients = await service.get_top_purchased_ingredients(
products = await service.get_top_purchased_inventory_products(
tenant_id=current_user.tenant_id,
days_back=days_back,
limit=limit
)
return ingredients
return products
except Exception as e:
logger.error("Error getting top purchased ingredients", error=str(e))
raise HTTPException(status_code=500, detail="Failed to retrieve top purchased ingredients")
logger.error("Error getting top purchased inventory products", error=str(e))
raise HTTPException(status_code=500, detail="Failed to retrieve top purchased inventory products")

View File

@@ -186,9 +186,8 @@ class SupplierPriceList(Base):
supplier_id = Column(UUID(as_uuid=True), ForeignKey('suppliers.id'), nullable=False, index=True)
# Product identification (references inventory service)
ingredient_id = Column(UUID(as_uuid=True), nullable=False, index=True) # Reference to inventory.ingredients
inventory_product_id = Column(UUID(as_uuid=True), nullable=False, index=True) # Reference to inventory products
product_code = Column(String(100), nullable=True) # Supplier's product code
product_name = Column(String(255), nullable=False)
# Pricing information
unit_price = Column(Numeric(10, 4), nullable=False)
@@ -228,7 +227,7 @@ class SupplierPriceList(Base):
# Indexes
__table_args__ = (
Index('ix_price_lists_tenant_supplier', 'tenant_id', 'supplier_id'),
Index('ix_price_lists_ingredient', 'ingredient_id'),
Index('ix_price_lists_inventory_product', 'inventory_product_id'),
Index('ix_price_lists_active', 'is_active'),
Index('ix_price_lists_effective_date', 'effective_date'),
)
@@ -317,9 +316,8 @@ class PurchaseOrderItem(Base):
price_list_item_id = Column(UUID(as_uuid=True), ForeignKey('supplier_price_lists.id'), nullable=True, index=True)
# Product identification
ingredient_id = Column(UUID(as_uuid=True), nullable=False, index=True) # Reference to inventory.ingredients
inventory_product_id = Column(UUID(as_uuid=True), nullable=False, index=True) # Reference to inventory products
product_code = Column(String(100), nullable=True) # Supplier's product code
product_name = Column(String(255), nullable=False)
# Order quantities
ordered_quantity = Column(Integer, nullable=False)
@@ -347,7 +345,7 @@ class PurchaseOrderItem(Base):
# Indexes
__table_args__ = (
Index('ix_po_items_tenant_po', 'tenant_id', 'purchase_order_id'),
Index('ix_po_items_ingredient', 'ingredient_id'),
Index('ix_po_items_inventory_product', 'inventory_product_id'),
)
@@ -421,8 +419,7 @@ class DeliveryItem(Base):
purchase_order_item_id = Column(UUID(as_uuid=True), ForeignKey('purchase_order_items.id'), nullable=False, index=True)
# Product identification
ingredient_id = Column(UUID(as_uuid=True), nullable=False, index=True)
product_name = Column(String(255), nullable=False)
inventory_product_id = Column(UUID(as_uuid=True), nullable=False, index=True)
# Delivery quantities
ordered_quantity = Column(Integer, nullable=False)
@@ -451,7 +448,7 @@ class DeliveryItem(Base):
# Indexes
__table_args__ = (
Index('ix_delivery_items_tenant_delivery', 'tenant_id', 'delivery_id'),
Index('ix_delivery_items_ingredient', 'ingredient_id'),
Index('ix_delivery_items_inventory_product', 'inventory_product_id'),
)

View File

@@ -28,19 +28,19 @@ class PurchaseOrderItemRepository(BaseRepository[PurchaseOrderItem]):
.all()
)
def get_by_ingredient(
def get_by_inventory_product(
self,
tenant_id: UUID,
ingredient_id: UUID,
inventory_product_id: UUID,
limit: int = 20
) -> List[PurchaseOrderItem]:
"""Get recent order items for a specific ingredient"""
"""Get recent order items for a specific inventory product"""
return (
self.db.query(self.model)
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.ingredient_id == ingredient_id
self.model.inventory_product_id == inventory_product_id
)
)
.order_by(self.model.created_at.desc())
@@ -103,7 +103,7 @@ class PurchaseOrderItemRepository(BaseRepository[PurchaseOrderItem]):
def get_pending_receipt_items(
self,
tenant_id: UUID,
ingredient_id: Optional[UUID] = None
inventory_product_id: Optional[UUID] = None
) -> List[PurchaseOrderItem]:
"""Get items pending receipt (not yet delivered)"""
query = (
@@ -116,8 +116,8 @@ class PurchaseOrderItemRepository(BaseRepository[PurchaseOrderItem]):
)
)
if ingredient_id:
query = query.filter(self.model.ingredient_id == ingredient_id)
if inventory_product_id:
query = query.filter(self.model.inventory_product_id == inventory_product_id)
return query.order_by(self.model.created_at).all()
@@ -134,13 +134,13 @@ class PurchaseOrderItemRepository(BaseRepository[PurchaseOrderItem]):
self.db.refresh(item)
return item
def get_ingredient_purchase_history(
def get_inventory_product_purchase_history(
self,
tenant_id: UUID,
ingredient_id: UUID,
inventory_product_id: UUID,
days_back: int = 90
) -> Dict[str, Any]:
"""Get purchase history and analytics for an ingredient"""
"""Get purchase history and analytics for an inventory product"""
from datetime import timedelta
cutoff_date = datetime.utcnow() - timedelta(days=days_back)
@@ -151,7 +151,7 @@ class PurchaseOrderItemRepository(BaseRepository[PurchaseOrderItem]):
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.ingredient_id == ingredient_id,
self.model.inventory_product_id == inventory_product_id,
self.model.created_at >= cutoff_date
)
)
@@ -202,22 +202,21 @@ class PurchaseOrderItemRepository(BaseRepository[PurchaseOrderItem]):
"price_trend": price_trend
}
def get_top_purchased_ingredients(
def get_top_purchased_inventory_products(
self,
tenant_id: UUID,
days_back: int = 30,
limit: int = 10
) -> List[Dict[str, Any]]:
"""Get most purchased ingredients by quantity or value"""
"""Get most purchased inventory products by quantity or value"""
from datetime import timedelta
cutoff_date = datetime.utcnow() - timedelta(days=days_back)
# Group by ingredient and calculate totals
# Group by inventory product and calculate totals
results = (
self.db.query(
self.model.ingredient_id,
self.model.product_name,
self.model.inventory_product_id,
self.model.unit_of_measure,
func.sum(self.model.ordered_quantity).label('total_quantity'),
func.sum(self.model.line_total).label('total_amount'),
@@ -231,8 +230,7 @@ class PurchaseOrderItemRepository(BaseRepository[PurchaseOrderItem]):
)
)
.group_by(
self.model.ingredient_id,
self.model.product_name,
self.model.inventory_product_id,
self.model.unit_of_measure
)
.order_by(func.sum(self.model.line_total).desc())
@@ -242,8 +240,7 @@ class PurchaseOrderItemRepository(BaseRepository[PurchaseOrderItem]):
return [
{
"ingredient_id": str(row.ingredient_id),
"product_name": row.product_name,
"inventory_product_id": str(row.inventory_product_id),
"unit_of_measure": row.unit_of_measure,
"total_quantity": int(row.total_quantity),
"total_amount": round(float(row.total_amount), 2),

View File

@@ -186,9 +186,8 @@ class SupplierSummary(BaseModel):
class PurchaseOrderItemCreate(BaseModel):
"""Schema for creating purchase order items"""
ingredient_id: UUID
inventory_product_id: UUID
product_code: Optional[str] = Field(None, max_length=100)
product_name: str = Field(..., min_length=1, max_length=255)
ordered_quantity: int = Field(..., gt=0)
unit_of_measure: str = Field(..., max_length=20)
unit_price: Decimal = Field(..., gt=0)
@@ -210,9 +209,8 @@ class PurchaseOrderItemResponse(BaseModel):
tenant_id: UUID
purchase_order_id: UUID
price_list_item_id: Optional[UUID] = None
ingredient_id: UUID
inventory_product_id: UUID
product_code: Optional[str] = None
product_name: str
ordered_quantity: int
unit_of_measure: str
unit_price: Decimal
@@ -376,8 +374,7 @@ class PurchaseOrderSummary(BaseModel):
class DeliveryItemCreate(BaseModel):
"""Schema for creating delivery items"""
purchase_order_item_id: UUID
ingredient_id: UUID
product_name: str = Field(..., min_length=1, max_length=255)
inventory_product_id: UUID
ordered_quantity: int = Field(..., gt=0)
delivered_quantity: int = Field(..., ge=0)
accepted_quantity: int = Field(..., ge=0)
@@ -400,8 +397,7 @@ class DeliveryItemResponse(BaseModel):
tenant_id: UUID
delivery_id: UUID
purchase_order_item_id: UUID
ingredient_id: UUID
product_name: str
inventory_product_id: UUID
ordered_quantity: int
delivered_quantity: int
accepted_quantity: int

View File

@@ -444,24 +444,24 @@ class PurchaseOrderService:
return to_status in valid_transitions.get(from_status, [])
async def get_ingredient_purchase_history(
async def get_inventory_product_purchase_history(
self,
tenant_id: UUID,
ingredient_id: UUID,
inventory_product_id: UUID,
days_back: int = 90
) -> Dict[str, Any]:
"""Get purchase history for an ingredient"""
return self.item_repository.get_ingredient_purchase_history(
tenant_id, ingredient_id, days_back
"""Get purchase history for an inventory product"""
return self.item_repository.get_inventory_product_purchase_history(
tenant_id, inventory_product_id, days_back
)
async def get_top_purchased_ingredients(
async def get_top_purchased_inventory_products(
self,
tenant_id: UUID,
days_back: int = 30,
limit: int = 10
) -> List[Dict[str, Any]]:
"""Get most purchased ingredients"""
return self.item_repository.get_top_purchased_ingredients(
"""Get most purchased inventory products"""
return self.item_repository.get_top_purchased_inventory_products(
tenant_id, days_back, limit
)