from datetime import date, datetime, time from decimal import Decimal from sqlalchemy import ( JSON, Boolean, Date, DateTime, ForeignKey, Integer, Numeric, String, Text, Time, UniqueConstraint, func, ) from sqlalchemy.orm import Mapped, mapped_column, relationship from app.db.base import Base class Car(Base): __tablename__ = "cars" id: Mapped[int] = mapped_column(primary_key=True) owner_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) name: Mapped[str] = mapped_column(String(160)) make: Mapped[str | None] = mapped_column(String(80)) model: Mapped[str | None] = mapped_column(String(80)) trim: Mapped[str | None] = mapped_column(String(120)) generation: Mapped[str | None] = mapped_column(String(120)) body_type: Mapped[str | None] = mapped_column(String(80)) year: Mapped[int | None] plate_number: Mapped[str | None] = mapped_column(String(32)) vin: Mapped[str | None] = mapped_column(String(32)) license_plate_display: Mapped[str | None] = mapped_column(String(32)) license_plate_normalized: Mapped[str | None] = mapped_column(String(32), index=True) license_plate_country: Mapped[str | None] = mapped_column(String(2), index=True) vin_normalized: Mapped[str | None] = mapped_column(String(17), unique=True, index=True) fuel_type: Mapped[str | None] = mapped_column(String(32)) engine_volume_l: Mapped[Decimal | None] = mapped_column(Numeric(5, 2)) transmission: Mapped[str | None] = mapped_column(String(40)) drive_type: Mapped[str | None] = mapped_column(String(40)) target_consumption_l_per_100km: Mapped[Decimal | None] = mapped_column(Numeric(6, 2)) fuel_tank_volume_l: Mapped[Decimal | None] = mapped_column(Numeric(6, 2)) engine_oil_type: Mapped[str | None] = mapped_column(String(80)) engine_oil_volume_l: Mapped[Decimal | None] = mapped_column(Numeric(5, 2)) transmission_fluid_type: Mapped[str | None] = mapped_column(String(80)) transmission_fluid_volume_l: Mapped[Decimal | None] = mapped_column(Numeric(5, 2)) coolant_type: Mapped[str | None] = mapped_column(String(80)) brake_fluid_type: Mapped[str | None] = mapped_column(String(80)) tire_pressure_front_bar: Mapped[Decimal | None] = mapped_column(Numeric(4, 2)) tire_pressure_rear_bar: Mapped[Decimal | None] = mapped_column(Numeric(4, 2)) tire_size: Mapped[str | None] = mapped_column(String(80)) oil_change_interval_km: Mapped[int | None] = mapped_column(Integer) oil_change_interval_months: Mapped[int | None] = mapped_column(Integer) purchase_date: Mapped[date | None] = mapped_column(Date) purchase_price: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) purchase_currency: Mapped[str | None] = mapped_column(String(3)) purchase_type: Mapped[str] = mapped_column(String(24), default="unknown", server_default="unknown") currency: Mapped[str] = mapped_column(String(3), default="RUB", server_default="RUB") include_depreciation: Mapped[bool] = mapped_column(Boolean, default=False, server_default="false") expected_ownership_months: Mapped[int | None] = mapped_column(Integer) expected_residual_value: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) loan_principal: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) loan_down_payment: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) loan_term_months: Mapped[int | None] = mapped_column(Integer) loan_annual_interest_rate: Mapped[Decimal | None] = mapped_column(Numeric(6, 3)) loan_first_payment_date: Mapped[date | None] = mapped_column(Date) loan_payment_day: Mapped[int | None] = mapped_column(Integer) loan_payment_type: Mapped[str] = mapped_column(String(24), default="annuity", server_default="annuity") loan_currency: Mapped[str | None] = mapped_column(String(3)) loan_comment: Mapped[str | None] = mapped_column(Text) current_odometer: Mapped[int | None] notes: Mapped[str | None] = mapped_column(Text) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) owner = relationship("User", back_populates="cars") fuel_entries = relationship("FuelEntry", back_populates="car", cascade="all, delete-orphan") service_entries = relationship("ServiceEntry", back_populates="car", cascade="all, delete-orphan") expense_entries = relationship("ExpenseEntry", back_populates="car", cascade="all, delete-orphan") service_links = relationship("CarServiceLink", back_populates="car", cascade="all, delete-orphan") odometer_history = relationship("OdometerHistory", back_populates="car", cascade="all, delete-orphan") class CarMake(Base): __tablename__ = "car_makes" id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(80), unique=True, index=True) country: Mapped[str | None] = mapped_column(String(80)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) models = relationship("CarModel", back_populates="make", cascade="all, delete-orphan") class CarModel(Base): __tablename__ = "car_models" __table_args__ = (UniqueConstraint("make_id", "name", name="uq_car_models_make_name"),) id: Mapped[int] = mapped_column(primary_key=True) make_id: Mapped[int] = mapped_column(ForeignKey("car_makes.id", ondelete="CASCADE"), index=True) name: Mapped[str] = mapped_column(String(100), index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) make = relationship("CarMake", back_populates="models") trims = relationship("CarTrim", back_populates="model", cascade="all, delete-orphan") class CarTrim(Base): __tablename__ = "car_trims" __table_args__ = (UniqueConstraint("model_id", "name", name="uq_car_trims_model_name"),) id: Mapped[int] = mapped_column(primary_key=True) model_id: Mapped[int] = mapped_column(ForeignKey("car_models.id", ondelete="CASCADE"), index=True) name: Mapped[str] = mapped_column(String(120), index=True) body_type: Mapped[str | None] = mapped_column(String(60)) fuel_type: Mapped[str | None] = mapped_column(String(32)) transmission: Mapped[str | None] = mapped_column(String(32)) drive_type: Mapped[str | None] = mapped_column(String(32)) year_from: Mapped[int | None] = mapped_column(Integer) year_to: Mapped[int | None] = mapped_column(Integer) market: Mapped[str | None] = mapped_column(String(80)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) model = relationship("CarModel", back_populates="trims") class ServiceCenter(Base): __tablename__ = "service_centers" id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(160), unique=True, index=True) legal_name: Mapped[str | None] = mapped_column(String(240)) display_name: Mapped[str | None] = mapped_column(String(160), index=True) country: Mapped[str | None] = mapped_column(String(2), index=True) city: Mapped[str | None] = mapped_column(String(120)) telegram_chat_id: Mapped[str | None] = mapped_column(String(80), unique=True, index=True) phone: Mapped[str | None] = mapped_column(String(40)) contact_phone: Mapped[str | None] = mapped_column(String(40)) address: Mapped[str | None] = mapped_column(String(240)) description: Mapped[str | None] = mapped_column(Text) specializations: Mapped[list | None] = mapped_column(JSON) working_hours: Mapped[str | None] = mapped_column(String(240)) facade_photo_url: Mapped[str | None] = mapped_column(String(500)) document_photo_urls: Mapped[list | None] = mapped_column(JSON) additional_photo_urls: Mapped[list | None] = mapped_column(JSON) contact_person: Mapped[str | None] = mapped_column(String(160)) rating_avg: Mapped[Decimal | None] = mapped_column(Numeric(3, 2)) reviews_count: Mapped[int] = mapped_column(Integer, default=0, server_default="0") business_registration_number: Mapped[str | None] = mapped_column(String(80)) verification_status: Mapped[str] = mapped_column(String(24), default="pending", server_default="pending", index=True) owner_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) verified_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) suspended_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) car_links = relationship("CarServiceLink", back_populates="service_center", cascade="all, delete-orphan") inbox_messages = relationship("ServiceInboxMessage", back_populates="service_center") employees = relationship("ServiceEmployee", back_populates="service_center", cascade="all, delete-orphan") visits = relationship("ServiceVisit", back_populates="service_center") reviews = relationship("ServiceCenterReview", back_populates="service_center", cascade="all, delete-orphan") booking_settings = relationship( "ServiceCenterBookingSettings", back_populates="service_center", cascade="all, delete-orphan", uselist=False, ) holidays = relationship("ServiceCenterHoliday", back_populates="service_center", cascade="all, delete-orphan") appointments = relationship("ServiceAppointment", back_populates="service_center", cascade="all, delete-orphan") class CarServiceLink(Base): __tablename__ = "car_service_links" __table_args__ = (UniqueConstraint("car_id", "service_center_id", name="uq_car_service_link"),) id: Mapped[int] = mapped_column(primary_key=True) car_id: Mapped[int] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), index=True) service_center_id: Mapped[int] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True) external_vehicle_ref: Mapped[str | None] = mapped_column(String(120), index=True) access_level: Mapped[str] = mapped_column(String(32), default="basic", server_default="basic", index=True) status: Mapped[str] = mapped_column(String(32), default="pending", server_default="pending", index=True) requested_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True) approved_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True) approved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) revoked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) is_active: Mapped[bool] = mapped_column(default=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) car = relationship("Car", back_populates="service_links") service_center = relationship("ServiceCenter", back_populates="car_links") class OdometerHistory(Base): __tablename__ = "odometer_history" id: Mapped[int] = mapped_column(primary_key=True) car_id: Mapped[int] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), index=True) previous_odometer: Mapped[int | None] = mapped_column(Integer) new_odometer: Mapped[int] = mapped_column(Integer) source_record_type: Mapped[str] = mapped_column(String(40), index=True) source_record_id: Mapped[int | None] = mapped_column(Integer, index=True) changed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True) changed_by: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True) confirmation_required: Mapped[bool] = mapped_column(Boolean, default=False, server_default="false") user_confirmed: Mapped[bool] = mapped_column(Boolean, default=True, server_default="true") car = relationship("Car", back_populates="odometer_history") class ServiceInboxMessage(Base): __tablename__ = "service_inbox_messages" id: Mapped[int] = mapped_column(primary_key=True) service_center_id: Mapped[int | None] = mapped_column(ForeignKey("service_centers.id", ondelete="SET NULL"), index=True) car_id: Mapped[int | None] = mapped_column(ForeignKey("cars.id", ondelete="SET NULL"), index=True) source_chat_id: Mapped[str | None] = mapped_column(String(80), index=True) raw_text: Mapped[str] = mapped_column(Text) parsed_status: Mapped[str] = mapped_column(String(32), default="pending", index=True) parsed_payload: Mapped[str | None] = mapped_column(Text) error: Mapped[str | None] = mapped_column(Text) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) service_center = relationship("ServiceCenter", back_populates="inbox_messages") class VehicleAccess(Base): __tablename__ = "vehicle_access" __table_args__ = (UniqueConstraint("vehicle_id", "user_id", "role", name="uq_vehicle_access_user_role"),) id: Mapped[int] = mapped_column(primary_key=True) vehicle_id: Mapped[int] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), index=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) role: Mapped[str] = mapped_column(String(24), default="owner", server_default="owner", index=True) status: Mapped[str] = mapped_column(String(24), default="active", server_default="active", index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) revoked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) class ServiceCenterVerification(Base): __tablename__ = "service_center_verifications" id: Mapped[int] = mapped_column(primary_key=True) service_center_id: Mapped[int] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True) submitted_documents: Mapped[list | None] = mapped_column(JSON) comment: Mapped[str | None] = mapped_column(Text) status: Mapped[str] = mapped_column(String(24), default="pending", server_default="pending", index=True) reviewed_by: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True) reviewed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) class ServiceEmployee(Base): __tablename__ = "service_employees" __table_args__ = (UniqueConstraint("service_center_id", "user_id", name="uq_service_employee_user"),) id: Mapped[int] = mapped_column(primary_key=True) service_center_id: Mapped[int] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) role: Mapped[str] = mapped_column(String(32), default="receptionist", server_default="receptionist", index=True) permissions: Mapped[dict | None] = mapped_column(JSON) status: Mapped[str] = mapped_column(String(24), default="active", server_default="active", index=True) invite_token: Mapped[str | None] = mapped_column(String(96), unique=True, index=True) invite_expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) invite_revoked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) activated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) service_center = relationship("ServiceCenter", back_populates="employees") class ServiceCenterBookingSettings(Base): __tablename__ = "service_center_booking_settings" id: Mapped[int] = mapped_column(primary_key=True) service_center_id: Mapped[int] = mapped_column( ForeignKey("service_centers.id", ondelete="CASCADE"), unique=True, index=True ) working_days: Mapped[list] = mapped_column(JSON, default=lambda: [0, 1, 2, 3, 4], server_default="[0,1,2,3,4]") open_time: Mapped[time] = mapped_column(Time, default=time(9, 0), server_default="09:00:00") close_time: Mapped[time] = mapped_column(Time, default=time(18, 0), server_default="18:00:00") lunch_break_start: Mapped[time | None] = mapped_column(Time) lunch_break_end: Mapped[time | None] = mapped_column(Time) timezone: Mapped[str] = mapped_column(String(64), default="Asia/Seoul", server_default="Asia/Seoul") slot_duration_minutes: Mapped[int] = mapped_column(Integer, default=30, server_default="30") booking_buffer_minutes: Mapped[int] = mapped_column(Integer, default=0, server_default="0") max_parallel_bookings: Mapped[int] = mapped_column(Integer, default=1, server_default="1") accepts_online_booking: Mapped[bool] = mapped_column(Boolean, default=True, server_default="true", index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) service_center = relationship("ServiceCenter", back_populates="booking_settings") class ServiceCenterHoliday(Base): __tablename__ = "service_center_holidays" __table_args__ = (UniqueConstraint("service_center_id", "holiday_date", name="uq_service_center_holiday"),) id: Mapped[int] = mapped_column(primary_key=True) service_center_id: Mapped[int] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True) holiday_date: Mapped[date] = mapped_column(Date, index=True) reason: Mapped[str | None] = mapped_column(String(240)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) service_center = relationship("ServiceCenter", back_populates="holidays") class ServiceVisit(Base): __tablename__ = "service_visits" id: Mapped[int] = mapped_column(primary_key=True) work_order_number: Mapped[str | None] = mapped_column(String(40), unique=True, index=True) service_center_id: Mapped[int] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True) vehicle_id: Mapped[int] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), index=True) owner_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True) created_by_employee_id: Mapped[int | None] = mapped_column(ForeignKey("service_employees.id", ondelete="SET NULL"), index=True) assigned_employee_id: Mapped[int | None] = mapped_column(ForeignKey("service_employees.id", ondelete="SET NULL"), index=True) visit_date: Mapped[date] = mapped_column(Date, index=True) odometer: Mapped[int | None] status: Mapped[str] = mapped_column(String(40), default="draft", server_default="draft", index=True) customer_complaint: Mapped[str | None] = mapped_column(Text) diagnosis: Mapped[str | None] = mapped_column(Text) notes: Mapped[str | None] = mapped_column(Text) service_comment: Mapped[str | None] = mapped_column(Text) owner_comment: Mapped[str | None] = mapped_column(Text) recommendations_text: Mapped[str | None] = mapped_column(Text) attachment_urls: Mapped[list | None] = mapped_column(JSON) total_cost: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) labor_total: Mapped[Decimal] = mapped_column(Numeric(12, 2), default=0, server_default="0") product_total: Mapped[Decimal] = mapped_column(Numeric(12, 2), default=0, server_default="0") discount_total: Mapped[Decimal] = mapped_column(Numeric(12, 2), default=0, server_default="0") final_total: Mapped[Decimal] = mapped_column(Numeric(12, 2), default=0, server_default="0") price_approved_total: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) approval_required: Mapped[bool] = mapped_column(Boolean, default=False, server_default="false") version: Mapped[int] = mapped_column(Integer, default=1, server_default="1") completed_snapshot: Mapped[dict | None] = mapped_column(JSON) currency: Mapped[str] = mapped_column(String(3), default="RUB", server_default="RUB") opened_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) approved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) owner_resolved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) service_center = relationship("ServiceCenter", back_populates="visits") work_items = relationship("ServiceWorkItem", back_populates="visit", cascade="all, delete-orphan") product_items = relationship("ServiceProductItem", back_populates="visit", cascade="all, delete-orphan") status_history = relationship("WorkOrderStatusHistory", back_populates="visit", cascade="all, delete-orphan") corrections = relationship("WorkOrderCorrection", back_populates="visit", cascade="all, delete-orphan") class MaintenanceRecommendation(Base): __tablename__ = "maintenance_recommendations" id: Mapped[int] = mapped_column(primary_key=True) vehicle_id: Mapped[int] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), index=True) recommendation_type: Mapped[str] = mapped_column(String(64), index=True) title: Mapped[str] = mapped_column(String(180)) description: Mapped[str | None] = mapped_column(Text) due_odometer_km: Mapped[int | None] = mapped_column(Integer, index=True) due_date: Mapped[date | None] = mapped_column(Date, index=True) priority: Mapped[str] = mapped_column(String(24), default="medium", server_default="medium", index=True) status: Mapped[str] = mapped_column(String(24), default="active", server_default="active", index=True) source: Mapped[str] = mapped_column(String(40), default="system_analysis", server_default="system_analysis", index=True) source_service_center_id: Mapped[int | None] = mapped_column(ForeignKey("service_centers.id", ondelete="SET NULL"), index=True) source_appointment_id: Mapped[int | None] = mapped_column(Integer, index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) class ServiceAppointment(Base): __tablename__ = "service_appointments" id: Mapped[int] = mapped_column(primary_key=True) service_center_id: Mapped[int] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True) vehicle_id: Mapped[int] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), index=True) owner_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) created_by: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) service_type: Mapped[str] = mapped_column(String(64), index=True) service_name: Mapped[str] = mapped_column(String(180)) requested_start_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True) requested_end_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True) confirmed_start_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), index=True) confirmed_end_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) proposed_start_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), index=True) proposed_end_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) estimated_duration_minutes: Mapped[int] = mapped_column(Integer, default=60, server_default="60") status: Mapped[str] = mapped_column(String(40), default="requested", server_default="requested", index=True) customer_comment: Mapped[str | None] = mapped_column(Text) service_center_comment: Mapped[str | None] = mapped_column(Text) source_recommendation_id: Mapped[int | None] = mapped_column( ForeignKey("maintenance_recommendations.id", ondelete="SET NULL"), index=True ) linked_work_order_id: Mapped[int | None] = mapped_column(ForeignKey("service_visits.id", ondelete="SET NULL"), index=True) cancellation_reason: Mapped[str | None] = mapped_column(Text) cancelled_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) service_center = relationship("ServiceCenter", back_populates="appointments") class ServiceNotification(Base): __tablename__ = "service_notifications" id: Mapped[int] = mapped_column(primary_key=True) recipient_user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) service_center_id: Mapped[int | None] = mapped_column(ForeignKey("service_centers.id", ondelete="SET NULL"), index=True) appointment_id: Mapped[int | None] = mapped_column(ForeignKey("service_appointments.id", ondelete="SET NULL"), index=True) notification_type: Mapped[str] = mapped_column(String(80), index=True) title: Mapped[str] = mapped_column(String(180)) body: Mapped[str | None] = mapped_column(Text) status: Mapped[str] = mapped_column(String(24), default="pending", server_default="pending", index=True) retry_count: Mapped[int] = mapped_column(Integer, default=0, server_default="0") last_error: Mapped[str | None] = mapped_column(Text) idempotency_key: Mapped[str | None] = mapped_column(String(160), unique=True, index=True) sent_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) read_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True) class ServiceWorkItem(Base): __tablename__ = "service_work_items" id: Mapped[int] = mapped_column(primary_key=True) service_visit_id: Mapped[int] = mapped_column(ForeignKey("service_visits.id", ondelete="CASCADE"), index=True) work_type: Mapped[str] = mapped_column(String(40), default="other", server_default="other", index=True) title: Mapped[str] = mapped_column(String(180)) category: Mapped[str | None] = mapped_column(String(80)) description: Mapped[str | None] = mapped_column(Text) quantity: Mapped[Decimal] = mapped_column(Numeric(10, 3), default=1, server_default="1") unit: Mapped[str] = mapped_column(String(24), default="pcs", server_default="pcs") unit_price: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) discount: Mapped[Decimal] = mapped_column(Numeric(12, 2), default=0, server_default="0") total: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) parts: Mapped[list | None] = mapped_column(JSON) oil_brand: Mapped[str | None] = mapped_column(String(80)) oil_viscosity: Mapped[str | None] = mapped_column(String(40)) oil_volume: Mapped[Decimal | None] = mapped_column(Numeric(5, 2)) next_due_odometer: Mapped[int | None] next_due_date: Mapped[date | None] = mapped_column(Date) price: Mapped[Decimal | None] = mapped_column(Numeric(12, 2)) warranty_days: Mapped[int | None] = mapped_column(Integer) warranty_odometer_km: Mapped[int | None] = mapped_column(Integer) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) visit = relationship("ServiceVisit", back_populates="work_items") class ServiceProductItem(Base): __tablename__ = "service_product_items" id: Mapped[int] = mapped_column(primary_key=True) service_visit_id: Mapped[int] = mapped_column(ForeignKey("service_visits.id", ondelete="CASCADE"), index=True) title: Mapped[str] = mapped_column(String(180)) category: Mapped[str | None] = mapped_column(String(80), index=True) product_type: Mapped[str] = mapped_column(String(40), default="other", server_default="other", index=True) brand: Mapped[str | None] = mapped_column(String(80)) sku: Mapped[str | None] = mapped_column(String(120)) quantity: Mapped[Decimal] = mapped_column(Numeric(10, 3), default=1, server_default="1") unit: Mapped[str] = mapped_column(String(24), default="pcs", server_default="pcs") unit_price: Mapped[Decimal] = mapped_column(Numeric(12, 2), default=0, server_default="0") discount: Mapped[Decimal] = mapped_column(Numeric(12, 2), default=0, server_default="0") total: Mapped[Decimal] = mapped_column(Numeric(12, 2), default=0, server_default="0") volume: Mapped[Decimal | None] = mapped_column(Numeric(8, 3)) viscosity: Mapped[str | None] = mapped_column(String(40)) specification: Mapped[str | None] = mapped_column(String(120)) used_volume: Mapped[Decimal | None] = mapped_column(Numeric(8, 3)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) visit = relationship("ServiceVisit", back_populates="product_items") class WorkOrderStatusHistory(Base): __tablename__ = "work_order_status_history" id: Mapped[int] = mapped_column(primary_key=True) service_visit_id: Mapped[int] = mapped_column(ForeignKey("service_visits.id", ondelete="CASCADE"), index=True) from_status: Mapped[str | None] = mapped_column(String(40)) to_status: Mapped[str] = mapped_column(String(40), index=True) changed_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True) comment: Mapped[str | None] = mapped_column(Text) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True) visit = relationship("ServiceVisit", back_populates="status_history") class WorkOrderCorrection(Base): __tablename__ = "work_order_corrections" id: Mapped[int] = mapped_column(primary_key=True) service_visit_id: Mapped[int] = mapped_column(ForeignKey("service_visits.id", ondelete="CASCADE"), index=True) requested_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True) reason: Mapped[str] = mapped_column(Text) proposed_changes: Mapped[dict | None] = mapped_column(JSON) status: Mapped[str] = mapped_column(String(24), default="pending", server_default="pending", index=True) owner_approval_required: Mapped[bool] = mapped_column(Boolean, default=True, server_default="true") created_version: Mapped[int] = mapped_column(Integer, default=1, server_default="1") resolved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True) visit = relationship("ServiceVisit", back_populates="corrections") class InventoryTransaction(Base): __tablename__ = "inventory_transactions" id: Mapped[int] = mapped_column(primary_key=True) service_center_id: Mapped[int] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True) service_visit_id: Mapped[int | None] = mapped_column(ForeignKey("service_visits.id", ondelete="SET NULL"), index=True) product_item_id: Mapped[int | None] = mapped_column(ForeignKey("service_product_items.id", ondelete="SET NULL"), index=True) transaction_type: Mapped[str] = mapped_column(String(32), index=True) sku: Mapped[str | None] = mapped_column(String(120), index=True) title: Mapped[str | None] = mapped_column(String(180)) quantity: Mapped[Decimal] = mapped_column(Numeric(10, 3), default=0, server_default="0") unit: Mapped[str] = mapped_column(String(24), default="pcs", server_default="pcs") actor_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True) metadata_json: Mapped[dict | None] = mapped_column(JSON) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True) class ServiceCenterReview(Base): __tablename__ = "service_center_reviews" __table_args__ = (UniqueConstraint("service_center_id", "user_id", name="uq_service_review_user"),) id: Mapped[int] = mapped_column(primary_key=True) service_center_id: Mapped[int] = mapped_column(ForeignKey("service_centers.id", ondelete="CASCADE"), index=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) rating: Mapped[int] = mapped_column(Integer) text: Mapped[str | None] = mapped_column(Text) photo_urls: Mapped[list | None] = mapped_column(JSON) status: Mapped[str] = mapped_column(String(24), default="published", server_default="published", index=True) service_response: Mapped[str | None] = mapped_column(Text) service_responded_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) service_center = relationship("ServiceCenter", back_populates="reviews") comments = relationship("ServiceCenterReviewComment", back_populates="review", cascade="all, delete-orphan") class ServiceCenterReviewComment(Base): __tablename__ = "service_center_review_comments" id: Mapped[int] = mapped_column(primary_key=True) review_id: Mapped[int] = mapped_column(ForeignKey("service_center_reviews.id", ondelete="CASCADE"), index=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) text: Mapped[str] = mapped_column(Text) status: Mapped[str] = mapped_column(String(24), default="published", server_default="published", index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True) review = relationship("ServiceCenterReview", back_populates="comments") class VehicleDataChangeRequest(Base): __tablename__ = "vehicle_data_change_requests" id: Mapped[int] = mapped_column(primary_key=True) vehicle_id: Mapped[int] = mapped_column(ForeignKey("cars.id", ondelete="CASCADE"), index=True) requested_by_service_center_id: Mapped[int | None] = mapped_column(ForeignKey("service_centers.id", ondelete="SET NULL"), index=True) requested_by_employee_id: Mapped[int | None] = mapped_column(ForeignKey("service_employees.id", ondelete="SET NULL"), index=True) field_name: Mapped[str] = mapped_column(String(80), index=True) old_value: Mapped[str | None] = mapped_column(Text) new_value: Mapped[str | None] = mapped_column(Text) status: Mapped[str] = mapped_column(String(24), default="pending", server_default="pending", index=True) owner_user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) resolved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) class AuditLog(Base): __tablename__ = "audit_logs" id: Mapped[int] = mapped_column(primary_key=True) actor_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"), index=True) actor_role: Mapped[str | None] = mapped_column(String(64)) action: Mapped[str] = mapped_column(String(120), index=True) target_type: Mapped[str] = mapped_column(String(80), index=True) target_id: Mapped[str | None] = mapped_column(String(80), index=True) ip: Mapped[str | None] = mapped_column(String(64)) user_agent: Mapped[str | None] = mapped_column(String(256)) metadata_json: Mapped[dict | None] = mapped_column(JSON) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), index=True)