133 lines
6.4 KiB
Python
133 lines
6.4 KiB
Python
from sqlalchemy import Column, String, Boolean, DateTime, Integer, Numeric, ForeignKey
|
|
from sqlalchemy.sql import func
|
|
from sqlalchemy.orm import relationship
|
|
from app.core.database.db_session import Base
|
|
|
|
class ServiceCatalog(Base):
|
|
__tablename__ = "service_catalog"
|
|
|
|
service_id = Column(String(26), primary_key=True)
|
|
name = Column(String(255), nullable=False)
|
|
description = Column(String(1000), nullable=True)
|
|
base_price = Column(Numeric(10, 2), nullable=False)
|
|
estimated_duration_minutes = Column(Integer, nullable=False)
|
|
workflow_type = Column(String(50), default="REPAIR_QUOTE") # FIXED_SERVICE, INSPECTION_REQUIRED, REPAIR_QUOTE
|
|
active = Column(Boolean, default=True)
|
|
|
|
from sqlalchemy import Date
|
|
|
|
class ServiceJob(Base):
|
|
__tablename__ = "service_jobs"
|
|
|
|
job_id = Column(String(26), primary_key=True)
|
|
job_no = Column(String(50), unique=True, nullable=False)
|
|
customer_id = Column(String(26), nullable=False, index=True)
|
|
device_id = Column(String(26), ForeignKey("customer_devices.device_id"), nullable=False)
|
|
source = Column(String(20), default="ONLINE") # ONLINE, WALK_IN
|
|
service_id = Column(String(26), ForeignKey("service_catalog.service_id"), nullable=True) # Nullable for Cashify-style jobs
|
|
status = Column(String(30), default="BOOKING_PENDING", index=True)
|
|
custom_service_name = Column(String(255), nullable=True)
|
|
|
|
# Granular selection IDs
|
|
device_type = Column(String(50), nullable=True)
|
|
brand_id = Column(String(26), ForeignKey("brands.brand_id"), nullable=True)
|
|
series_id = Column(String(26), ForeignKey("device_series.series_id"), nullable=True)
|
|
model_id = Column(String(26), ForeignKey("device_models.model_id"), nullable=True)
|
|
service_type_id = Column(String(26), nullable=True)
|
|
repair_service_id = Column(String(26), nullable=True)
|
|
repair_variant_id = Column(String(26), nullable=True)
|
|
|
|
# Parity Price & Config Snapshots
|
|
currency = Column(String(3), default="INR", nullable=False)
|
|
service_name_snapshot = Column(String(255), nullable=True)
|
|
variant_name_snapshot = Column(String(255), nullable=True)
|
|
base_price_snapshot = Column(Numeric(10, 2), nullable=True)
|
|
duration_snapshot = Column(Integer, nullable=True)
|
|
warranty_snapshot = Column(Integer, nullable=True)
|
|
inspection_fee_snapshot = Column(Numeric(10, 2), nullable=True)
|
|
|
|
# Queue & Priority Attributes
|
|
queue_number = Column(String(50), nullable=True)
|
|
queue_date = Column(Date, nullable=True)
|
|
priority = Column(String(20), default="NORMAL")
|
|
|
|
created_at = Column(DateTime, server_default=func.now())
|
|
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
|
|
|
device = relationship("CustomerDevice")
|
|
service = relationship("ServiceCatalog")
|
|
|
|
class ServiceAppointment(Base):
|
|
__tablename__ = "service_appointments"
|
|
|
|
appointment_id = Column(String(26), primary_key=True)
|
|
service_job_id = Column(String(26), ForeignKey("service_jobs.job_id"), nullable=False, index=True)
|
|
scheduled_start = Column(DateTime, nullable=False)
|
|
scheduled_end = Column(DateTime, nullable=False)
|
|
status = Column(String(20), default="HELD", index=True) # HELD, CONFIRMED, CANCELLED, EXPIRED, COMPLETED
|
|
hold_expires_at = Column(DateTime, nullable=True)
|
|
created_at = Column(DateTime, server_default=func.now())
|
|
confirmed_at = Column(DateTime, nullable=True)
|
|
cancelled_at = Column(DateTime, nullable=True)
|
|
|
|
job = relationship("ServiceJob")
|
|
|
|
class ServiceJobAssignment(Base):
|
|
__tablename__ = "service_job_assignments"
|
|
|
|
assignment_id = Column(String(26), primary_key=True)
|
|
service_job_id = Column(String(26), ForeignKey("service_jobs.job_id"), nullable=False, index=True)
|
|
appointment_id = Column(String(26), ForeignKey("service_appointments.appointment_id"), nullable=False)
|
|
technician_id = Column(String(26), nullable=False, index=True)
|
|
assigned_at = Column(DateTime, server_default=func.now())
|
|
assigned_by = Column(String(26), nullable=True)
|
|
unassigned_at = Column(DateTime, nullable=True)
|
|
reason = Column(String(255), nullable=True)
|
|
|
|
class ServiceJobIntake(Base):
|
|
__tablename__ = "service_job_intakes"
|
|
|
|
intake_id = Column(String(26), primary_key=True)
|
|
service_job_id = Column(String(26), ForeignKey("service_jobs.job_id"), nullable=False, unique=True)
|
|
received_by = Column(String(26), nullable=False)
|
|
received_at = Column(DateTime, server_default=func.now())
|
|
power_status = Column(String(50), nullable=True)
|
|
screen_condition = Column(String(100), nullable=True)
|
|
body_condition = Column(String(100), nullable=True)
|
|
back_condition = Column(String(100), nullable=True)
|
|
camera_condition = Column(String(100), nullable=True)
|
|
accessories = Column(String(255), nullable=True)
|
|
customer_notes = Column(String(1000), nullable=True)
|
|
technician_notes = Column(String(1000), nullable=True)
|
|
|
|
class ServiceJobInspection(Base):
|
|
__tablename__ = "service_job_inspections"
|
|
|
|
inspection_id = Column(String(26), primary_key=True)
|
|
service_job_id = Column(String(26), ForeignKey("service_jobs.job_id"), nullable=False, index=True)
|
|
technician_id = Column(String(26), nullable=False, index=True)
|
|
result = Column(String(50), nullable=False) # CUSTOMER_REPORT_CONFIRMED, CUSTOMER_REPORT_PARTIALLY_CONFIRMED, CUSTOMER_REPORT_NOT_CONFIRMED, ADDITIONAL_DAMAGE_FOUND
|
|
customer_report = Column(String(1000), nullable=True)
|
|
confirmed_damage = Column(String(1000), nullable=True)
|
|
additional_damage = Column(String(1000), nullable=True)
|
|
notes = Column(String(1000), nullable=True)
|
|
created_at = Column(DateTime, server_default=func.now())
|
|
|
|
class ServiceJobMedia(Base):
|
|
__tablename__ = "service_job_media"
|
|
|
|
media_id = Column(String(26), primary_key=True)
|
|
service_job_id = Column(String(26), ForeignKey("service_jobs.job_id"), nullable=False, index=True)
|
|
category = Column(String(50), nullable=False) # INTAKE_PHOTO, INTAKE_VIDEO, BEFORE_REPAIR, AFTER_REPAIR
|
|
file_id = Column(String(100), nullable=False)
|
|
created_at = Column(DateTime, server_default=func.now())
|
|
|
|
class ServiceJobEvent(Base):
|
|
__tablename__ = "service_job_events"
|
|
|
|
event_id = Column(String(26), primary_key=True)
|
|
job_id = Column(String(26), ForeignKey("service_jobs.job_id"), nullable=False, index=True)
|
|
event_type = Column(String(50), nullable=False)
|
|
performed_by = Column(String(26), nullable=False)
|
|
timestamp = Column(DateTime, server_default=func.now())
|
|
notes = Column(String(500), nullable=True)
|