1차완료

This commit is contained in:
byun
2026-06-02 19:34:36 +09:00
parent 9f0f4326fe
commit b6863cd260
28 changed files with 1667 additions and 460 deletions

View File

@@ -49,6 +49,10 @@ def _fmt_report(r: models.Report, db: Session):
"closure_note": r.closure_note,
"closed_at": r.closed_at.isoformat() if r.closed_at else None,
"closed_by_name": r.closer.name if r.closer else None,
"re_dispatch_count": r.re_dispatch_count or 0,
"report_scope": r.report_scope or "single",
"scope_charger_count": r.scope_charger_count or 1,
"charger_ids": r.charger_ids or [],
}
@router.post("")
@@ -105,7 +109,8 @@ async def create_report(
@router.post("/batch")
async def create_batch_report(
charger_id: str = Form(...),
scope: str = Form("single"), # single | station | type
scope: str = Form("single"), # single | station | type | multi
charger_ids: Optional[str] = Form(None), # JSON: ["id1","id2",...] for multi scope
issue_types: str = Form(...),
issue_detail: str = Form(""),
error_code: str = Form(""),
@@ -124,14 +129,28 @@ async def create_batch_report(
charger = db.query(models.Charger).filter_by(id=charger_id).first()
if not charger: raise HTTPException(404, "충전기를 찾을 수 없습니다.")
if scope == "station":
targets = db.query(models.Charger).filter_by(
selected_ids = None
if scope == "multi" and charger_ids:
selected_ids = json.loads(charger_ids)
all_targets = [charger]
report_scope = "multi"
scope_charger_count = len(selected_ids)
elif scope == "station":
all_targets = db.query(models.Charger).filter_by(
station_name=charger.station_name, is_active=True).all()
report_scope = "station"
scope_charger_count = len(all_targets)
elif scope == "type" and charger.charger_type_id:
targets = db.query(models.Charger).filter_by(
all_targets = db.query(models.Charger).filter_by(
charger_type_id=charger.charger_type_id, is_active=True).all()
report_scope = "type"
scope_charger_count = len(all_targets)
else:
targets = [charger]
all_targets = [charger]
report_scope = "single"
scope_charger_count = 1
targets = [charger] # 항상 단일 신고 생성
setting = db.query(models.SystemSetting).filter_by(key="report_visibility_policy").first()
policy = setting.value if setting else "immediate"
@@ -143,7 +162,6 @@ async def create_batch_report(
else:
source_value = "qr"
# Read all photo bytes upfront so they can be written for each target
photo_data = []
for photo in photos:
if photo.filename:
@@ -160,6 +178,9 @@ async def create_batch_report(
ocpp_log=ocpp_log or None,
source=source_value,
reported_by=current_user.id if current_user else None,
report_scope=report_scope,
scope_charger_count=scope_charger_count,
charger_ids=selected_ids,
)
db.add(r); db.commit(); db.refresh(r)
@@ -181,6 +202,7 @@ async def create_batch_report(
def list_reports(
status: Optional[str] = None,
charger_id: Optional[str] = None,
station_name: Optional[str] = None,
active_only: bool = False,
db: Session = Depends(get_db),
current_user: models.User = Depends(get_current_user)
@@ -196,12 +218,17 @@ def list_reports(
q = (db.query(models.Report, seq_subq.c.seq)
.join(seq_subq, models.Report.id == seq_subq.c.rid)
.order_by(desc(models.Report.reported_at)))
if status:
if status == "pending_all":
q = q.filter(models.Report.status.in_(["pending", "pending_approval"]))
elif status:
q = q.filter(models.Report.status == status)
elif active_only:
q = q.filter(models.Report.status.in_(
["pending", "pending_approval", "in_progress", "waiting", "revisit"]))
if charger_id: q = q.filter(models.Report.charger_id == charger_id)
if station_name:
q = (q.join(models.Charger, models.Report.charger_id == models.Charger.id, isouter=True)
.filter(models.Charger.station_name == station_name))
if current_user.role == "mechanic":
q = q.filter(models.Report.status != "pending_approval")
@@ -254,20 +281,26 @@ def get_report(report_id: int, db: Session = Depends(get_db),
"root_cause": cost.root_cause,
"admin_note": cost.admin_note,
"cost_party_type": cost.cost_party_type,
"cost_party_manufacturer_id": cost.cost_party_manufacturer_id,
"cost_party_custom": cost.cost_party_custom,
"cost_manufacturer_name": cost.cost_manufacturer.name if cost.cost_manufacturer else None,
"recv_party_type": cost.recv_party_type,
"recv_party_manufacturer_id": cost.recv_party_manufacturer_id,
"recv_party_custom": cost.recv_party_custom,
"recv_manufacturer_name": cost.recv_manufacturer.name if cost.recv_manufacturer else None,
"cost_amount": cost.cost_amount,
"cost_status": cost.cost_status,
"manufacturer_name": cost.manufacturer.name if cost.manufacturer else None,
} if (cost and include_cost) else None,
"reviewed_by_name": cost.reviewer.name if cost.reviewer else None,
"reviewed_at": cost.reviewed_at.isoformat() if cost.reviewed_at else None,
} if cost else None,
"linked_improvements": _get_linked_improvements(repair, db) if include_cost else [],
}
if r.repair_links:
sorted_links = sorted(r.repair_links, key=lambda l: l.repair_id, reverse=True)
result["repair"] = _fmt_one_repair(sorted_links[0].repair)
# 재조치로 인한 이전 조치 이력 (최신 제외, re_dispatch_requested=True인 것)
result["prev_repairs"] = [
_fmt_one_repair(link.repair, include_cost=False)
_fmt_one_repair(link.repair, include_cost=True)
for link in sorted_links[1:]
if link.repair
]
@@ -306,6 +339,8 @@ def bulk_delete_reports(
@router.patch("/{report_id}")
async def update_report(
report_id: int,
charger_id: Optional[str] = Form(None),
scope: Optional[str] = Form(None),
issue_types: Optional[str] = Form(None),
issue_detail: Optional[str] = Form(None),
error_code: Optional[str] = Form(None),
@@ -320,6 +355,24 @@ async def update_report(
import json
r = db.query(models.Report).filter_by(id=report_id).first()
if not r: raise HTTPException(404)
if charger_id is not None and charger_id.strip():
ch = db.query(models.Charger).filter_by(id=charger_id.strip()).first()
if not ch: raise HTTPException(400, "충전기를 찾을 수 없습니다")
r.charger_id = charger_id.strip()
if scope is not None and scope in ("single", "station", "type"):
ref = db.query(models.Charger).filter_by(id=r.charger_id).first()
if scope == "station" and ref:
count = db.query(models.Charger).filter_by(
station_name=ref.station_name, is_active=True).count()
elif scope == "type" and ref and ref.charger_type_id:
count = db.query(models.Charger).filter_by(
charger_type_id=ref.charger_type_id, is_active=True).count()
else:
count = 1
r.report_scope = scope
r.scope_charger_count = count
if scope != "multi":
r.charger_ids = None
if issue_types is not None:
r.issue_types = json.loads(issue_types)
if issue_detail is not None: