fix(discord): skip zero-amount payment stats messages (#540)

## Qué

Una suscripción en periodo de prueba genera una factura
`invoice.payment_succeeded` de **0 €** en Stripe. El listener la
convertía en un mensaje "💰 Payment succeeded" en Discord, duplicando
información con el mensaje de la suscripción y sin aportar datos de pago
útiles.

Ahora, si el importe de la factura es 0, no se envía ningún embed. El
mensaje de la suscripción sigue enviándose de forma independiente.

## Cómo

- `PostStripeEventToDiscord::invoiceEmbed` devuelve `null` cuando el
importe es 0. `handle()` ya corta en `$embed === null`, así que no se
publica nada.
- Aplica tanto a pagos exitosos como fallidos de 0 € (una factura de 0
no aporta info de pago en ningún caso).

## Tests

- Nuevo test `skips a zero-amount payment so only the subscription
message is posted` (`assertNothingSent`).
- Suite completa del listener en verde (10 tests).
This commit is contained in:
Víctor Falcón 2026-06-15 19:21:47 +02:00 committed by GitHub
parent a38ed69d2e
commit 7693e4813f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 18 additions and 2 deletions

View File

@ -153,9 +153,9 @@ class PostStripeEventToDiscord implements ShouldQueue
/**
* @param array<string, mixed> $payload
* @return array<string, mixed>
* @return array<string, mixed>|null
*/
private function invoiceEmbed(string $type, array $payload): array
private function invoiceEmbed(string $type, array $payload): ?array
{
$object = $payload['data']['object'] ?? [];
@ -164,6 +164,10 @@ class PostStripeEventToDiscord implements ShouldQueue
default => ['title' => '💰 Payment succeeded', 'color' => self::COLOR_GREEN, 'amount' => $object['amount_paid'] ?? 0],
};
if ((int) $meta['amount'] === 0) {
return null;
}
$email = $this->stringOrNull($object['customer_email'] ?? null);
$fields = [

View File

@ -79,6 +79,18 @@ test('posts the formatted amount for a succeeded payment', function () {
->contains(fn ($field) => $field['value'] === '€19.99'));
});
test('skips a zero-amount payment so only the subscription message is posted', function () {
Http::fake();
handleStripeWebhook([
'id' => 'evt_zero',
'type' => 'invoice.payment_succeeded',
'data' => ['object' => ['amount_paid' => 0, 'currency' => 'eur', 'customer_email' => 'a@b.com', 'subscription' => 'sub_123']],
]);
Http::assertNothingSent();
});
test('uses amount_due for a failed payment', function () {
Http::fake();