Přeskočit na obsah

Webhook potvrzuje platbu jen na jedné z platebních cest

import { Aside } from ‘@astrojs/starlight/components’;

Po migraci z brány A (Stripe) na bránu B (Barion) služby fungují — platba proběhne, aktivace se spustí. Ale objednávky zůstávají payment_status='pending' navždy a faktury vznikají se stavem „Vystavena” místo „Zaplaceno”, přestože peníze prokazatelně přišly (klient kontroluje banku). Admin přehledy ukazují nezaplaceno u zaplacených.

Zápis payment_status='paid' žil jen ve webhooku staré brány A. Webhook nové brány B volal aktivační funkci, která měnila jen workflow status — na payment_status se zapomnělo, protože „to přece nastavuje webhook” (ten starý, mrtvý). Návazný efekt: generátor faktur odvozoval stav faktury z payment_status v momentě vystavení → všechny faktury nové brány „Vystavena”.

// webhook brány B (živý):
await processPayment(ids); // mění jen status → 'in_progress'
// payment_status nastavoval JEN webhook brány A (mrtvý kód)
// generátor faktury:
status: order.payment_status === 'paid' ? 'paid' : 'issued', // vždy 'issued'

Druhá past téže migrace: fail-branch webhooku označoval selhané platby jen v tabulce staré domény (orders), zatímco nové objednávky žily v jiné tabulce (promo_orders) — selhané platby taky zůstaly „pending”.

  1. Potvrzení platby přesunuto do sdílené funkce: atomický claim pending→paid na začátku zpracování (řeší zároveň idempotenci opakovaného IPN).
  2. Fail-branch rozlišuje prefix čísla objednávky a zapisuje do správné tabulky.
  3. Backfill historických dat (status IN (paid,…) AND payment_status='pending' + faktury issued se zaplacenou objednávkou).
  4. Denní invariant-monitor: alarmuje, když se cokoli z toho vrátí.

Jak se tomu vyvarovat v jiných systémech

Sekce “Jak se tomu vyvarovat v jiných systémech”
  • Detection: grep všech zápisů payment_status/status='paid' a ověř, že každá živá platební cesta jimi prochází. SQL smoke: SELECT count(*) WHERE status IN ('paid','completed') AND payment_status<>'paid' — má být 0.
  • Anti-pattern: stavové zápisy roztroušené po webhoocích jednotlivých bran; migrace brány provedená přidáním nové cesty bez auditu, co všechno stará cesta zapisovala.
  • Lepší přístup: jediná funkce confirmPayment(orderRef) (idempotentní claim) volaná ze všech bran + invariant-monitor jako trvalá pojistka.

Sister bugs / související

Sekce “Sister bugs / související”

[[explicit-null-overrides-column-default]] (stejný projekt, stejná migrační vlna). Odvozené stavy (faktura z payment_status) dědí každou díru v primárním stavu — po opravě primáru je nutný backfill odvozených.

Přidal aiarchitekt.cz · 4. 7. 2026 2:00
Provozuje aiarchitekt.cz