Files
X-Financial/server/src/app/models/attachment_association_job.py

111 lines
4.7 KiB
Python

from __future__ import annotations
from datetime import datetime
from typing import Any
from sqlalchemy import (
Boolean,
CheckConstraint,
DateTime,
Float,
Index,
Integer,
String,
Text,
UniqueConstraint,
func,
)
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON
from app.db.base_class import Base
class AttachmentAssociationJob(Base):
"""可跨进程恢复的票据归集任务状态。"""
__tablename__ = "attachment_association_jobs"
__table_args__ = (
UniqueConstraint(
"tenant_id",
"owner_username",
"dedupe_key",
"generation",
name="uq_attachment_association_jobs_owner_dedupe",
),
CheckConstraint(
"status IN ('queued', 'running', 'succeeded', 'failed')",
name="ck_attachment_association_jobs_status",
),
CheckConstraint(
"attempt_count >= 0",
name="ck_attachment_association_jobs_attempt_count",
),
CheckConstraint(
"generation >= 1",
name="ck_attachment_association_jobs_generation",
),
CheckConstraint(
"status != 'running' OR lease_expires_at IS NOT NULL",
name="ck_attachment_association_jobs_running_lease",
),
Index(
"ix_attachment_association_jobs_owner_time",
"tenant_id",
"owner_username",
"created_at",
),
Index(
"ix_attachment_association_jobs_status_lease",
"status",
"lease_expires_at",
),
)
id: Mapped[str] = mapped_column(String(80), primary_key=True)
tenant_id: Mapped[str] = mapped_column(String(64), nullable=False)
owner_username: Mapped[str] = mapped_column(String(255), nullable=False)
owner_name: Mapped[str] = mapped_column(String(255), nullable=False, default="")
owner_context_json: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False, default=dict)
dedupe_key: Mapped[str] = mapped_column(String(64), nullable=False)
generation: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
receipt_ids_json: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
prompt: Mapped[str] = mapped_column(Text, nullable=False, default="")
conversation_id: Mapped[str] = mapped_column(String(120), nullable=False, default="")
status: Mapped[str] = mapped_column(String(20), nullable=False, default="queued")
message: Mapped[str] = mapped_column(Text, nullable=False, default="")
claim_id: Mapped[str] = mapped_column(String(36), nullable=False, default="")
claim_no: Mapped[str] = mapped_column(String(80), nullable=False, default="")
uploaded_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
skipped_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
resolution: Mapped[str] = mapped_column(String(40), nullable=False, default="pending")
requires_confirmation: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
expense_case_id: Mapped[str] = mapped_column(String(36), nullable=False, default="")
application_claim_id: Mapped[str] = mapped_column(String(36), nullable=False, default="")
application_claim_no: Mapped[str] = mapped_column(String(80), nullable=False, default="")
confidence: Mapped[str] = mapped_column(String(20), nullable=False, default="")
confidence_score: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
match_reasons_json: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
exceptions_json: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
missing_fields_json: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
risk_items_json: Mapped[list[str]] = mapped_column(JSON, nullable=False, default=list)
candidates_json: Mapped[list[dict[str, Any]]] = mapped_column(JSON, nullable=False, default=list)
draft_payload_json: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)
error: Mapped[str] = mapped_column(Text, nullable=False, default="")
attempt_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
lease_expires_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True),
nullable=True,
)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
server_default=func.now(),
nullable=False,
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
server_default=func.now(),
onupdate=func.now(),
nullable=False,
)