Calendrier fixe Stripe — 1.1.0-dev.5, version de recette

Portée
Les nouveaux contrats Stripe fixes reçoivent calendar_basis=stripe_utc_v1 dans
leurs conditions immuables, avant consentement. Les contrats déjà enregistrés
sans ce marqueur conservent leur moteur et leurs références. Pas de migration
automatique ni de recréation d'abonnement existant.

Dates
L'instant initial est converti en UTC. Son jour, heure, minute et seconde sont
transmis à billing_cycle_anchor_config ; le mois est ajouté pour l'annuel.
Les dates du récapitulatif sont calculées avec cette même base UTC. L'heure et,
près de minuit, la date locale peuvent différer : ce n'est pas une promesse
d'heure locale fixe malgré les changements d'heure. L'information est affichée
avant le consentement. Les contrats variables gardent leur calendrier local.

Création
Après encaissement des paiements initiaux : création du produit, abonnement
avec proration_behavior=none, contrôle de la première échéance et de l'absence
de facture initiale, conversion from_subscription, configuration de l'échéancier.
Un calendrier distant différent entraîne une demande d'annulation, pas une
acceptation silencieuse. La programmation doit avoir lieu dans la première
période du contrat ; une souscription future ou échue exige un traitement dédié.

Paiements fractionnés
La période initiale déjà payée est conservée sans prorata. Seules les sommes
restantes sont ajoutées aux phases suivantes. Les montants égaux sont regroupés,
le reste d'arrondi appartient à la dernière échéance. Les bornes de phase sont
explicites et calculées depuis l'ancre originale. end_behavior=cancel termine
l'abonnement après la période de la dernière échéance. L'abonnement illimité
utilise release, sans arrêter l'abonnement sous-jacent.

Résistance aux coupures
Colonne additive schedule_state_json : étape prévue enregistrée AVANT chaque
appel, puis références reçues enregistrées APRÈS. Clés d'idempotence propres à
chaque étape. Le statut scheduling empêche une deuxième création ; un webhook
précoce ne libère pas ce verrou. Le journal ne contient aucun secret.
Si une étape échoue après identification de l'abonnement, tentative de nettoyage
après relecture du client, environnement et contrat : annulation de l'échéancier
ou de l'abonnement, sans facture immédiate ni prorata.

Une réponse perdue avant connaissance de l'ID d'abonnement, ou un nettoyage
impossible, exige un rapprochement administrateur. Il n'existe pas encore de
reprise automatique de ces cas : ne pas réinitialiser le verrou ni créer un
autre contrat pour contourner l'incertitude. Vérifier les objets Stripe, leurs
métadonnées et le journal avant toute intervention.

Validation
La piste d'ancrage a été testée directement dans Stripe TEST avec Test Clock.
L'intégration PHP dev.5 a des tests locaux SQLite/transport simulé ; sa recette
complète depuis WordPress, particulièrement les phases avec reste d'arrondi et
le calendrier annuel, reste à effectuer. Ce document n'atteste pas une version
commerciale validée.

Référence : https://docs.stripe.com/billing/subscriptions/billing-cycle
