Add supplier and imporve inventory frontend

This commit is contained in:
Urtzi Alfaro
2025-09-18 23:32:53 +02:00
parent ae77a0e1c5
commit d61056df33
40 changed files with 2022 additions and 629 deletions

View File

@@ -8,7 +8,7 @@ from typing import List, Optional
from uuid import UUID
import structlog
from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db
from app.services.supplier_service import SupplierService
from app.schemas.suppliers import (
@@ -27,7 +27,7 @@ async def create_supplier(
supplier_data: SupplierCreate,
tenant_id: str = Path(..., description="Tenant ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
try:
@@ -54,7 +54,7 @@ async def list_suppliers(
status: Optional[str] = Query(None, description="Status filter"),
limit: int = Query(50, ge=1, le=1000, description="Number of results to return"),
offset: int = Query(0, ge=0, description="Number of results to skip"),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
"""List suppliers with optional filters"""
# require_permissions(current_user, ["suppliers:read"])
@@ -81,7 +81,7 @@ async def list_suppliers(
@router.get("/statistics", response_model=SupplierStatistics)
async def get_supplier_statistics(
tenant_id: str = Path(..., description="Tenant ID"),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
"""Get supplier statistics for dashboard"""
# require_permissions(current_user, ["suppliers:read"])
@@ -98,7 +98,7 @@ async def get_supplier_statistics(
@router.get("/active", response_model=List[SupplierSummary])
async def get_active_suppliers(
tenant_id: str = Path(..., description="Tenant ID"),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
"""Get all active suppliers"""
# require_permissions(current_user, ["suppliers:read"])
@@ -116,7 +116,7 @@ async def get_active_suppliers(
async def get_top_suppliers(
tenant_id: str = Path(..., description="Tenant ID"),
limit: int = Query(10, ge=1, le=50, description="Number of top suppliers to return"),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
"""Get top performing suppliers"""
# require_permissions(current_user, ["suppliers:read"])
@@ -134,7 +134,7 @@ async def get_top_suppliers(
async def get_suppliers_needing_review(
tenant_id: str = Path(..., description="Tenant ID"),
days_since_last_order: int = Query(30, ge=1, le=365, description="Days since last order"),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
"""Get suppliers that may need performance review"""
# require_permissions(current_user, ["suppliers:read"])
@@ -154,7 +154,7 @@ async def get_suppliers_needing_review(
async def get_supplier(
supplier_id: UUID = Path(..., description="Supplier ID"),
tenant_id: str = Path(..., description="Tenant ID"),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
"""Get supplier by ID"""
# require_permissions(current_user, ["suppliers:read"])
@@ -179,7 +179,7 @@ async def update_supplier(
supplier_data: SupplierUpdate,
supplier_id: UUID = Path(..., description="Supplier ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
"""Update supplier information"""
# require_permissions(current_user, ["suppliers:update"])
@@ -214,7 +214,7 @@ async def update_supplier(
@router.delete("/{supplier_id}")
async def delete_supplier(
supplier_id: UUID = Path(..., description="Supplier ID"),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
"""Delete supplier (soft delete)"""
# require_permissions(current_user, ["suppliers:delete"])
@@ -244,7 +244,7 @@ async def approve_supplier(
approval_data: SupplierApproval,
supplier_id: UUID = Path(..., description="Supplier ID"),
current_user: Dict[str, Any] = Depends(get_current_user_dep),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
"""Approve or reject a pending supplier"""
# require_permissions(current_user, ["suppliers:approve"])
@@ -289,7 +289,7 @@ async def approve_supplier(
async def get_suppliers_by_type(
supplier_type: str = Path(..., description="Supplier type"),
tenant_id: str = Path(..., description="Tenant ID"),
db: Session = Depends(get_db)
db: AsyncSession = Depends(get_db)
):
"""Get suppliers by type"""
# require_permissions(current_user, ["suppliers:read"])

View File

@@ -18,84 +18,84 @@ from shared.database.base import Base
class SupplierType(enum.Enum):
"""Types of suppliers"""
INGREDIENTS = "ingredients" # Raw materials supplier
PACKAGING = "packaging" # Packaging materials
EQUIPMENT = "equipment" # Bakery equipment
SERVICES = "services" # Service providers
UTILITIES = "utilities" # Utilities (gas, electricity)
MULTI = "multi" # Multi-category supplier
ingredients = "ingredients" # Raw materials supplier
packaging = "packaging" # Packaging materials
equipment = "equipment" # Bakery equipment
services = "services" # Service providers
utilities = "utilities" # Utilities (gas, electricity)
multi = "multi" # Multi-category supplier
class SupplierStatus(enum.Enum):
"""Supplier lifecycle status"""
ACTIVE = "active"
INACTIVE = "inactive"
PENDING_APPROVAL = "pending_approval"
SUSPENDED = "suspended"
BLACKLISTED = "blacklisted"
active = "active"
inactive = "inactive"
pending_approval = "pending_approval"
suspended = "suspended"
blacklisted = "blacklisted"
class PaymentTerms(enum.Enum):
"""Payment terms with suppliers"""
CASH_ON_DELIVERY = "cod"
NET_15 = "net_15"
NET_30 = "net_30"
NET_45 = "net_45"
NET_60 = "net_60"
PREPAID = "prepaid"
CREDIT_TERMS = "credit_terms"
cod = "cod"
net_15 = "net_15"
net_30 = "net_30"
net_45 = "net_45"
net_60 = "net_60"
prepaid = "prepaid"
credit_terms = "credit_terms"
class PurchaseOrderStatus(enum.Enum):
"""Purchase order lifecycle status"""
DRAFT = "draft"
PENDING_APPROVAL = "pending_approval"
APPROVED = "approved"
SENT_TO_SUPPLIER = "sent_to_supplier"
CONFIRMED = "confirmed"
PARTIALLY_RECEIVED = "partially_received"
COMPLETED = "completed"
CANCELLED = "cancelled"
DISPUTED = "disputed"
draft = "draft"
pending_approval = "pending_approval"
approved = "approved"
sent_to_supplier = "sent_to_supplier"
confirmed = "confirmed"
partially_received = "partially_received"
completed = "completed"
cancelled = "cancelled"
disputed = "disputed"
class DeliveryStatus(enum.Enum):
"""Delivery status tracking"""
SCHEDULED = "scheduled"
IN_TRANSIT = "in_transit"
OUT_FOR_DELIVERY = "out_for_delivery"
DELIVERED = "delivered"
PARTIALLY_DELIVERED = "partially_delivered"
FAILED_DELIVERY = "failed_delivery"
RETURNED = "returned"
scheduled = "scheduled"
in_transit = "in_transit"
out_for_delivery = "out_for_delivery"
delivered = "delivered"
partially_delivered = "partially_delivered"
failed_delivery = "failed_delivery"
returned = "returned"
class QualityRating(enum.Enum):
"""Quality rating scale"""
EXCELLENT = 5
GOOD = 4
AVERAGE = 3
POOR = 2
VERY_POOR = 1
excellent = 5
good = 4
average = 3
poor = 2
very_poor = 1
class DeliveryRating(enum.Enum):
"""Delivery performance rating scale"""
EXCELLENT = 5
GOOD = 4
AVERAGE = 3
POOR = 2
VERY_POOR = 1
excellent = 5
good = 4
average = 3
poor = 2
very_poor = 1
class InvoiceStatus(enum.Enum):
"""Invoice processing status"""
PENDING = "pending"
APPROVED = "approved"
PAID = "paid"
OVERDUE = "overdue"
DISPUTED = "disputed"
CANCELLED = "cancelled"
pending = "pending"
approved = "approved"
paid = "paid"
overdue = "overdue"
disputed = "disputed"
cancelled = "cancelled"
class Supplier(Base):
@@ -113,7 +113,7 @@ class Supplier(Base):
# Supplier classification
supplier_type = Column(SQLEnum(SupplierType), nullable=False, index=True)
status = Column(SQLEnum(SupplierStatus), nullable=False, default=SupplierStatus.PENDING_APPROVAL, index=True)
status = Column(SQLEnum(SupplierStatus), nullable=False, default=SupplierStatus.pending_approval, index=True)
# Contact information
contact_person = Column(String(200), nullable=True)
@@ -131,7 +131,7 @@ class Supplier(Base):
country = Column(String(100), nullable=True)
# Business terms
payment_terms = Column(SQLEnum(PaymentTerms), nullable=False, default=PaymentTerms.NET_30)
payment_terms = Column(SQLEnum(PaymentTerms), nullable=False, default=PaymentTerms.net_30)
credit_limit = Column(Numeric(12, 2), nullable=True)
currency = Column(String(3), nullable=False, default="EUR") # ISO currency code
@@ -246,7 +246,7 @@ class PurchaseOrder(Base):
reference_number = Column(String(100), nullable=True) # Internal reference
# Order status and workflow
status = Column(SQLEnum(PurchaseOrderStatus), nullable=False, default=PurchaseOrderStatus.DRAFT, index=True)
status = Column(SQLEnum(PurchaseOrderStatus), nullable=False, default=PurchaseOrderStatus.draft, index=True)
priority = Column(String(20), nullable=False, default="normal") # urgent, high, normal, low
# Order details
@@ -363,7 +363,7 @@ class Delivery(Base):
supplier_delivery_note = Column(String(100), nullable=True) # Supplier's delivery reference
# Delivery status and tracking
status = Column(SQLEnum(DeliveryStatus), nullable=False, default=DeliveryStatus.SCHEDULED, index=True)
status = Column(SQLEnum(DeliveryStatus), nullable=False, default=DeliveryStatus.scheduled, index=True)
# Scheduling and timing
scheduled_date = Column(DateTime(timezone=True), nullable=True)
@@ -517,7 +517,7 @@ class SupplierInvoice(Base):
supplier_invoice_number = Column(String(100), nullable=False)
# Invoice status and dates
status = Column(SQLEnum(InvoiceStatus), nullable=False, default=InvoiceStatus.PENDING, index=True)
status = Column(SQLEnum(InvoiceStatus), nullable=False, default=InvoiceStatus.pending, index=True)
invoice_date = Column(DateTime(timezone=True), nullable=False)
due_date = Column(DateTime(timezone=True), nullable=False)
received_date = Column(DateTime(timezone=True), nullable=False, default=lambda: datetime.now(timezone.utc))

View File

@@ -4,8 +4,8 @@ Base repository class for common database operations
"""
from typing import TypeVar, Generic, List, Optional, Dict, Any
from sqlalchemy.orm import Session
from sqlalchemy import desc, asc
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import desc, asc, select, func
from uuid import UUID
T = TypeVar('T')
@@ -14,55 +14,59 @@ T = TypeVar('T')
class BaseRepository(Generic[T]):
"""Base repository with common CRUD operations"""
def __init__(self, model: type, db: Session):
def __init__(self, model: type, db: AsyncSession):
self.model = model
self.db = db
def create(self, obj_data: Dict[str, Any]) -> T:
async def create(self, obj_data: Dict[str, Any]) -> T:
"""Create a new record"""
db_obj = self.model(**obj_data)
self.db.add(db_obj)
self.db.commit()
self.db.refresh(db_obj)
await self.db.commit()
await self.db.refresh(db_obj)
return db_obj
def get_by_id(self, record_id: UUID) -> Optional[T]:
async def get_by_id(self, record_id: UUID) -> Optional[T]:
"""Get record by ID"""
return self.db.query(self.model).filter(self.model.id == record_id).first()
stmt = select(self.model).filter(self.model.id == record_id)
result = await self.db.execute(stmt)
return result.scalar_one_or_none()
def get_by_tenant_id(self, tenant_id: UUID, limit: int = 100, offset: int = 0) -> List[T]:
async def get_by_tenant_id(self, tenant_id: UUID, limit: int = 100, offset: int = 0) -> List[T]:
"""Get records by tenant ID with pagination"""
return (
self.db.query(self.model)
.filter(self.model.tenant_id == tenant_id)
.limit(limit)
.offset(offset)
.all()
)
stmt = select(self.model).filter(
self.model.tenant_id == tenant_id
).limit(limit).offset(offset)
result = await self.db.execute(stmt)
return result.scalars().all()
def update(self, record_id: UUID, update_data: Dict[str, Any]) -> Optional[T]:
async def update(self, record_id: UUID, update_data: Dict[str, Any]) -> Optional[T]:
"""Update record by ID"""
db_obj = self.get_by_id(record_id)
db_obj = await self.get_by_id(record_id)
if db_obj:
for key, value in update_data.items():
if hasattr(db_obj, key):
setattr(db_obj, key, value)
self.db.commit()
self.db.refresh(db_obj)
await self.db.commit()
await self.db.refresh(db_obj)
return db_obj
def delete(self, record_id: UUID) -> bool:
async def delete(self, record_id: UUID) -> bool:
"""Delete record by ID"""
db_obj = self.get_by_id(record_id)
db_obj = await self.get_by_id(record_id)
if db_obj:
self.db.delete(db_obj)
self.db.commit()
await self.db.delete(db_obj)
await self.db.commit()
return True
return False
def count_by_tenant(self, tenant_id: UUID) -> int:
async def count_by_tenant(self, tenant_id: UUID) -> int:
"""Count records by tenant"""
return self.db.query(self.model).filter(self.model.tenant_id == tenant_id).count()
stmt = select(func.count()).select_from(self.model).filter(
self.model.tenant_id == tenant_id
)
result = await self.db.execute(stmt)
return result.scalar() or 0
def list_with_filters(
self,

View File

@@ -4,8 +4,8 @@ Supplier repository for database operations
"""
from typing import List, Optional, Dict, Any
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, func
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import and_, or_, func, select
from uuid import UUID
from datetime import datetime
@@ -16,36 +16,32 @@ from app.repositories.base import BaseRepository
class SupplierRepository(BaseRepository[Supplier]):
"""Repository for supplier management operations"""
def __init__(self, db: Session):
def __init__(self, db: AsyncSession):
super().__init__(Supplier, db)
def get_by_name(self, tenant_id: UUID, name: str) -> Optional[Supplier]:
async def get_by_name(self, tenant_id: UUID, name: str) -> Optional[Supplier]:
"""Get supplier by name within tenant"""
return (
self.db.query(self.model)
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.name == name
)
stmt = select(self.model).filter(
and_(
self.model.tenant_id == tenant_id,
self.model.name == name
)
.first()
)
result = await self.db.execute(stmt)
return result.scalar_one_or_none()
def get_by_supplier_code(self, tenant_id: UUID, supplier_code: str) -> Optional[Supplier]:
async def get_by_supplier_code(self, tenant_id: UUID, supplier_code: str) -> Optional[Supplier]:
"""Get supplier by supplier code within tenant"""
return (
self.db.query(self.model)
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.supplier_code == supplier_code
)
stmt = select(self.model).filter(
and_(
self.model.tenant_id == tenant_id,
self.model.supplier_code == supplier_code
)
.first()
)
result = await self.db.execute(stmt)
return result.scalar_one_or_none()
def search_suppliers(
async def search_suppliers(
self,
tenant_id: UUID,
search_term: Optional[str] = None,
@@ -55,8 +51,8 @@ class SupplierRepository(BaseRepository[Supplier]):
offset: int = 0
) -> List[Supplier]:
"""Search suppliers with filters"""
query = self.db.query(self.model).filter(self.model.tenant_id == tenant_id)
stmt = select(self.model).filter(self.model.tenant_id == tenant_id)
# Search term filter (name, contact person, email)
if search_term:
search_filter = or_(
@@ -64,31 +60,30 @@ class SupplierRepository(BaseRepository[Supplier]):
self.model.contact_person.ilike(f"%{search_term}%"),
self.model.email.ilike(f"%{search_term}%")
)
query = query.filter(search_filter)
stmt = stmt.filter(search_filter)
# Type filter
if supplier_type:
query = query.filter(self.model.supplier_type == supplier_type)
stmt = stmt.filter(self.model.supplier_type == supplier_type)
# Status filter
if status:
query = query.filter(self.model.status == status)
return query.order_by(self.model.name).limit(limit).offset(offset).all()
stmt = stmt.filter(self.model.status == status)
stmt = stmt.order_by(self.model.name).limit(limit).offset(offset)
result = await self.db.execute(stmt)
return result.scalars().all()
def get_active_suppliers(self, tenant_id: UUID) -> List[Supplier]:
async def get_active_suppliers(self, tenant_id: UUID) -> List[Supplier]:
"""Get all active suppliers for a tenant"""
return (
self.db.query(self.model)
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.status == SupplierStatus.ACTIVE
)
stmt = select(self.model).filter(
and_(
self.model.tenant_id == tenant_id,
self.model.status == SupplierStatus.active
)
.order_by(self.model.name)
.all()
)
).order_by(self.model.name)
result = await self.db.execute(stmt)
return result.scalars().all()
def get_suppliers_by_type(
self,
@@ -102,7 +97,7 @@ class SupplierRepository(BaseRepository[Supplier]):
and_(
self.model.tenant_id == tenant_id,
self.model.supplier_type == supplier_type,
self.model.status == SupplierStatus.ACTIVE
self.model.status == SupplierStatus.active
)
)
.order_by(self.model.quality_rating.desc(), self.model.name)
@@ -120,7 +115,7 @@ class SupplierRepository(BaseRepository[Supplier]):
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.status == SupplierStatus.ACTIVE
self.model.status == SupplierStatus.active
)
)
.order_by(
@@ -178,7 +173,7 @@ class SupplierRepository(BaseRepository[Supplier]):
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.status == SupplierStatus.ACTIVE,
self.model.status == SupplierStatus.active,
or_(
self.model.quality_rating < 3.0, # Poor rating
self.model.delivery_rating < 3.0, # Poor delivery
@@ -190,66 +185,33 @@ class SupplierRepository(BaseRepository[Supplier]):
.all()
)
def get_supplier_statistics(self, tenant_id: UUID) -> Dict[str, Any]:
async def get_supplier_statistics(self, tenant_id: UUID) -> Dict[str, Any]:
"""Get supplier statistics for dashboard"""
total_suppliers = self.count_by_tenant(tenant_id)
active_suppliers = (
self.db.query(self.model)
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.status == SupplierStatus.ACTIVE
)
)
.count()
)
pending_suppliers = (
self.db.query(self.model)
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.status == SupplierStatus.PENDING_APPROVAL
)
)
.count()
)
avg_quality_rating = (
self.db.query(func.avg(self.model.quality_rating))
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.status == SupplierStatus.ACTIVE,
self.model.quality_rating > 0
)
)
.scalar()
) or 0.0
avg_delivery_rating = (
self.db.query(func.avg(self.model.delivery_rating))
.filter(
and_(
self.model.tenant_id == tenant_id,
self.model.status == SupplierStatus.ACTIVE,
self.model.delivery_rating > 0
)
)
.scalar()
) or 0.0
total_spend = (
self.db.query(func.sum(self.model.total_amount))
.filter(self.model.tenant_id == tenant_id)
.scalar()
) or 0.0
total_suppliers = await self.count_by_tenant(tenant_id)
# Get all suppliers for this tenant to avoid multiple queries and enum casting issues
all_stmt = select(self.model).filter(self.model.tenant_id == tenant_id)
all_result = await self.db.execute(all_stmt)
all_suppliers = all_result.scalars().all()
# Calculate statistics in Python to avoid database enum casting issues
active_suppliers = [s for s in all_suppliers if s.status == SupplierStatus.active]
pending_suppliers = [s for s in all_suppliers if s.status == SupplierStatus.pending_approval]
# Calculate averages from active suppliers
quality_ratings = [s.quality_rating for s in active_suppliers if s.quality_rating and s.quality_rating > 0]
avg_quality_rating = sum(quality_ratings) / len(quality_ratings) if quality_ratings else 0.0
delivery_ratings = [s.delivery_rating for s in active_suppliers if s.delivery_rating and s.delivery_rating > 0]
avg_delivery_rating = sum(delivery_ratings) / len(delivery_ratings) if delivery_ratings else 0.0
# Total spend for all suppliers
total_spend = sum(float(s.total_amount or 0) for s in all_suppliers)
return {
"total_suppliers": total_suppliers,
"active_suppliers": active_suppliers,
"pending_suppliers": pending_suppliers,
"active_suppliers": len(active_suppliers),
"pending_suppliers": len(pending_suppliers),
"avg_quality_rating": round(float(avg_quality_rating), 2),
"avg_delivery_rating": round(float(avg_delivery_rating), 2),
"total_spend": float(total_spend)

View File

@@ -42,7 +42,7 @@ class SupplierCreate(BaseModel):
country: Optional[str] = Field(None, max_length=100)
# Business terms
payment_terms: PaymentTerms = PaymentTerms.NET_30
payment_terms: PaymentTerms = PaymentTerms.net_30
credit_limit: Optional[Decimal] = Field(None, ge=0)
currency: str = Field(default="EUR", max_length=3)
standard_lead_time: int = Field(default=3, ge=0, le=365)

View File

@@ -138,7 +138,6 @@ class DashboardService:
return SupplierPerformanceInsights(
supplier_id=supplier_id,
supplier_name=supplier['name'],
current_overall_score=current_metrics.get('overall_score', 0),
previous_score=previous_metrics.get('overall_score'),
score_change_percentage=self._calculate_change_percentage(

View File

@@ -7,7 +7,7 @@ import structlog
from typing import List, Optional, Dict, Any
from uuid import UUID
from datetime import datetime
from sqlalchemy.orm import Session
from sqlalchemy.ext.asyncio import AsyncSession
from app.repositories.supplier_repository import SupplierRepository
from app.models.suppliers import Supplier, SupplierStatus, SupplierType
@@ -23,7 +23,7 @@ logger = structlog.get_logger()
class SupplierService:
"""Service for supplier management operations"""
def __init__(self, db: Session):
def __init__(self, db: AsyncSession):
self.db = db
self.repository = SupplierRepository(db)
@@ -37,13 +37,13 @@ class SupplierService:
logger.info("Creating supplier", tenant_id=str(tenant_id), name=supplier_data.name)
# Check for duplicate name
existing = self.repository.get_by_name(tenant_id, supplier_data.name)
existing = await self.repository.get_by_name(tenant_id, supplier_data.name)
if existing:
raise ValueError(f"Supplier with name '{supplier_data.name}' already exists")
# Check for duplicate supplier code if provided
if supplier_data.supplier_code:
existing_code = self.repository.get_by_supplier_code(
existing_code = await self.repository.get_by_supplier_code(
tenant_id, supplier_data.supplier_code
)
if existing_code:
@@ -61,7 +61,7 @@ class SupplierService:
create_data.update({
'tenant_id': tenant_id,
'supplier_code': supplier_code,
'status': SupplierStatus.PENDING_APPROVAL,
'status': SupplierStatus.pending_approval,
'created_by': created_by,
'updated_by': created_by,
'quality_rating': 0.0,
@@ -70,7 +70,7 @@ class SupplierService:
'total_amount': 0.0
})
supplier = self.repository.create(create_data)
supplier = await self.repository.create(create_data)
logger.info(
"Supplier created successfully",
@@ -83,7 +83,7 @@ class SupplierService:
async def get_supplier(self, supplier_id: UUID) -> Optional[Supplier]:
"""Get supplier by ID"""
return self.repository.get_by_id(supplier_id)
return await self.repository.get_by_id(supplier_id)
async def update_supplier(
self,
@@ -138,7 +138,7 @@ class SupplierService:
# Soft delete by changing status
self.repository.update(supplier_id, {
'status': SupplierStatus.INACTIVE,
'status': SupplierStatus.inactive,
'updated_at': datetime.utcnow()
})
@@ -151,7 +151,7 @@ class SupplierService:
search_params: SupplierSearchParams
) -> List[Supplier]:
"""Search suppliers with filters"""
return self.repository.search_suppliers(
return await self.repository.search_suppliers(
tenant_id=tenant_id,
search_term=search_params.search_term,
supplier_type=search_params.supplier_type,
@@ -239,7 +239,7 @@ class SupplierService:
async def get_supplier_statistics(self, tenant_id: UUID) -> Dict[str, Any]:
"""Get supplier statistics for dashboard"""
return self.repository.get_supplier_statistics(tenant_id)
return await self.repository.get_supplier_statistics(tenant_id)
async def get_suppliers_needing_review(
self,