Checkbox ETTN receipts, order editing, dashboard tabs and COD summary #1

Merged
lauadmin merged 10 commits from feature/checkbox-ettn into main 2026-09-24 22:36:52 +00:00
Owner

Что сделано

  • ЕТТН-чеки в Checkbox по ТТН Новой Почты с контролем оплаты (двухфазное создание через worker, повтор при rate limit NP, поиск существующего чека перед повторной отправкой).
  • После принятия чека Checkbox заказ переводится в CRM в статус PACKED.
  • Редактирование заказа в карточке (только без чека).
  • Вкладки дашборда: «Без чека», «Выписаны чеки», «Полученные», «Отказы» — статус посылки NP важнее наличия чека.
  • Сводка «Наложка в пути» над вкладками (GET /orders/summary): сумма и число посылок, которые ещё не забраны и без отказа.
  • nginx фронтенда резолвит upstream api на каждый запрос.

Проверка

  • pytest — 141 passed, ruff чисто
  • npm run build и npm run lint — без ошибок
  • ЕТТН пока не проверены на реальной кассе (на тестовой кассе Checkbox ЕТТН не работает)

🤖 Generated with Claude Code

## Что сделано - ЕТТН-чеки в Checkbox по ТТН Новой Почты с контролем оплаты (двухфазное создание через worker, повтор при rate limit NP, поиск существующего чека перед повторной отправкой). - После принятия чека Checkbox заказ переводится в CRM в статус PACKED. - Редактирование заказа в карточке (только без чека). - Вкладки дашборда: «Без чека», «Выписаны чеки», «Полученные», «Отказы» — статус посылки NP важнее наличия чека. - Сводка «Наложка в пути» над вкладками (`GET /orders/summary`): сумма и число посылок, которые ещё не забраны и без отказа. - nginx фронтенда резолвит upstream api на каждый запрос. ## Проверка - `pytest` — 141 passed, `ruff` чисто - `npm run build` и `npm run lint` — без ошибок - ЕТТН пока не проверены на реальной кассе (на тестовой кассе Checkbox ЕТТН не работает) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
lauadmin added 10 commits 2026-09-24 22:34:00 +00:00
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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Payments now carry type=ETTN / label=Експрес-накладна instead of relying on
Checkbox defaults; body build fails fast if goods - discounts - prepayment
does not equal the COD amount.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nginx resolved api:8000 once at startup, so recreating the api container
(new IP) left the proxy pointing at a dead address and every /api call
returned 502.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- prepayment as DISCOUNT: live API rejects PRE_PAYMENT with 400 third_party.generic
- normalize lowercase ETTN statuses returned by the live API
- show Checkbox error code instead of bare 'Internal Server Error'
- page size 50 for ETTN list, 429 rate limit is retryable, pause polling on it
- phone in 380XXXXXXXXX format like portal receipts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ExoCrmClient.set_status: live SetStatus needs {Orders: [id], Status} and
  replies per order, unlike the documented {ID, Status}
- receipts.crm_status_set_at (migration 0006); set right after creation,
  retried by cron, row-locked to avoid a repeat PACKED overwriting a newer status
- CRM errors under capitalized 'Errors' and non-JSON replies are reported

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cashiers can edit recipient, TTN, notes, goods and total in the order
modal and save via PATCH /orders/{id}. Edited orders get edited_at and
are no longer overwritten by CRM sync. Editing is blocked once a receipt
exists; changing the TTN resets Nova Poshta tracking fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Orders whose Nova Poshta status is a refusal (102/103/105/108) now show
only under «Отказы», whether or not they have a receipt. GET /orders takes
tab=no_receipt|has_receipt|refused instead of has_receipt. NP statuses are
also polled for orders that already have a receipt, until NP reports a
final status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Checkbox relays Nova Poshta's "To many requests" (20000401501) as a 4xx
third_party.generic error, not a 429, so bursts of receipt requests ended
up as failed receipts. Such responses are now CheckboxRateLimitedError:
the receipt stays pending and the worker job is retried with arq.Retry
after the "Try again after N seconds" delay plus backoff. NP timeouts
relayed the same way are treated as unavailable (unknown outcome).

The HTTP client also sends Checkbox requests one at a time with a
CHECKBOX_MIN_REQUEST_INTERVAL_MS pause and signs the cashier in once for
concurrent jobs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- GET /orders/summary: count and sum of cash-on-delivery for parcels not
  yet picked up (excludes received, refused, deleted/unknown TTNs, paid COD);
  shown as a card above the tabs.
- New «Полученные» tab: orders with NP received codes (9, 10, 11, 106) move
  there automatically, regardless of receipt; 106 is now a final status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lauadmin merged commit ed635cab94 into main 2026-09-24 22:36:52 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: lauadmin/lux_fiscal#1