Реализованы сервисы ВМ2 - проверка сообщений и синхронизация с Б24 (деплой еще без перевода в боевой режим)
This commit is contained in:
@@ -34,6 +34,10 @@ class Base(DeclarativeBase):
|
||||
type_annotation_map = {dict[str, Any]: JSON}
|
||||
|
||||
|
||||
class BitrixBase(DeclarativeBase):
|
||||
"""Models owned by bitrix-sync, excluded from han_app create_all."""
|
||||
|
||||
|
||||
class Common:
|
||||
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
record_status: Mapped[str] = mapped_column(String(1), default="A", server_default="A")
|
||||
@@ -142,6 +146,9 @@ class Message(Common, Base):
|
||||
content_kind: Mapped[str] = mapped_column(String(16))
|
||||
text: Mapped[str] = mapped_column(Text, default="")
|
||||
safety_status: Mapped[str] = mapped_column(String(16))
|
||||
safety_processing_mode: Mapped[str | None] = mapped_column(String(16))
|
||||
safety_config_version: Mapped[int | None] = mapped_column(BigInteger)
|
||||
safety_rules_version: Mapped[str | None] = mapped_column(String(128))
|
||||
delivery_status: Mapped[str] = mapped_column(String(16))
|
||||
external_message_id: Mapped[str | None] = mapped_column(String(255))
|
||||
client_idempotency_key: Mapped[str | None] = mapped_column(String(128))
|
||||
@@ -152,7 +159,7 @@ class MessageAttachment(Common, Base):
|
||||
__tablename__ = "message_attachments"
|
||||
__table_args__ = (
|
||||
CheckConstraint("direction IN ('client_upload','company_inbound')"),
|
||||
CheckConstraint("scan_status IN ('pending','clean','infected','failed')"),
|
||||
CheckConstraint("scan_status IN ('pending','clean','bypassed','infected','failed')"),
|
||||
CheckConstraint("size_bytes > 0"),
|
||||
{"schema": SCHEMA},
|
||||
)
|
||||
@@ -171,6 +178,8 @@ class MessageAttachment(Common, Base):
|
||||
storage_bucket: Mapped[str] = mapped_column(String(255))
|
||||
object_key: Mapped[str] = mapped_column(String(1024))
|
||||
quarantine_object_key: Mapped[str | None] = mapped_column(String(1024))
|
||||
quarantine_version_id: Mapped[str | None] = mapped_column(String(1024))
|
||||
quarantine_etag: Mapped[str | None] = mapped_column(String(1024))
|
||||
upload_expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
|
||||
@@ -193,10 +202,15 @@ class SafetyTask(Base):
|
||||
__table_args__ = ({"schema": SCHEMA},)
|
||||
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
task_id: Mapped[str] = mapped_column(String(255), unique=True)
|
||||
poll_location: Mapped[str] = mapped_column(String(1024))
|
||||
message_id: Mapped[uuid.UUID] = mapped_column(ForeignKey(f"{SCHEMA}.messages.id"), unique=True)
|
||||
attachment_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
|
||||
quarantine_object_key: Mapped[str | None] = mapped_column(String(1024))
|
||||
status: Mapped[str] = mapped_column(String(16))
|
||||
processing_mode: Mapped[str | None] = mapped_column(String(16))
|
||||
config_version: Mapped[int | None] = mapped_column(BigInteger)
|
||||
rules_version: Mapped[str | None] = mapped_column(String(128))
|
||||
expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True))
|
||||
deadline_at: Mapped[datetime] = mapped_column(DateTime(timezone=True))
|
||||
next_poll_at: Mapped[datetime] = mapped_column(DateTime(timezone=True))
|
||||
attempt_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
@@ -321,18 +335,32 @@ class PopularQuestion(Common, Base):
|
||||
|
||||
class SyncQueue(Base):
|
||||
__tablename__ = "sync_queue"
|
||||
__table_args__ = ({"schema": SCHEMA},)
|
||||
__table_args__ = (
|
||||
CheckConstraint(
|
||||
"status IN ('pending','leased','processed','retry_wait','dead_letter','cancelled')"
|
||||
),
|
||||
Index("ix_sync_queue_claim", "status", "next_attempt_at", "created_at"),
|
||||
Index("ix_sync_queue_entity_history", "entity_type", "entity_id", "created_at"),
|
||||
{"schema": SCHEMA},
|
||||
)
|
||||
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
task_type: Mapped[str] = mapped_column(String(64))
|
||||
entity_type: Mapped[str] = mapped_column(String(64))
|
||||
entity_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True))
|
||||
dedup_key: Mapped[str] = mapped_column(String(255), unique=True)
|
||||
dedup_key: Mapped[str] = mapped_column(String(255))
|
||||
payload_json: Mapped[dict[str, Any]] = mapped_column(JSON)
|
||||
status: Mapped[str] = mapped_column(String(16), default="pending")
|
||||
attempt_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
next_attempt_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now()
|
||||
)
|
||||
locked_by: Mapped[str | None] = mapped_column(String(128))
|
||||
locked_until: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
lease_token: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True))
|
||||
last_error_code: Mapped[str | None] = mapped_column(String(64))
|
||||
last_error_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
cancel_reason: Mapped[str | None] = mapped_column(String(255))
|
||||
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())
|
||||
|
||||
@@ -347,6 +375,53 @@ class EntityExternalMapping(Base):
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
|
||||
class BitrixEntityExternalMapping(BitrixBase):
|
||||
__tablename__ = "entity_external_mapping"
|
||||
__table_args__ = ({"schema": "bitrix_sync"},)
|
||||
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
entity_type: Mapped[str] = mapped_column(String(64))
|
||||
entity_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True))
|
||||
external_system: Mapped[str] = mapped_column(String(32), default="bitrix24")
|
||||
external_entity_type: Mapped[str] = mapped_column(String(32), default="contact")
|
||||
external_id: Mapped[str] = mapped_column(String(128))
|
||||
status: Mapped[str] = mapped_column(String(16), default="active")
|
||||
opened_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
closed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
close_reason: Mapped[str | None] = mapped_column(String(64))
|
||||
workflow_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=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())
|
||||
|
||||
|
||||
Index(
|
||||
"uq_sync_queue_active_dedup",
|
||||
SyncQueue.dedup_key,
|
||||
unique=True,
|
||||
postgresql_where=SyncQueue.status.in_(["pending", "leased", "retry_wait"]),
|
||||
)
|
||||
Index(
|
||||
"ix_sync_queue_expired_lease",
|
||||
SyncQueue.locked_until,
|
||||
postgresql_where=SyncQueue.status == "leased",
|
||||
)
|
||||
Index(
|
||||
"uq_external_mapping_active_entity",
|
||||
BitrixEntityExternalMapping.external_system,
|
||||
BitrixEntityExternalMapping.entity_type,
|
||||
BitrixEntityExternalMapping.entity_id,
|
||||
unique=True,
|
||||
postgresql_where=BitrixEntityExternalMapping.status == "active",
|
||||
)
|
||||
Index(
|
||||
"uq_external_mapping_active_external",
|
||||
BitrixEntityExternalMapping.external_system,
|
||||
BitrixEntityExternalMapping.external_entity_type,
|
||||
BitrixEntityExternalMapping.external_id,
|
||||
unique=True,
|
||||
postgresql_where=BitrixEntityExternalMapping.status == "active",
|
||||
)
|
||||
|
||||
|
||||
class Database:
|
||||
def __init__(self, url: str) -> None:
|
||||
self.engine: AsyncEngine = create_postgres_engine(url, pool_pre_ping=True)
|
||||
|
||||
Reference in New Issue
Block a user