Improve the frontend and repository layer
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user