File size: 5,640 Bytes
b84ea83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
"""
Assessment Controller — Read operations for Ghost Shopper assessments.

Functions:
    get_assessments_by_visit  — All assessment items for a visit (grouped by category)
"""

import uuid
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import UploadFile


CATEGORY_LABELS = {
    "A": "Pelayanan Awal (Frontliner/Kasir)",
    "B": "Kualitas Produk (Minuman & Makanan)",
    "C": "Kebersihan dan Suasana Outlet",
    "D": "Kepatuhan SOP & Keselamatan",
    "E": "Keseluruhan Pengalaman Pelanggan",
}


async def get_assessments_by_visit(
    db: AsyncSession, visit_id: uuid.UUID
) -> dict | None:
    """
    Get all assessment items for a visit, grouped by category A–E.
    Returns None if visit not found.
    """
    # Check visit exists
    result = await db.execute(
        text("SELECT id FROM visits WHERE id = :vid"), {"vid": visit_id}
    )
    if not result.fetchone():
        return None

    # Get all assessments
    assess_result = await db.execute(text("""
        SELECT id, category, item_no, criteria, score, raw_value, notes, description
        FROM assessments
        WHERE visit_id = :vid
        ORDER BY category, item_no
    """), {"vid": visit_id})

    grouped = {}
    total_score = 0.0
    total_count = 0

    for row in assess_result.fetchall():
        cat = row[1]
        if cat not in grouped:
            grouped[cat] = {
                "category": cat,
                "label": CATEGORY_LABELS.get(cat, cat),
                "items": [],
                "avg_score": 0.0,
            }
        grouped[cat]["items"].append({
            "id": str(row[0]),
            "item_no": row[2],
            "criteria": row[3],
            "score": float(row[4]),
            "raw_value": row[5],
            "notes": row[6],
            "description": row[7],
        })
        total_score += float(row[4])
        total_count += 1

    # Calculate per-category averages
    for cat_data in grouped.values():
        items = cat_data["items"]
        if items:
            cat_data["avg_score"] = round(
                sum(i["score"] for i in items) / len(items), 2
            )

    return {
        "status": "success",
        "data": {
            "visit_id": str(visit_id),
            "categories": grouped,
            "overall_avg": round(total_score / total_count, 2) if total_count > 0 else 0.0,
            "total_items": total_count,
        },
    }

async def update_assessment(
    db: AsyncSession, assessment_id: uuid.UUID, update_data: dict
) -> dict | None:
    """Update an assessment item (score, raw_value, notes, description)."""
    # Check if exists
    result = await db.execute(
        text("SELECT id FROM assessments WHERE id = :id"), {"id": assessment_id}
    )
    if not result.fetchone():
        return None

    # Filter allowed update fields
    allowed = {"score", "raw_value", "notes", "description"}
    updates = {k: v for k, v in update_data.items() if k in allowed}
    
    if not updates:
        return {"status": "success", "message": "No valid fields to update"}

    set_clauses = []
    params = {"id": assessment_id}
    for k, v in updates.items():
        set_clauses.append(f"{k} = :{k}")
        params[k] = v

    query = text(f"UPDATE assessments SET {', '.join(set_clauses)} WHERE id = :id")
    await db.execute(query, params)
    await db.commit()

    return {"status": "success", "message": "Assessment updated successfully"}

async def upload_assessment_photo(
    db: AsyncSession, assessment_id: uuid.UUID, file: UploadFile
) -> dict | None:
    """Mock upload photo to assessment."""
    import os
    from datetime import datetime
    
    # Check if assessment exists
    result = await db.execute(text("SELECT visit_id FROM assessments WHERE id = :id"), {"id": assessment_id})
    row = result.fetchone()
    if not row:
        return None
    visit_id = row[0]

    # Save file
    upload_dir = "uploads/assessments"
    os.makedirs(upload_dir, exist_ok=True)
    file_ext = os.path.splitext(file.filename)[1] if file.filename else ".jpg"
    safe_name = f"assessment_{assessment_id}_{uuid.uuid4().hex[:8]}{file_ext}"
    file_path = os.path.join(upload_dir, safe_name)
    
    content = await file.read()
    with open(file_path, "wb") as f:
        f.write(content)

    # Insert to DB
    photo_id = uuid.uuid4()
    await db.execute(
        text("""
            INSERT INTO photos (id, visit_id, assessment_id, file_path, file_name, file_size, mime_type, uploaded_at)
            VALUES (:id, :vid, :aid, :path, :name, :size, :mime, :now)
        """),
        {
            "id": photo_id,
            "vid": visit_id,
            "aid": assessment_id,
            "path": file_path,
            "name": safe_name,
            "size": len(content),
            "mime": file.content_type or "image/jpeg",
            "now": datetime.utcnow()
        }
    )
    await db.commit()

    return {"status": "success", "data": {"id": str(photo_id), "file_path": file_path}}

async def get_assessment_photos(
    db: AsyncSession, assessment_id: uuid.UUID
) -> list[dict] | None:
    """Get all photos for an assessment item."""
    result = await db.execute(
        text("SELECT id FROM assessments WHERE id = :id"), {"id": assessment_id}
    )
    if not result.fetchone():
        return None

    photos_result = await db.execute(
        text("SELECT id, file_path, file_name FROM photos WHERE assessment_id = :id"),
        {"id": assessment_id}
    )
    return [
        {"id": str(row[0]), "file_path": row[1], "file_name": row[2]}
        for row in photos_result
    ]