This commit is contained in:
@@ -264,6 +264,10 @@ class ServiceEmployee(Base):
|
||||
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")
|
||||
@@ -311,15 +315,35 @@ 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(
|
||||
@@ -328,6 +352,9 @@ class ServiceVisit(Base):
|
||||
|
||||
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):
|
||||
@@ -395,7 +422,12 @@ class ServiceNotification(Base):
|
||||
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="unread", server_default="unread", index=True)
|
||||
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)
|
||||
|
||||
|
||||
@@ -406,7 +438,13 @@ class ServiceWorkItem(Base):
|
||||
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))
|
||||
@@ -414,11 +452,85 @@ class ServiceWorkItem(Base):
|
||||
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"),)
|
||||
|
||||
Reference in New Issue
Block a user