feat(tradein/payments): схема БД, конфиг и kill-switch платёжного контура #2732

Merged
lekss361 merged 5 commits from feat/tradein-payments-schema into main 2026-08-06 16:33:28 +00:00

5 commits

Author SHA1 Message Date
bot-backend
95ed9c7811 fix(tradein/payments): номер 232->233 + статусы T-Bank по официальной спеке
All checks were successful
CI / changes (pull_request) Successful in 9s
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 3m10s
Четыре правки HOLD-ревью PR #2732, форма таблиц не меняется:

1. Коллизия номера: 232_listings_observation_time_meaning.sql несёт открытый
   PR #2742 (не main, поэтому пропущено в прошлый раз). Переименовано 232 ->
   233 (git mv, история сохранена), manifest обновлён. Урок задокументирован
   в шапке файла: сверять номер нужно по main И по всем открытым PR-веткам.
   Перепроверено дважды (main + 5 остальных открытых веток) — 233 свободен.

2. payments_status_check дополнен пятью реальными in-flight статусами из
   канонического источника (OpenAPI-спека developer.tbank.ru/schemas/eacq/
   openapi.yaml, схема Confirm-2, v1.24): CHECKING, CHECKED, PROCESSING,
   COMPLETING, COMPLETED. Это статусы, которые GetState/CheckOrder вернёт по
   зависшему платежу — их читает реконсиляция PR-E; пропуск реального
   значения был единственным опасным направлением ошибки CHECK.

3. Блок про источник статусов переписан: убрана ссылка на сторонний Go-клиент
   и формулировка "enum рендерится клиентским JS" — источник истины теперь
   openapi.yaml. Отдельно зафиксировано: GetState/CheckOrder объявляют Status
   свободной строкой (maxLength: 20, без enum) — наш CHECK строже контракта
   поставщика, осознанно.

4. Контракт 'UNKNOWN' переадресован: теперь явно на обработчик нотификаций
   И задачу реконсиляции (GetState/CheckOrder, PR-E), а не только на вебхуки.

Побочно подтверждено спекой: AUTHORIZED_AND_CHARGED/RECEIPT_REGISTERED
отсутствуют (плюс maxLength:20 делает первое физически невозможным);
3DS_CHECKING/3DS_CHECKED и PREAUTHORIZING есть; ATTEMPTS_EXPIRED/PAY_CHECKING
нет; PARTIAL_REVERSED/REFUND_FAILED тоже нет в спеке — оставлены как
безвредный запас, комментарий перестал ложно утверждать обратное.

Полный pytest: 3858 passed, 10 skipped, 0 failed.
2026-08-06 19:28:44 +03:00
bot-backend
04b268ad3a fix(tradein/payments): разрешить коллизию номера миграции 228 -> 232
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 7s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 3m7s
Пока PR был на ревью, в main влились 228_scrape_proxies_browser_health.sql
и 230_house_merge_log.sql — номер 228 занят, 229/231 параллельно занимает
PR #2547. Переименовано в 232_payments.sql (git mv, история файла сохранена),
manifest обновлён (228_payments.sql -> 232_payments.sql), шапка миграции
объясняет причину переименования и актуализирован "Apply after".

Смержен свежий forgejo/main (обычный merge, без rebase/force-push) —
конфликтов не было, config.py не задет. test_new_files_do_not_reuse_prefix
теперь зелёный. Полный pytest после merge: 3858 passed, 10 skipped, 0 failed.
2026-08-06 19:07:02 +03:00
bot-backend
31620c7559 Merge remote-tracking branch 'refs/remotes/forgejo/main' into feat/tradein-payments-schema 2026-08-06 19:00:24 +03:00
bot-backend
b8f225bf86 fix(tradein/payments): NULLS NOT DISTINCT дедуп, pd_erased_at, статусы T-Bank
All checks were successful
CI / changes (pull_request) Successful in 8s
CI Trade-In / changes (pull_request) Successful in 10s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 3m9s
HOLD-правки ревью PR #2732 (миграция ни разу не применялась на проде,
manifest не трогаем):

- Блокер: UNIQUE(payment_id, kind, ref_id) и UNIQUE(tbank_payment_id, status,
  amount_kopecks, token) не защищали при NULL (NULL != NULL в Postgres) —
  на проде воспроизведено 3 одинаковых INSERT -> 3 строки. Оба ключа теперь
  UNIQUE NULLS NOT DISTINCT (PG15+, прод на 16.4).
- payment_notifications.processed_at — контракт "выдача состоялась" для PR-D,
  закрывает окно at-most-once (падение между INSERT нотификации и выдачей
  товара при захолдированных деньгах).
- payments_lead_idx — FK lead_id ON DELETE SET NULL без индекса это seq scan
  на каждый DELETE FROM trade_in_leads, а #2547 вводит пакетное удаление.
- payment_entitlements: убраны amount/consumed — модель кредитов/пакетов
  явно отвергнута в mera-b2c-paid-flow-decision.md §1 (capability-URL вместо
  кошелька).
- payments.pd_erased_at — покрытие purge-контура #2547, который не знает про
  ПДн в payments (customer_email/customer_phone), появляющиеся в PR-D.
- payments.order_id CHECK char_length <= 50 — лимит T-Bank OrderId, падать
  у себя, а не на /v2/Init.
- payments.status CHECK сверен с github.com/nikita-vanyasin/tinkoff/status.go
  (developer.tbank.ru рендерит enum клиентским JS, прямого доступа нет):
  убраны неподтверждённые AUTHORIZED_AND_CHARGED/RECEIPT_REGISTERED, добавлены
  подтверждённые 3DS_CHECKING/3DS_CHECKED. ATTEMPTS_EXPIRED/PAY_CHECKING НЕ
  добавлены — не подтверждены ни одним источником.
- config.py: комментарий TBANK_PAY_TYPE ссылался на recon-док (выбирает "O"),
  переставлен на mera-b2c-paid-flow-decision.md §1 (выбирает "T", источник
  реального дефолта).

Полный pytest: 3755 passed, 9 skipped, 0 failed.
2026-08-06 15:52:44 +03:00
bot-backend
277d7e6030 feat(tradein/payments): схема БД, конфиг и kill-switch платёжного контура
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 3m5s
2026-08-06 15:16:20 +03:00