Laravel SISP 0.7 rend l'état du checkout visible
La release 0.7 transforme Laravel SISP, d'aide au redirect de paiement en infrastructure de checkout dotée de mémoire.
Laravel SISP 0.7 n’est pas une aide au paiement plus grosse. C’est la release où le package commence à traiter le checkout comme une infrastructure.
Cette distinction compte parce que la partie facile de SISP, c’est d’envoyer la demande de paiement. La partie difficile commence après le redirect. Un client paie, le navigateur revient, le callback atterrit, une facture change d’état, un retry peut devoir se produire, un remboursement peut être partiel, et une transaction en attente peut rester au milieu assez longtemps pour rendre tout le monde nerveux.
Un wrapper fin peut cacher ça pour une démo. Un package de production, non.
Les paiements ont besoin de mémoire
La fonctionnalité qui m’importe le plus dans la 0.7 n’est pas la plus visible. Ce sont les logs d’audit de transactions.
Le checkout a trop de transitions pour se fier à la seule valeur finale. Quand une transaction passe d’en attente à complétée, échouée, remboursée, ou repasse par un chemin de récupération, la question utile n’est pas seulement “quel est le statut maintenant ?”. La question utile est “qu’est-ce qui a changé, depuis où, et pourquoi ?”.
La nouvelle action de logging enregistre les attributs modifiés, les anciennes valeurs, les nouvelles valeurs et le contexte source de chaque mise à jour de transaction.
src/Actions/LogTransactionChangesAction.php
$transaction->logs()->create([
'source' => TransactionLogContext::current(),
'changed_attributes' => $changes['changed_attributes'],
'old_values' => $changes['old_values'],
'new_values' => $changes['new_values'],
]);
C’est du petit code avec une grande conséquence. Ça donne au package une mémoire. Quand le support, la finance ou l’ingénierie demande ce qui est arrivé à un paiement, la réponse n’a plus à être reconstruite à partir du flux du controller et de snapshots de base de données.
Les remboursements ne sont pas un booléen
La 0.7 ajoute aussi les remboursements partiels. Cela change la forme du modèle.
Avant ça, un chemin de remboursement pouvait être traité comme une opération terminale : payé devient remboursé. Les remboursements partiels cassent ce raccourci. Une transaction peut rester complétée alors qu’une partie de son solde est déjà revenue au client. Le package doit suivre le solde remboursable, ajouter l’historique des remboursements, et ne marquer la transaction entière comme remboursée que lorsque le solde restant atteint zéro.
src/Actions/RefundTransactionAction.php
$remainingThousandths = $refundableThousandths - $refundThousandths;
TransactionLogContext::run(
'refund',
fn (): bool => $transaction->update([
'status' => $remainingThousandths === 0 ? TransactionStatus::refunded->value : TransactionStatus::completed->value,
'merchant_response' => "{$reason}::{$refundAmount}",
'payload' => $payload,
'refunded_at' => now(),
])
);
Ce compromis rend le package plus lourd. Il le rend aussi plus honnête. Les vrais systèmes de paiement ne vivent pas dans des états binaires propres. Ils vivent dans des soldes, des historiques, des retries et des exceptions.
En attente est un état de production
L’autre mouvement de la 0.7, c’est la réconciliation via la facade.
En attente n’est pas une erreur. C’est un état qui a besoin d’un chemin de récupération. Si le callback échoue, arrive en retard, ou laisse la transaction locale derrière la vérité du fournisseur, l’application a besoin d’un moyen de redemander à SISP et d’appliquer la réponse sans bâtir ce flux à partir de rien.
src/Facades/Sisp.php
* @method static TransactionStatusResponse queryTransactionStatus(Transaction|string $transaction)
* @method static Transaction reconcileTransactionStatus(Transaction $transaction)
L’implémentation garde la règle étroite : seules les transactions en attente sont réconciliées, les appels d’API au statut échoué laissent la transaction inchangée, et les réponses réussies mettent à jour à la fois l’état de la transaction et celui de la facture.
C’est le motif que je veux de ce package. Faire le travail propre à SISP une fois. Exposer une API à la forme de Laravel. Garder le code de l’application concentré sur le flux métier plutôt que sur la plomberie des paiements.
L’objection évidente
L’objection est juste : c’est plus qu’un wrapper. Un wrapper serait plus petit. Il s’installerait plus vite dans ta tête.
Mais le checkout n’est pas une requête unique. C’est une surface opérationnelle. Si le package possède la construction de la requête mais laisse l’historique d’audit, l’état de la facture, les remboursements et la réconciliation éparpillés dans le code de l’application, il a déplacé le travail difficile au lieu de le résoudre.
La ligne 0.7 est publique maintenant aussi. Packagist affiche 661 installations, 15 étoiles GitHub, et la v0.7.0 publiée le 2026-05-31. C’est encore tôt, mais c’est assez d’usage pour justifier de traiter le package comme une infrastructure plutôt qu’un script de week-end.
La ligne à retenir
Un package de checkout n’est pas fini quand le redirect marche. Il est fini quand les états moches ont un endroit où vivre.