intra_max_bot/app/repositories/applications.py
2026-03-19 16:47:49 +03:00

178 lines
5.9 KiB
Python

from __future__ import annotations
import json
from typing import Iterable
from app.db import Database
from app.models import (
ApplicationCreate,
ApplicationEventRecord,
ApplicationRecord,
ExternalSyncStatus,
utc_now_iso,
)
class ApplicationRepository:
def __init__(self, db: Database) -> None:
self._db = db
def create(self, payload: ApplicationCreate) -> ApplicationRecord:
now = utc_now_iso()
with self._db.connect() as conn:
cursor = conn.execute(
"""
INSERT INTO applications (
customer_id, customer_name, chat_id, category, description,
attachments_json, status, external_sync_status, source, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, 'new', ?, ?, ?, ?)
""",
(
payload.customer_id,
payload.customer_name,
payload.chat_id,
payload.category,
payload.description,
payload.attachments_json,
ExternalSyncStatus.NOT_SENT.value,
payload.source,
now,
now,
),
)
app_id = cursor.lastrowid
self.add_event(
conn=conn,
application_id=app_id,
event_type="created",
actor=payload.source,
details={"category": payload.category},
)
row = conn.execute("SELECT * FROM applications WHERE id = ?", (app_id,)).fetchone()
conn.commit()
return ApplicationRecord(**dict(row))
def get(self, application_id: int) -> ApplicationRecord | None:
with self._db.connect() as conn:
row = conn.execute("SELECT * FROM applications WHERE id = ?", (application_id,)).fetchone()
return ApplicationRecord(**dict(row)) if row else None
def list(
self,
status: str | None = None,
search: str | None = None,
limit: int = 100,
offset: int = 0,
) -> list[ApplicationRecord]:
clauses: list[str] = []
params: list[object] = []
if status:
clauses.append("status = ?")
params.append(status)
if search:
clauses.append("(customer_name LIKE ? OR description LIKE ? OR CAST(id AS TEXT) LIKE ?)")
like = f"%{search}%"
params.extend([like, like, like])
where_sql = f"WHERE {' AND '.join(clauses)}" if clauses else ""
params.extend([limit, offset])
sql = f"""
SELECT * FROM applications
{where_sql}
ORDER BY created_at DESC
LIMIT ? OFFSET ?
"""
with self._db.connect() as conn:
rows = conn.execute(sql, params).fetchall()
return [ApplicationRecord(**dict(row)) for row in rows]
def update_status(
self,
application_id: int,
status: str,
actor: str,
reason: str | None = None,
) -> ApplicationRecord | None:
now = utc_now_iso()
with self._db.connect() as conn:
exists = conn.execute("SELECT id FROM applications WHERE id = ?", (application_id,)).fetchone()
if not exists:
return None
conn.execute(
"UPDATE applications SET status = ?, updated_at = ? WHERE id = ?",
(status, now, application_id),
)
self.add_event(
conn=conn,
application_id=application_id,
event_type="status_changed",
actor=actor,
details={"status": status, "reason": reason},
)
row = conn.execute("SELECT * FROM applications WHERE id = ?", (application_id,)).fetchone()
conn.commit()
return ApplicationRecord(**dict(row))
def update_external_sync(
self,
application_id: int,
sync_status: str,
external_id: str | None,
external_error: str | None,
) -> None:
now = utc_now_iso()
with self._db.connect() as conn:
conn.execute(
"""
UPDATE applications
SET external_sync_status = ?, external_id = ?, external_error = ?, updated_at = ?
WHERE id = ?
""",
(sync_status, external_id, external_error, now, application_id),
)
self.add_event(
conn=conn,
application_id=application_id,
event_type="external_sync",
actor="external_api",
details={
"sync_status": sync_status,
"external_id": external_id,
"external_error": external_error,
},
)
conn.commit()
def get_events(self, application_id: int) -> list[ApplicationEventRecord]:
with self._db.connect() as conn:
rows = conn.execute(
"""
SELECT * FROM application_events
WHERE application_id = ?
ORDER BY created_at DESC
""",
(application_id,),
).fetchall()
return [ApplicationEventRecord(**dict(row)) for row in rows]
@staticmethod
def add_event(
conn,
application_id: int,
event_type: str,
actor: str,
details: dict[str, object] | None = None,
) -> None:
conn.execute(
"""
INSERT INTO application_events (application_id, event_type, actor, details_json, created_at)
VALUES (?, ?, ?, ?, ?)
""",
(
application_id,
event_type,
actor,
json.dumps(details or {}, ensure_ascii=False),
utc_now_iso(),
),
)