feat: complete 5 GAP requirements — auto counters, inspection alarms, machine specs, responsive CSS
All checks were successful
Deploy to Production / deploy (push) Successful in 1m8s
All checks were successful
Deploy to Production / deploy (push) Successful in 1m8s
- GAP 2+4: auto_time/date counter auto-computation with manual update blocking - GAP 3: auto-generate alarms on inspection completion for failed items - GAP 1: machine spec fields (manufacturer, location, capacity, power, description) - GAP 5: enhanced mobile responsive CSS (768px/480px breakpoints) - Alembic migration for new columns, seed data enriched with specs and date-type parts
This commit is contained in:
@@ -8,7 +8,16 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from src.database.config import get_db
|
||||
from src.database.models import Alarm, EquipmentPart, PartCounter, Machine
|
||||
from src.database.models import (
|
||||
Alarm,
|
||||
EquipmentPart,
|
||||
PartCounter,
|
||||
Machine,
|
||||
InspectionSession,
|
||||
InspectionRecord,
|
||||
InspectionTemplate,
|
||||
InspectionTemplateItem,
|
||||
)
|
||||
from src.auth.models import TokenData
|
||||
from src.auth.dependencies import require_auth, verify_tenant_access
|
||||
|
||||
@@ -27,12 +36,19 @@ def _alarm_to_dict(alarm: Alarm) -> dict:
|
||||
return {
|
||||
"id": str(alarm.id),
|
||||
"tenant_id": str(alarm.tenant_id),
|
||||
"equipment_part_id": str(alarm.equipment_part_id),
|
||||
"machine_id": str(alarm.machine_id),
|
||||
"equipment_part_id": str(alarm.equipment_part_id)
|
||||
if alarm.equipment_part_id
|
||||
else None,
|
||||
"machine_id": str(alarm.machine_id) if alarm.machine_id else None,
|
||||
"inspection_session_id": str(alarm.inspection_session_id)
|
||||
if alarm.inspection_session_id
|
||||
else None,
|
||||
"alarm_type": str(alarm.alarm_type),
|
||||
"severity": str(alarm.severity),
|
||||
"message": str(alarm.message),
|
||||
"lifecycle_pct_at_trigger": float(alarm.lifecycle_pct_at_trigger),
|
||||
"lifecycle_pct_at_trigger": float(alarm.lifecycle_pct_at_trigger)
|
||||
if alarm.lifecycle_pct_at_trigger is not None
|
||||
else None,
|
||||
"is_acknowledged": bool(alarm.is_acknowledged),
|
||||
"acknowledged_by": str(alarm.acknowledged_by)
|
||||
if alarm.acknowledged_by
|
||||
@@ -182,3 +198,33 @@ async def generate_alarms_for_part(
|
||||
lifecycle_pct_at_trigger=pct,
|
||||
)
|
||||
db.add(alarm)
|
||||
|
||||
|
||||
async def generate_alarms_for_inspection(
|
||||
db: AsyncSession,
|
||||
tenant_id: str,
|
||||
session: InspectionSession,
|
||||
fail_records: list,
|
||||
template_name: str,
|
||||
):
|
||||
if not fail_records:
|
||||
return
|
||||
|
||||
fail_count = len(fail_records)
|
||||
severity = "critical" if fail_count >= 3 else "warning"
|
||||
|
||||
for record, item_name, spec_info in fail_records:
|
||||
message = (
|
||||
f"검사 '{template_name}'의 '{item_name}' 항목이 불합격입니다 ({spec_info})"
|
||||
)
|
||||
if len(message) > 500:
|
||||
message = message[:497] + "..."
|
||||
|
||||
alarm = Alarm(
|
||||
tenant_id=tenant_id,
|
||||
inspection_session_id=session.id,
|
||||
alarm_type="inspection_fail",
|
||||
severity=severity,
|
||||
message=message,
|
||||
)
|
||||
db.add(alarm)
|
||||
|
||||
Reference in New Issue
Block a user