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

- 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:
Johngreen
2026-02-10 15:45:51 +09:00
parent ca29e5b809
commit 00a17c0b86
10 changed files with 564 additions and 22 deletions

View File

@@ -17,6 +17,7 @@ from src.database.models import (
)
from src.auth.models import TokenData
from src.auth.dependencies import require_auth, verify_tenant_access
from src.api.alarms import generate_alarms_for_inspection
router = APIRouter(prefix="/api/{tenant_id}/inspections", tags=["inspections"])
@@ -471,11 +472,50 @@ async def complete_inspection(
if body and body.notes is not None:
session.notes = body.notes
fail_records_data = []
records_with_items_stmt = (
select(InspectionRecord)
.options(selectinload(InspectionRecord.template_item))
.where(
InspectionRecord.session_id == inspection_id,
InspectionRecord.is_pass == False,
)
)
fail_result = await db.execute(records_with_items_stmt)
fail_records = fail_result.scalars().all()
template_stmt = select(InspectionTemplate).where(
InspectionTemplate.id == session.template_id
)
tmpl = (await db.execute(template_stmt)).scalar_one_or_none()
template_name = str(tmpl.name) if tmpl else "알 수 없는 템플릿"
for r in fail_records:
ti = r.template_item
item_name = str(ti.name) if ti else "?"
spec_parts = []
if ti and ti.spec_min is not None:
spec_parts.append(f"최소: {ti.spec_min}")
if ti and ti.spec_max is not None:
spec_parts.append(f"최대: {ti.spec_max}")
measured = ""
if r.value_numeric is not None:
measured = f"측정값: {r.value_numeric}"
elif r.value_boolean is not None:
measured = f"측정값: {'합격' if r.value_boolean else '불합격'}"
spec_info = ", ".join(filter(None, [measured] + spec_parts))
fail_records_data.append((r, item_name, spec_info))
await db.flush()
await generate_alarms_for_inspection(
db, tenant_id, session, fail_records_data, template_name
)
await db.commit()
await db.refresh(session)
pass_count = sum(1 for r in session.records if r.is_pass is True)
fail_count = sum(1 for r in session.records if r.is_pass is False)
fail_count_val = sum(1 for r in session.records if r.is_pass is False)
total = len(session.records)
return {
@@ -484,8 +524,8 @@ async def complete_inspection(
"summary": {
"total": total,
"pass_count": pass_count,
"fail_count": fail_count,
"no_judgment": total - pass_count - fail_count,
"fail_count": fail_count_val,
"no_judgment": total - pass_count - fail_count_val,
},
}