Files
lux_fiscal/backend/app/worker.py
T
lauadminandClaude Opus 5.5 518a99197f Add Checkbox ETTN receipts for Nova Poshta COD waybills
Cashier creates an ETTN receipt in Checkbox bound to the TTN with payment
control; Checkbox fiscalizes it itself when the parcel is paid for.

- cash_registers (Fernet-encrypted license key / PIN) and receipts tables
- Checkbox HTTP client + stub (ETTN does not work on test registers)
- two-phase create via ARQ job, timeout reconciliation, cron status polling
- /receipts and /cash-registers API, audit records
- dashboard: per-order and bulk create, prepayment, cancel; cash registers page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 23:39:00 +03:00

63 lines
2.3 KiB
Python

"""ARQ worker: опрос Nova Poshta и ЕТТН-чеки Checkbox.
Запускается отдельным процессом: `arq app.worker.WorkerSettings`.
- `create_ettn_receipt` — задача, которую ставит API после запроса кассира;
- `poll_np_statuses` — раз в минуту статусы ТТН по заказам без чека;
- `poll_receipts` — раз в минуту повтор зависших `pending` и статусы `created`-чеков.
"""
from __future__ import annotations
import uuid
from typing import Any
from arq import cron
from arq.connections import RedisSettings
from app.core.config import settings
from app.core.logging import configure_logging, get_logger
from app.db.session import SessionFactory
from app.services import receipts as receipts_service
from app.services.checkbox.client import get_checkbox_client
from app.services.nova_poshta.np_client import NpTrackingClient
from app.services.orders import sync_np_statuses
log = get_logger(__name__)
async def startup(ctx: dict[str, Any]) -> None:
configure_logging()
ctx["np_client"] = NpTrackingClient(settings)
ctx["checkbox_client"] = get_checkbox_client()
log.info("worker_starting", environment=settings.environment)
async def poll_np_statuses(ctx: dict[str, Any]) -> None:
async with SessionFactory() as session:
await sync_np_statuses(session, ctx["np_client"])
log.info("np_statuses_polled")
async def create_ettn_receipt(ctx: dict[str, Any], receipt_id: str) -> None:
async with SessionFactory() as session:
await receipts_service.create_ettn_for_receipt(
session, ctx["checkbox_client"], uuid.UUID(receipt_id)
)
async def poll_receipts(ctx: dict[str, Any]) -> None:
async with SessionFactory() as session:
await receipts_service.retry_pending_receipts(session, ctx["checkbox_client"])
await receipts_service.sync_ettn_statuses(session, ctx["checkbox_client"])
log.info("receipts_polled")
class WorkerSettings:
redis_settings = RedisSettings.from_dsn(settings.redis_url)
on_startup = startup
functions = [create_ettn_receipt]
cron_jobs = [
cron(poll_np_statuses, minute=set(range(60)), run_at_startup=True),
cron(poll_receipts, minute=set(range(60)), second=30),
]