Improve the frontend and repository layer

This commit is contained in:
Urtzi Alfaro
2025-10-23 07:44:54 +02:00
parent 8d30172483
commit 07c33fa578
112 changed files with 14726 additions and 2733 deletions

View File

@@ -16,13 +16,14 @@ from shared.database.transactions import transactional
from app.core.config import settings
from app.models.food_safety import (
FoodSafetyCompliance,
TemperatureLog,
FoodSafetyCompliance,
TemperatureLog,
FoodSafetyAlert,
FoodSafetyStandard,
ComplianceStatus,
FoodSafetyAlertType
)
from app.repositories.food_safety_repository import FoodSafetyRepository
from app.schemas.food_safety import (
FoodSafetyComplianceCreate,
FoodSafetyComplianceUpdate,
@@ -42,9 +43,13 @@ logger = structlog.get_logger()
class FoodSafetyService:
"""Service for food safety and compliance operations"""
def __init__(self):
pass
def _get_repository(self, db) -> FoodSafetyRepository:
"""Get repository instance for the current database session"""
return FoodSafetyRepository(db)
# ===== COMPLIANCE MANAGEMENT =====
@@ -90,9 +95,9 @@ class FoodSafetyService:
updated_by=user_id
)
db.add(compliance)
await db.flush()
await db.refresh(compliance)
# Create compliance record using repository
repo = self._get_repository(db)
compliance = await repo.create_compliance(compliance)
# Check for compliance alerts
await self._check_compliance_alerts(db, compliance)
@@ -117,9 +122,10 @@ class FoodSafetyService:
) -> Optional[FoodSafetyComplianceResponse]:
"""Update an existing compliance record"""
try:
# Get existing compliance record
compliance = await db.get(FoodSafetyCompliance, compliance_id)
if not compliance or compliance.tenant_id != tenant_id:
# Get existing compliance record using repository
repo = self._get_repository(db)
compliance = await repo.get_compliance_by_id(compliance_id, tenant_id)
if not compliance:
return None
# Update fields
@@ -132,9 +138,9 @@ class FoodSafetyService:
setattr(compliance, field, value)
compliance.updated_by = user_id
await db.flush()
await db.refresh(compliance)
# Update compliance record using repository
compliance = await repo.update_compliance(compliance)
# Check for compliance alerts after update
await self._check_compliance_alerts(db, compliance)
@@ -336,85 +342,44 @@ class FoodSafetyService:
) -> FoodSafetyDashboard:
"""Get food safety dashboard data"""
try:
# Get compliance overview
from sqlalchemy import text
compliance_query = text("""
SELECT
COUNT(*) as total,
COUNT(CASE WHEN compliance_status = 'COMPLIANT' THEN 1 END) as compliant,
COUNT(CASE WHEN compliance_status = 'NON_COMPLIANT' THEN 1 END) as non_compliant,
COUNT(CASE WHEN compliance_status = 'PENDING_REVIEW' THEN 1 END) as pending_review
FROM food_safety_compliance
WHERE tenant_id = :tenant_id AND is_active = true
""")
compliance_result = await db.execute(compliance_query, {"tenant_id": tenant_id})
compliance_stats = compliance_result.fetchone()
total_compliance = compliance_stats.total or 0
compliant_items = compliance_stats.compliant or 0
# Get repository instance
repo = self._get_repository(db)
# Get compliance overview using repository
compliance_stats = await repo.get_compliance_stats(tenant_id)
total_compliance = compliance_stats["total"]
compliant_items = compliance_stats["compliant"]
compliance_percentage = (compliant_items / total_compliance * 100) if total_compliance > 0 else 0
# Get temperature monitoring status
temp_query = text("""
SELECT
COUNT(DISTINCT equipment_id) as sensors_online,
COUNT(CASE WHEN NOT is_within_range AND recorded_at > NOW() - INTERVAL '24 hours' THEN 1 END) as violations_24h
FROM temperature_logs
WHERE tenant_id = :tenant_id AND recorded_at > NOW() - INTERVAL '1 hour'
""")
temp_result = await db.execute(temp_query, {"tenant_id": tenant_id})
temp_stats = temp_result.fetchone()
# Get expiration tracking
expiration_query = text("""
SELECT
COUNT(CASE WHEN expiration_date::date = CURRENT_DATE THEN 1 END) as expiring_today,
COUNT(CASE WHEN expiration_date BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '7 days' THEN 1 END) as expiring_week,
COUNT(CASE WHEN expiration_date < CURRENT_DATE AND is_available THEN 1 END) as expired_requiring_action
FROM stock s
JOIN ingredients i ON s.ingredient_id = i.id
WHERE i.tenant_id = :tenant_id AND s.is_available = true
""")
expiration_result = await db.execute(expiration_query, {"tenant_id": tenant_id})
expiration_stats = expiration_result.fetchone()
# Get alert counts
alert_query = text("""
SELECT
COUNT(CASE WHEN severity = 'high' OR severity = 'critical' THEN 1 END) as high_risk,
COUNT(CASE WHEN severity = 'critical' THEN 1 END) as critical,
COUNT(CASE WHEN regulatory_action_required = true AND resolved_at IS NULL THEN 1 END) as regulatory_pending
FROM food_safety_alerts
WHERE tenant_id = :tenant_id AND status = 'active'
""")
alert_result = await db.execute(alert_query, {"tenant_id": tenant_id})
alert_stats = alert_result.fetchone()
# Get temperature monitoring status using repository
temp_stats = await repo.get_temperature_stats(tenant_id)
# Get expiration tracking using repository
expiration_stats = await repo.get_expiration_stats(tenant_id)
# Get alert counts using repository
alert_stats = await repo.get_alert_stats(tenant_id)
return FoodSafetyDashboard(
total_compliance_items=total_compliance,
compliant_items=compliant_items,
non_compliant_items=compliance_stats.non_compliant or 0,
pending_review_items=compliance_stats.pending_review or 0,
non_compliant_items=compliance_stats["non_compliant"],
pending_review_items=compliance_stats["pending_review"],
compliance_percentage=Decimal(str(compliance_percentage)),
temperature_sensors_online=temp_stats.sensors_online or 0,
temperature_sensors_total=temp_stats.sensors_online or 0, # Would need actual count
temperature_violations_24h=temp_stats.violations_24h or 0,
temperature_sensors_online=temp_stats["sensors_online"],
temperature_sensors_total=temp_stats["sensors_online"], # Would need actual count
temperature_violations_24h=temp_stats["violations_24h"],
current_temperature_status="normal", # Would need to calculate
items_expiring_today=expiration_stats.expiring_today or 0,
items_expiring_this_week=expiration_stats.expiring_week or 0,
expired_items_requiring_action=expiration_stats.expired_requiring_action or 0,
items_expiring_today=expiration_stats["expiring_today"],
items_expiring_this_week=expiration_stats["expiring_week"],
expired_items_requiring_action=expiration_stats["expired_requiring_action"],
upcoming_audits=0, # Would need to calculate
overdue_audits=0, # Would need to calculate
certifications_valid=compliant_items,
certifications_expiring_soon=0, # Would need to calculate
high_risk_items=alert_stats.high_risk or 0,
critical_alerts=alert_stats.critical or 0,
regulatory_notifications_pending=alert_stats.regulatory_pending or 0,
high_risk_items=alert_stats["high_risk"],
critical_alerts=alert_stats["critical"],
regulatory_notifications_pending=alert_stats["regulatory_pending"],
recent_safety_incidents=[] # Would need to get recent incidents
)
@@ -426,16 +391,14 @@ class FoodSafetyService:
async def _validate_compliance_data(self, db, compliance_data: FoodSafetyComplianceCreate):
"""Validate compliance data for business rules"""
# Check if ingredient exists
from sqlalchemy import text
ingredient_query = text("SELECT id FROM ingredients WHERE id = :ingredient_id AND tenant_id = :tenant_id")
result = await db.execute(ingredient_query, {
"ingredient_id": compliance_data.ingredient_id,
"tenant_id": compliance_data.tenant_id
})
if not result.fetchone():
# Check if ingredient exists using repository
repo = self._get_repository(db)
ingredient_exists = await repo.validate_ingredient_exists(
compliance_data.ingredient_id,
compliance_data.tenant_id
)
if not ingredient_exists:
raise ValueError("Ingredient not found")
# Validate standard