Ukladanie výsledkov
handle(), sync(), replay() aj úloha vo fronte zdieľajú jedno jadro ukladania. To nasmeruje výsledok podľa type() — z refundácie vznikne PurchaseRefund, z nákupu Purchase, z predplatného Subscription — a spustí príslušné udalosti. Výsledok typu Notification alebo Unknown je informatívny: nikam sa neuloží, nič nespustí a nikdy neprepíše stav predplatného. Líši sa len auditný záznam okolo neho:
| Vstup | Auditný záznam | Uloženie | Vracia |
|---|---|---|---|
handle() | Zapíše sa najprv (origin provider, overený podpis) | Hneď, alebo cez frontu pri queue.enabled | Záznam — alebo auditnú notifikáciu pri fronte či informatívnom výsledku |
sync() | Zapíše sa najprv (origin host, signature_verified false) | Vždy synchrónne | Záznam, alebo null pri informatívnom výsledku |
replay() | Nový sa nezapíše — uložený záznam sa označí ako spracovaný | Synchrónne, zoradené podľa času udalosti | Záznam, alebo null pri informatívnej notifikácii |
Idempotentné od základu
Každý záznam je kľúčovaný unikátnou dvojicou (provider, provider_id), takže keď obchod notifikáciu doručí znova, aktualizuje sa ten istý riadok namiesto duplikátu. Položky sa znova zosynchronizujú vždy, keď ich výsledok obsahuje; cena null ponechá uloženú cenu bez zmeny; pôvodný payload sa uchová v stĺpci meta. Nové predplatné, ktorému obchod nepošle názov, sa pomenuje podľa identifikátora produktu, prípadne identifikátora u poskytovateľa; neskoršia udalosť bez názvu uložený názov ponechá.
Zoradené podľa času udalosti
Ukladanie je zoradené podľa occurredAt(). Každý nákup, predplatné aj refundácia si pamätá čas poslednej uplatnenej udalosti (last_event_at): staršia udalosť — opakované doručenie, doručenie mimo poradia, replay — nič nezmení ani nespustí a refundovaný záznam zostane refundovaný, pokiaľ refundáciu nezvráti preukázateľne novšia udalosť (REFUND_REVERSED od Apple, vyhraný spor v Stripe). Výsledok, ktorý nevie povedať, kedy sa stal (occurredAt() je null — GenericResult zostavený bez neho), sa uplatní ako doteraz, no refundáciu nikdy nezruší. Počas rozhodovania je riadok uzamknutý, takže sa dve súbežné doručenia nemôžu prekrížiť. Záznam, ktorý ste soft-delete zmazali, sa neskoršími notifikáciami stále aktualizuje (zostane zmazaný), no nespustí žiadnu udalosť životného cyklu.
Súbežné prvé doručenia
Transakcia ukladania sa skúsi až trikrát. Na MySQL uzamknutie kľúča, ktorý ešte neexistuje, vytvorí gap lock, takže dve prvé doručenia toho istého nákupu, predplatného či refundácie môžu pri vkladaní uviaznuť v deadlocku (chyba 1213); neúspešná transakcia sa zopakuje a nájde riadok tej úspešnej, namiesto toho, aby jej webhook alebo úloha vo fronte zlyhali.
Dátumy a časové pásmo aplikácie
Všetky obchody uvádzajú dátumy v UTC, kým Eloquent ukladá čas na hodinách inštancie, ktorú dostane. Preto sa každý dátum od poskytovateľa — active_from, trial_ends_at, ends_at, refunded_at aj čas udalosti — pred uložením prevedie do časového pásma aplikácie: na serveri, ktorého app.timezone nie je UTC, predplatné aj tak expiruje v skutočnom okamihu.
Uloženie výsledku, ktorý ste získali sami
Pre výsledok, ktorý neprišiel ako webhook, použite Purchases::sync() — alebo jeho akciu SyncProviderResultAction; pozrite Fasáda Purchases a DI a akcie. Akcie Record* v jadre sú interné (@internal) — vynechajú auditný záznam, ktorý sync() zapíše a označí ako spracovaný.
Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.