303 lines
12 KiB
PHP
303 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Order;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Stripe\StripeClient;
|
|
use Stripe\Exception\ApiErrorException;
|
|
|
|
class OrderConfirmationController extends Controller
|
|
{
|
|
private ?StripeClient $stripe = null;
|
|
|
|
public function __construct()
|
|
{
|
|
$stripeSecretKey = env('STRIPE_SECRET_KEY');
|
|
if ($stripeSecretKey) {
|
|
$this->stripe = new StripeClient($stripeSecretKey);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Envoyer l'email de confirmation de commande
|
|
* Remplace la fonction Supabase send-order-confirmation-email
|
|
*/
|
|
public function sendConfirmationEmail(Request $request)
|
|
{
|
|
$validator = Validator::make($request->all(), [
|
|
'orderData' => 'required|array',
|
|
'sessionId' => 'nullable|string',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return response()->json([
|
|
'error' => 'Données invalides: ' . $validator->errors()->first()
|
|
], 400);
|
|
}
|
|
|
|
$orderData = $request->input('orderData');
|
|
$sessionId = $request->input('sessionId');
|
|
|
|
// 1. Récupérer l'email vérifié depuis la session Stripe
|
|
$customerEmail = null;
|
|
|
|
if ($sessionId && $this->stripe) {
|
|
try {
|
|
$session = $this->stripe->checkout->sessions->retrieve($sessionId);
|
|
$customerEmail = $session->customer_details->email ?? $session->customer_email ?? null;
|
|
} catch (ApiErrorException $e) {
|
|
\Log::error('Error retrieving Stripe session: ' . $e->getMessage());
|
|
$customerEmail = $orderData['email'] ?? $orderData['customer_email'] ?? null;
|
|
}
|
|
} else {
|
|
$customerEmail = $orderData['email'] ?? $orderData['customer_email'] ?? null;
|
|
}
|
|
|
|
// 2. Enregistrer la commande dans la base de données
|
|
$finalOrderData = [
|
|
...$orderData,
|
|
'customer_email' => $customerEmail,
|
|
'session_id' => $sessionId,
|
|
'status' => 'En attente de traitement',
|
|
];
|
|
|
|
try {
|
|
$order = Order::create($finalOrderData);
|
|
} catch (\Exception $e) {
|
|
\Log::error('Error saving order: ' . $e->getMessage());
|
|
$order = null;
|
|
}
|
|
|
|
// 3. Envoyer l'email client
|
|
$customerEmailResult = null;
|
|
$customerEmailError = null;
|
|
|
|
if ($customerEmail && env('RESEND_API_KEY')) {
|
|
$customerEmailResult = $this->sendCustomerEmail($customerEmail, $orderData, $order);
|
|
if (!$customerEmailResult) {
|
|
$customerEmailError = 'Erreur lors de l\'envoi de l\'email client';
|
|
}
|
|
}
|
|
|
|
// 4. Envoyer l'email admin
|
|
$adminEmailResult = null;
|
|
$adminEmailError = null;
|
|
|
|
if (env('RESEND_API_KEY') && env('ADMIN_EMAIL')) {
|
|
$adminEmailResult = $this->sendAdminEmail($orderData, $order, $sessionId, $customerEmail);
|
|
if (!$adminEmailResult) {
|
|
$adminEmailError = 'Erreur lors de l\'envoi de l\'email admin';
|
|
}
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'orderId' => $order?->id ?? 'N/A',
|
|
'customerEmail' => $customerEmail,
|
|
'emailSent' => !!$customerEmailResult,
|
|
'customerEmailError' => $customerEmailError,
|
|
'adminEmailSent' => !!$adminEmailResult,
|
|
'adminEmailError' => $adminEmailError,
|
|
], 200);
|
|
}
|
|
|
|
private function sendCustomerEmail(string $customerEmail, array $orderData, ?Order $order): bool
|
|
{
|
|
$resendApiKey = env('RESEND_API_KEY');
|
|
if (!$resendApiKey) {
|
|
return false;
|
|
}
|
|
|
|
$orderId = $order?->id ? substr($order->id, 0, 8) : '';
|
|
|
|
$html = $this->getCustomerEmailTemplate($orderData, $orderId);
|
|
|
|
try {
|
|
$response = Http::withHeaders([
|
|
'Authorization' => 'Bearer ' . $resendApiKey,
|
|
'Content-Type' => 'application/json',
|
|
])->post('https://api.resend.com/emails', [
|
|
'from' => 'Dites le en chanson <contact@dites-le-en-chanson.fr>',
|
|
'to' => [$customerEmail],
|
|
'subject' => "Votre commande Dites le en chanson est confirmée ! (ID: {$orderId})",
|
|
'html' => $html,
|
|
]);
|
|
|
|
return $response->successful();
|
|
} catch (\Exception $e) {
|
|
\Log::error('Error sending customer email: ' . $e->getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private function sendAdminEmail(array $orderData, ?Order $order, ?string $sessionId, ?string $customerEmail): bool
|
|
{
|
|
$resendApiKey = env('RESEND_API_KEY');
|
|
$adminEmail = env('ADMIN_EMAIL');
|
|
|
|
if (!$resendApiKey || !$adminEmail) {
|
|
return false;
|
|
}
|
|
|
|
$orderId = $order?->id ?? 'N/A';
|
|
|
|
$html = $this->getAdminEmailTemplate($orderData, $orderId, $sessionId, $customerEmail);
|
|
|
|
try {
|
|
$response = Http::withHeaders([
|
|
'Authorization' => 'Bearer ' . $resendApiKey,
|
|
'Content-Type' => 'application/json',
|
|
])->post('https://api.resend.com/emails', [
|
|
'from' => 'Dites le en chanson <contact@dites-le-en-chanson.fr>',
|
|
'to' => [$adminEmail],
|
|
'subject' => "Nouvelle commande reçue (ID: " . substr($orderId, 0, 8) . ")",
|
|
'html' => $html,
|
|
]);
|
|
|
|
return $response->successful();
|
|
} catch (\Exception $e) {
|
|
\Log::error('Error sending admin email: ' . $e->getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private function getCustomerEmailTemplate(array $orderData, string $orderId): string
|
|
{
|
|
// Pré-calculer les valeurs pour éviter l'utilisation de ?? dans le heredoc
|
|
$recipientName = $orderData['recipient_name'] ?? 'cher client';
|
|
$productName = $orderData['product_name'] ?? 'Chanson personnalisée';
|
|
$priceDisplay = isset($orderData['price']) ? $orderData['price'] . ' €' : '—';
|
|
$recipientNameDisplay = $orderData['recipient_name'] ?? '—';
|
|
$language = $orderData['language'] ?? '—';
|
|
$voiceGender = $orderData['voice_gender'] ?? '—';
|
|
$musicalStyle = $orderData['musical_style'] ?? '—';
|
|
$mood = $orderData['mood'] ?? '—';
|
|
$anecdote1 = isset($orderData['anecdote1']) ? "<p><strong>Anecdote 1:</strong> {$orderData['anecdote1']}</p>" : "";
|
|
$anecdote2 = isset($orderData['anecdote2']) ? "<p><strong>Anecdote 2:</strong> {$orderData['anecdote2']}</p>" : "";
|
|
$anecdote3 = isset($orderData['anecdote3']) ? "<p><strong>Anecdote 3:</strong> {$orderData['anecdote3']}</p>" : "";
|
|
|
|
return <<<HTML
|
|
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Confirmation de votre commande - Dites le en chanson</title>
|
|
<style>
|
|
body { font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin:0; padding:0; background:#f4f4f9; color:#333; }
|
|
.container { max-width:600px; margin:20px auto; background:#fff; border-radius:8px; box-shadow:0 4px 15px rgba(0,0,0,.1); overflow:hidden; }
|
|
.header { background:linear-gradient(135deg,#6B46C1,#9F7AEA); color:#fff; padding:30px 20px; text-align:center; }
|
|
.header img { max-width:100px; margin-bottom:15px; }
|
|
.header h1 { margin:0; font-size:28px; font-weight:600; }
|
|
.content { padding:30px; line-height:1.6; }
|
|
.content h2 { color:#6B46C1; font-size:22px; margin-top:0; }
|
|
.content p { margin-bottom:15px; }
|
|
.order-details { background:#f9fafb; padding:20px; border-radius:6px; margin-bottom:20px; border:1px solid #e5e7eb; }
|
|
.order-details p { margin:5px 0; }
|
|
.order-details strong { color:#555; }
|
|
.delivery-info { background:#eef2ff; padding:15px; border-radius:6px; text-align:center; margin-bottom:25px; border-left:4px solid #6366f1; }
|
|
.delivery-info p { margin:0; color:#4338ca; }
|
|
.button { display:inline-block; background:#6B46C1; color:#fff; padding:12px 25px; text-decoration:none; border-radius:5px; font-size:1em; font-weight:500; }
|
|
.button:hover { background:#553C9A; }
|
|
.footer { text-align:center; padding:20px; font-size:.9em; color:#777; background:#f1f1f1; }
|
|
.footer a { color:#6B46C1; text-decoration:none; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<img src="https://storage.googleapis.com/hostinger-horizons-assets-prod/72f15596-7338-40f3-8565-8548388d2677/4ac040560780878558644b6783d4f976.png" alt="Dites-le en chanson Logo" />
|
|
<h1>Merci pour votre commande !</h1>
|
|
</div>
|
|
<div class="content">
|
|
<h2>Bonjour {$recipientName},</h2>
|
|
<p>Nous sommes ravis de vous confirmer que votre commande a bien été enregistrée. Notre équipe de créateurs est déjà prête à composer votre chanson personnalisée !</p>
|
|
<div class="order-details">
|
|
<h3>Récapitulatif de votre commande (ID: {$orderId}) :</h3>
|
|
<p><strong>Produit:</strong> {$productName}</p>
|
|
<p><strong>Prix Payé:</strong> {$priceDisplay}</p>
|
|
<p><strong>Pour:</strong> {$recipientNameDisplay}</p>
|
|
<p><strong>Langue:</strong> {$language}</p>
|
|
<p><strong>Voix:</strong> {$voiceGender}</p>
|
|
<p><strong>Style:</strong> {$musicalStyle}</p>
|
|
<p><strong>Ambiance:</strong> {$mood}</p>
|
|
{$anecdote1}
|
|
{$anecdote2}
|
|
{$anecdote3}
|
|
</div>
|
|
<div class="delivery-info">
|
|
<p><strong>Délai de création :</strong> Votre chanson unique sera prête et vous sera livrée par email dans les <strong>48 heures</strong>.</p>
|
|
</div>
|
|
<p>Nous mettons tout notre cœur pour transformer vos histoires en mélodies inoubliables.</p>
|
|
<p>Si vous avez la moindre question, n'hésitez pas à nous contacter.</p>
|
|
<p style="text-align:center; margin-top:30px;">
|
|
<a href="https://dites-le-en-chanson.fr" class="button">Visiter notre site</a>
|
|
</p>
|
|
</div>
|
|
<div class="footer">
|
|
<p>© " . date('Y') . " <a href="https://dites-le-en-chanson.fr">Dites-le en chanson</a>. Tous droits réservés.</p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
HTML;
|
|
}
|
|
|
|
private function getAdminEmailTemplate(array $orderData, string $orderId, ?string $sessionId, ?string $customerEmail): string
|
|
{
|
|
$sessionIdDisplay = $sessionId ?? 'N/A';
|
|
$customerEmailDisplay = $customerEmail ?? 'N/A';
|
|
|
|
// Pré-calculer les valeurs pour éviter l'utilisation de ?? dans le heredoc
|
|
$recipientName = $orderData['recipient_name'] ?? 'Non spécifié';
|
|
$songForWhom = $orderData['song_for_whom'] ?? 'Non spécifié';
|
|
$occasion = $orderData['occasion'] ?? 'Non spécifié';
|
|
$language = $orderData['language'] ?? 'Non spécifié';
|
|
$anecdote1 = $orderData['anecdote1'] ?? 'Non spécifié';
|
|
$anecdote2 = $orderData['anecdote2'] ?? 'Non spécifié';
|
|
$anecdote3 = $orderData['anecdote3'] ?? 'Non spécifié';
|
|
$voiceGender = $orderData['voice_gender'] ?? 'Non spécifié';
|
|
$musicalStyle = $orderData['musical_style'] ?? 'Non spécifié';
|
|
$mood = $orderData['mood'] ?? 'Non spécifié';
|
|
$price = $orderData['price'] ?? 'Non spécifié';
|
|
$productName = $orderData['product_name'] ?? 'Non spécifié';
|
|
|
|
return <<<HTML
|
|
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Nouvelle Commande Reçue</title>
|
|
</head>
|
|
<body style="font-family: Arial, sans-serif; color:#333;">
|
|
<h1>Nouvelle Commande Reçue !</h1>
|
|
<p>Une nouvelle commande a été passée sur votre site.</p>
|
|
<p><strong>ID de Commande :</strong> {$orderId}</p>
|
|
<p><strong>ID de Session Stripe :</strong> {$sessionIdDisplay}</p>
|
|
<p><strong>Email du Client :</strong> {$customerEmailDisplay}</p>
|
|
<p><strong>Statut :</strong> En attente de traitement</p>
|
|
<h2>Détails de la commande :</h2>
|
|
<ul>
|
|
<li><strong>Recipient Name:</strong> {$recipientName}</li>
|
|
<li><strong>Song For Whom:</strong> {$songForWhom}</li>
|
|
<li><strong>Occasion:</strong> {$occasion}</li>
|
|
<li><strong>Language:</strong> {$language}</li>
|
|
<li><strong>Anecdote1:</strong> {$anecdote1}</li>
|
|
<li><strong>Anecdote2:</strong> {$anecdote2}</li>
|
|
<li><strong>Anecdote3:</strong> {$anecdote3}</li>
|
|
<li><strong>Voice Gender:</strong> {$voiceGender}</li>
|
|
<li><strong>Musical Style:</strong> {$musicalStyle}</li>
|
|
<li><strong>Mood:</strong> {$mood}</li>
|
|
<li><strong>Price:</strong> {$price}</li>
|
|
<li><strong>Product Name:</strong> {$productName}</li>
|
|
</ul>
|
|
</body>
|
|
</html>
|
|
HTML;
|
|
}
|
|
}
|