Spaces:
Sleeping
Sleeping
File size: 4,748 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 | """
Assessment Model β ORM + Pydantic Schemas
ORM: Assessment (SQLAlchemy table: assessments)
Schemas: AssessmentCreate, AssessmentResponse
Stores individual Ghost Shopper evaluation items for each visit.
Each visit has ~21 assessment items grouped into 5 categories (AβE).
Categories:
A = Pelayanan Awal (Frontliner/Kasir) β 5 items
B = Kualitas Produk (Minuman & Makanan) β 5 items
C = Kebersihan dan Suasana Outlet β 4 items
D = Kepatuhan SOP & Keselamatan β 2 items
E = Keseluruhan Pengalaman Pelanggan β 5 items
All ratings are normalized to a 1.0β5.0 float scale regardless of
the original input format (Ya/Tidak, Qualitative, or Numeric).
"""
import uuid
from datetime import datetime
from typing import Optional
from sqlalchemy import String, Text, Float, Integer, DateTime, ForeignKey, func
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship
from pydantic import BaseModel, Field, ConfigDict
from models.base import Base
# ββββββββββββββββββββββββββββββββββββββββββββββββββ
# ORM Model
# ββββββββββββββββββββββββββββββββββββββββββββββββββ
class Assessment(Base):
"""SQLAlchemy ORM model for the 'assessments' table."""
__tablename__ = "assessments"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
)
visit_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
ForeignKey("visits.id", ondelete="CASCADE"),
nullable=False,
)
category: Mapped[str] = mapped_column(
String(1), nullable=False,
comment="Assessment category: A, B, C, D, or E"
)
item_no: Mapped[int] = mapped_column(
Integer, nullable=False,
comment="Item sequence number within the category (1-based)"
)
criteria: Mapped[str] = mapped_column(
String(500), nullable=False,
comment="Assessment question/criteria text"
)
score: Mapped[float] = mapped_column(
Float, nullable=False,
comment="Normalized score 1.0 to 5.0"
)
raw_value: Mapped[str] = mapped_column(
String(100), nullable=False,
comment="Original value from document: 'Baik', 'Ya', '4', etc."
)
notes: Mapped[Optional[str]] = mapped_column(
Text, nullable=True,
comment="Catatan / notes from the Ghost Shopper"
)
description: Mapped[Optional[str]] = mapped_column(
Text, nullable=True,
comment="Detailed evaluator description / observation for this item"
)
created_at: Mapped[datetime] = mapped_column(
DateTime, server_default=func.now()
)
# Relationships
visit = relationship("Visit", back_populates="assessments")
photos = relationship(
"Photo", back_populates="assessment",
cascade="all, delete-orphan",
foreign_keys="Photo.assessment_id",
)
def __repr__(self) -> str:
return (
f"<Assessment(category={self.category}, item={self.item_no}, "
f"score={self.score}, raw='{self.raw_value}')>"
)
# ββββββββββββββββββββββββββββββββββββββββββββββββββ
# Pydantic Schemas
# ββββββββββββββββββββββββββββββββββββββββββββββββββ
class AssessmentCreate(BaseModel):
"""Schema for creating an assessment item."""
category: str = Field(..., min_length=1, max_length=1, description="Category A-E")
item_no: int = Field(..., ge=1, le=10, description="Item number within category")
criteria: str = Field(..., min_length=1, max_length=500, description="Criteria text")
score: float = Field(..., ge=1.0, le=5.0, description="Normalized score 1.0-5.0")
raw_value: str = Field(..., max_length=100, description="Original raw value")
notes: Optional[str] = Field(None, description="Catatan from evaluator")
description: Optional[str] = Field(None, description="Detailed observation/description for this item")
class AssessmentResponse(BaseModel):
"""Schema for an assessment item in API responses."""
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
visit_id: uuid.UUID
category: str
item_no: int
criteria: str
score: float
raw_value: str
notes: Optional[str]
description: Optional[str]
created_at: datetime
|