HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/ai.naniguide.com/app/Notifications/Admin/RemoteInvoiceFailed.php
<?php

namespace App\Notifications\Admin;

use App\Model\Customer;
use App\Model\Invoice;
use App\Model\PaymentGateway;
use App\Notifications\AppNotification;
use Illuminate\Database\Eloquent\Model;

/**
 * A remote-managed subscription attempted an auto-billing charge and the
 * vendor reported failure (declined / past_due).
 *
 * Severity=warning, category=alert — admin attention recommended:
 *   - Customer's card may have expired / insufficient funds
 *   - Vendor will retry per its own dunning rules (Stripe Smart Retries,
 *     Paddle's payment recovery), but admins may want to email the customer
 *     directly to reduce churn.
 *
 * Group key = remote_invoice_id → re-sync collapses into the same row.
 * Body identifies customer + gateway + amount + currency + failure reason.
 */
class RemoteInvoiceFailed extends AppNotification
{
    public function __construct(
        public Invoice $invoice,
        public Customer $customer,
        public PaymentGateway $gateway,
        public float $amount,
        public string $currency,
        public ?string $failureReason = null,
    ) {}

    public function audience(): string { return self::AUDIENCE_ADMINS; }
    public function category(): string { return self::CATEGORY_ALERT; }
    public function severity(): string { return self::SEVERITY_WARNING; }

    public function groupKey(): string
    {
        return 'remote-invoice-failed:' . ($this->invoice->remote_invoice_id ?: $this->invoice->id);
    }

    public function subject(): ?Model
    {
        return $this->invoice;
    }

    public function toArray(object $notifiable = null): array
    {
        $customerName = $this->customer->displayName() ?? $this->customer->name ?? 'Customer';
        $amountStr    = number_format($this->amount, 2) . ' ' . $this->currency;
        $reasonSuffix = $this->failureReason ? ' Reason: ' . $this->failureReason . '.' : '';

        return [
            'title' => 'Recurring payment failed',
            'body'  => sprintf(
                '%s — %s charge via %s declined.%s Vendor will retry automatically.',
                $customerName,
                $amountStr,
                $this->gateway->name,
                $reasonSuffix
            ),
            'meta' => [
                'remote_invoice_id' => $this->invoice->remote_invoice_id,
                'gateway_id'        => $this->gateway->id,
                'gateway_name'      => $this->gateway->name,
                'gateway_type'      => $this->gateway->type,
                'customer_id'       => $this->customer->id,
                'customer_name'     => $customerName,
                'invoice_uid'       => $this->invoice->uid,
                'amount'            => $this->amount,
                'currency'          => $this->currency,
                'failure_reason'    => $this->failureReason,
            ],
            'action' => [
                'label'  => 'View invoice',
                'route'  => 'refactor.admin.invoices.index',
                'params' => [],
            ],
        ];
    }
}