diff --git a/app/Mail/AlertePaiementAnnule.php b/app/Mail/AlertePaiementAnnule.php
new file mode 100644
index 00000000..4772be88
--- /dev/null
+++ b/app/Mail/AlertePaiementAnnule.php
@@ -0,0 +1,51 @@
+numero_commande = $order->ref;
+ $this->date_commande = $order->created_at->format('d/m/Y H:i');
+ $this->montant = number_format($order->total_shipped, 2, ',', ' ').' €';
+ $this->client_nom = $order->customer
+ ? $order->customer->last_name.' '.$order->customer->first_name
+ : 'Client supprimé';
+ $this->client_email = $order->customer->email ?? 'inconnu';
+ $this->reference_paiement = $reference;
+ }
+
+ public function envelope()
+ {
+ return new Envelope(
+ from: new Address('boutique@jardinenvie.com', 'Jardin\'en\'Vie'),
+ subject: $this->subject,
+ );
+ }
+}
diff --git a/app/Repositories/Shop/OrderMails.php b/app/Repositories/Shop/OrderMails.php
index 869664c4..f87935e8 100644
--- a/app/Repositories/Shop/OrderMails.php
+++ b/app/Repositories/Shop/OrderMails.php
@@ -3,9 +3,11 @@
namespace App\Repositories\Shop;
use App\Mail\Acheminement;
+use App\Mail\AlertePaiementAnnule;
use App\Mail\ConfirmationCommande;
use App\Mail\Preparation;
use Illuminate\Support\Facades\Mail;
+use Illuminate\Support\Facades\Log;
class OrderMails
{
@@ -37,4 +39,25 @@ class OrderMails
return Mail::to($order->customer->email)->send($mail);
}
+
+ public static function sendCancelledOrderPaymentAlert($orderId, $reference)
+ {
+ $order = Orders::get($orderId, ['customer']);
+
+ try {
+ Mail::to('commande@jardinenvie.com')
+ ->send(new AlertePaiementAnnule($order, $reference));
+ Log::info('Cancelled order payment alert sent', [
+ 'order_id' => $orderId,
+ 'order_ref' => $order->ref,
+ 'reference' => $reference,
+ ]);
+ } catch (\Throwable $e) {
+ Log::error('Failed to send cancelled order payment alert', [
+ 'order_id' => $orderId,
+ 'order_ref' => $order->ref,
+ 'exception' => $e->getMessage(),
+ ]);
+ }
+ }
}
diff --git a/app/Repositories/Shop/Paybox.php b/app/Repositories/Shop/Paybox.php
index 6ca3195f..63b37365 100644
--- a/app/Repositories/Shop/Paybox.php
+++ b/app/Repositories/Shop/Paybox.php
@@ -104,7 +104,9 @@ class Paybox
return true;
}
- DB::transaction(function () use ($invoice, $order, $reference, $payload, $existingPayment, &$shouldNotify) {
+ $isCancelled = (int) $order->status === 4;
+
+ DB::transaction(function () use ($invoice, $order, $reference, $payload, $existingPayment, &$shouldNotify, $isCancelled) {
$attributes = [
'payment_type' => 1,
'amount' => $invoice->total_shipped,
@@ -134,14 +136,24 @@ class Paybox
Invoices::checkPayments($invoice->id);
- $paidStatus = Orders::getStatusByName('Préparation');
- if ($paidStatus !== '' && (int) $order->status !== (int) $paidStatus) {
- $order->status = $paidStatus;
- $order->save();
+ if (! $isCancelled) {
+ $paidStatus = Orders::getStatusByName('Préparation');
+ if ($paidStatus !== '' && (int) $order->status !== (int) $paidStatus) {
+ $order->status = $paidStatus;
+ $order->save();
+ }
}
});
- if ($shouldNotify) {
+ if ($isCancelled && $shouldNotify) {
+ Log::warning('Paybox payment received on cancelled order', [
+ 'order_id' => $order->id,
+ 'order_ref' => $order->ref,
+ 'invoice_id' => $invoice->id,
+ 'reference' => $reference,
+ ]);
+ OrderMails::sendCancelledOrderPaymentAlert($order->id, $reference);
+ } elseif ($shouldNotify) {
try {
OrderMails::sendOrderConfirmed($order->id);
} catch (\Throwable $exception) {
diff --git a/database/migrations/shop/2026_02_20_120000_insert_mail_template_alerte_paiement_annule.php b/database/migrations/shop/2026_02_20_120000_insert_mail_template_alerte_paiement_annule.php
new file mode 100644
index 00000000..aa88577d
--- /dev/null
+++ b/database/migrations/shop/2026_02_20_120000_insert_mail_template_alerte_paiement_annule.php
@@ -0,0 +1,86 @@
+insert([
+ 'mailable' => 'App\\Mail\\AlertePaiementAnnule',
+ 'subject' => json_encode(['fr' => '[URGENT] Paiement reçu sur commande annulée {{numero_commande}}'], JSON_UNESCAPED_UNICODE),
+ 'html_template' => json_encode(['fr' => $this->getHtmlTemplate()], JSON_UNESCAPED_UNICODE),
+ 'text_template' => json_encode(['fr' => $this->getTextTemplate()], JSON_UNESCAPED_UNICODE),
+ 'created_at' => now(),
+ 'updated_at' => now(),
+ ]);
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ DB::table('mail_templates')
+ ->where('mailable', 'App\\Mail\\AlertePaiementAnnule')
+ ->delete();
+ }
+
+ private function getHtmlTemplate(): string
+ {
+ return '
'
+ .''
+ .''
+ .''
+ .''
+ .''
+ .' | '
+ .' '
+ .''
+ .''
+ .''
+ .''
+ .'| '
+ .'⚠ Paiement sur commande annulée | '
+ .'| '
+ .' Un paiement Paybox a été reçu sur une commande annulée. '
+ .'Un remboursement est probablement nécessaire. '
+ .''
+ .'| Commande : | {{numero_commande}} | '
+ .'| Date : | {{date_commande}} | '
+ .'| Montant : | {{montant}} | '
+ .'| Client : | {{client_nom}} | '
+ .'| Email : | {{client_email}} | '
+ .'| Réf. paiement : | {{reference_paiement}} | '
+ .' '
+ .'Veuillez procéder au remboursement du client dans les plus brefs délais. '
+ .' | '
+ .' '
+ .' | '
+ .''
+ .''
+ .'Jardin\'enVie Artisan Semencier 429 route des chaux, 26500 Bourg les Valence - Drôme'
+ .' | '
+ .' |
';
+ }
+
+ private function getTextTemplate(): string
+ {
+ return "⚠ PAIEMENT SUR COMMANDE ANNULÉE\n\n"
+ ."Un paiement Paybox a été reçu sur une commande annulée.\n"
+ ."Un remboursement est probablement nécessaire.\n\n"
+ ."Commande : {{numero_commande}}\n"
+ ."Date : {{date_commande}}\n"
+ ."Montant : {{montant}}\n"
+ ."Client : {{client_nom}}\n"
+ ."Email : {{client_email}}\n"
+ ."Réf. paiement : {{reference_paiement}}\n\n"
+ ."Veuillez procéder au remboursement du client dans les plus brefs délais.\n\n"
+ ."Jardin'enVie Artisan Semencier\n"
+ .'429 route des chaux, 26500 Bourg les Valence - Drôme';
+ }
+};