Aller au contenu

Cartes cadeaux (gift cards)

Extrait du domain map API, qui était chargé dans chaque session agent. La rule garde l'index module → contexte ; le détail vit ici, à côté du code.

Le parrainage a sa propre doc : investor-referral/docs/.

  • La gift_card est emise a l'achat (createGiftCard, appele par createGiftCardPurchaseWt) : ligne en pending, tandis que la WT gift_card_purchase reste waiting. L'email destinataire (notifyGiftCardRecipient) part apres le commit SQL de l'achat : un echec ne rollback pas la carte, il declenche une alerte Slack pour renvoi manuel. Sous une transaction parente (topup carte), l'appelant l'envoie apres son propre commit. Le worker played-lemonway-p2p ne fait plus que la confirmer quand le P2P donneur -> compte d'attente aboutit. Les WT creees avant ce changement n'ont pas de giftcardId en contexte : confirmGiftCardCreation les emet encore, email compris dans la transaction du worker, fallback a supprimer quand la file est vide
  • Consequence : entre l'emission et la reussite du P2P, la carte existe et est claimable alors que la WT est waiting. refundGiftCard, pour tout P2P pending (achat, et credit du claimer avant de le passer declined), interroge Lemonway (GET /p2p?reference=<wtId>) dans la transaction du refund, WT verrouillee FOR UPDATE. Trouve chez Lemonway : refus gift-card.refund-p2p-in-flight, rien ne bouge ; l'admin reessaie une fois que le worker pending-p2p-to-play a passe le P2P en succeeded (il se retrouve seul par la reference). Absent : pas d'argent deplace, refund confirmed sans P2P inverse. Echec du GET : lemonway-p2p.lw-check-failed. Pas de decalage cote Bricks entre le check et le refund : le worker verrouille la meme WT (SKIP LOCKED) avant le POST et ne selectionne que les WT waiting. Risque residuel accepte : une requete deja recue par Lemonway mais pas encore executee a l'instant du GET (crash du worker en plein POST). Si le P2P finit failed, declineGiftCardPurchase decline la WT en laissant la carte claimable
  • Le refund d'une gift card claimee doit d'abord debiter le giftBalance du claimer (P2P claimer -> compte d'attente), puis refund le donneur en withdrawableBalance
  • Le claim applique le code parrain du donneur au claimer (si eligible : pas de referrer existant, dans la fenetre de durabilite)
  • L'email est schedule en heure francaise (emailTriggerFrenchHour en Europe/Paris), converti en UTC
  • L'expiration est calculee depuis triggerDate (pas depuis l'envoi de l'email)
  • Le gift balance est separe du withdrawable balance (credit gift, pas withdrawable)
  • La ligne gift_card a deux ecrivains concurrents : le claim (status/claimer*) et le worker PDF (documentState). Les deux ecrivent le document entier, ce qui n'est sur que parce que chacun lit sous FOR UPDATE et ecrit dans la meme transaction — le worker PDF la tient pendant la generation + S3 + email, donc plusieurs secondes. Le claim lit en for update skip locked et n'attend donc jamais derriere lui : 0 ligne = code inconnu ou ligne prise, desambigue par une relecture sans verrou (gift-card-temporarily-locked vs gift-card-not-found). Codes d'erreur du claim en kebab sans point : le front les utilise directement comme cle i18n et . y est un separateur de niveaux. Sortir l'I/O de la transaction imposera de relire la ligne sous verrou avant d'ecrire
  • Un P2P d'achat qui echoue sur debit_account_blocked (codes Lemonway 111/167) gele le donneur mais ne decline pas l'achat : le P2P repart en pending sans nouveau délai (attemptAfter conserve) et la WT reste waiting, donc les fonds restent reserves. Le ranking unifie (debitsRankedToPlayCTE) exclut P2P et retraits d'un donneur gele : un withdraw waiting ne peut pas passer devant pendant le gel. Au degel, les deux reviennent dans le FIFO, ordonnes par index (pas de priorite gift-card). Toute autre erreur business decline l'achat (declineGiftCardPurchase + email d'erreur au donneur)
  • confirmGiftCardCredit renvoie Err('gift-card.not-found-for-credit-wt') si la carte ne pointe plus vers la WT de credit. La WT reste waiting et bloque la file du customer (1 WT par customer dans played-lemonway-p2p) : code d'erreur loggue a chaque iteration, detection par monitor Datadog, resolution manuelle