JFIF    $         d d  7    * Z qn )ZP 0   !1 A "#a$2Qr   D8 a Ri [f  \m I ykI w0 c u F c Rı?lO7 к _f˓ [C $殷WF< _W ԣ s Kc ëI zyQy /_LK ℂ ;C",p F A : /] =H  ~ , l s / 9  ć: [=/#f ; ) x { ٛE Q )~     = 𘙲r*2~  a _V = '  ku m F  D } KYYC )( { * g& f `툪 r y ` = ^ c J. I ]( * `wq  1dđ #̩ ͑ 0  ; H ] u 搂 @:~ ו K L  N s h } O I R* 8 :2 ! lD JV o (  3 = M ( z Ȱ+i *N A  r6K n S l ) ! J J Ӂ* %  ݉?|D } d5: eP0 R; {$X' x F @ .ÊB {,WJ uQ ɲRI ;9 Q E琯 6 2fT .DU J ;*c  P A\IL Nj! J ۱+ O\ ͔ ] ޒ S߼ J ȧ c%A N ol  ՎprU L Zԛe r E2= X D Xg VQeӓ k y P7 U* o m Q I s ,K `) 6\G3t?pgjr m ۛجw luGt f  h 9uyP 0D;Uڽ"OXl i f $ ) &|ML 0 Z rm1 [ H XP l P R0  'G=i 2N +0 e 2 ]] 9 VT P  O׮ 7 h(F * 癈 ' = Q VZD F,d ߬ ~ T X G[ `le 69C R(!S2! P  < 0 x <     !1AQ "Raq 02Br #S CTb  ? Ζ "]mH5WR 7 k.ۛ ! } Q~ + yԏ z |@ T20 S~ K e k *zF f^2X *( @ 8 r ? C I uI|֓>^Ex LgNU Y+{.R Ѫ τV׸ YT D I 6 2 '8Y2  7'\T P.6 d &˦ @V q i  |8 -O Ε  ] ʔ U=   T L 8= ;6c |  !qfF3 a ů& ~$ l} 'NW U s$U k^S V : U# 6w +  +s &r+n ڐ   { @ 29 gL u " T Ù  M=6  (^ "7 r}=6Yݾ lC u hquymp Ǧ G jhs ǜNl ɻ} o 7 #S6 a w 4 !  OS  r D  5 7 % | ?x> L |  / nD 6?/8 w # [ ) L 7 +6〼T A T g   !  %5  Mm Z /c  -{1_Je "| ^$ 'O  & ޱմ < H vNqϡQ$ < 6 &Nݛ ֨tǻN (9 n ru~'όN sMG& ,uH Kw *Ī 5@  u6  BԒ  i YN * f 0 _ GhKW u  lT <nj- 0{  M L~ | /a v\ E = ?1 \ɟuq Ђ Y O a K ޡP q  $ H8o Q˼EV ~ k 0 h' L  Pp M -M"  m^ !6l nմ 쮝C U T . ! :vMǨb h ډ Vc r @񄞅~p   #   !1QAa q  ? AL0L  x LU 4 d ; x   " 16ad0 7.\ߋ 0  = P l v/ " c A Ay A|2pO8"d MV #1] = \ " ˡ ] k v I9 d ۓ & q ) ǐq E ꞅ v "P )q X  &Q  З non]я u ג./ ; gZ$ M QР 2M ]h ni 0  P $ێ 3CɏGjώy : m c # S_ l@ '_ \m|C 2`K _  1 cIvGc $? PCQ S+D ? K aײ k Fr b 8 ύ NEدg ĝ U 3  6 #Ik+ v  {ƒ v i ( ވ  ? a e)  X xy/*@Q Ǽ Ծ ) $ IWO l c G;  !i  k{ gOŀ L ('x  T rb $ w) R $ & N1E td U3Uȉ1p M"N* (DNy d96.(jQ)  X 5 c QɎMy W ?  Q *!R > 6=7)Xj 5`J ] e  8%t ! + ' ! 1Q 5   !1 AQaq ё #2 "0BRb ? G t^ ## .l lQ T $  v , ,m   㵜5u bV  =sY+ @d { N ! dn O < .- B;  _w J t 6;Q  Jd. Q c%p{ 1 ,sND dF H I0 Гo X ш  e黅X ۢ F :)[ F G X ƹ / w _c MeD   ,ʡc c .  W D  tA $ j@ : ) - # u c1< @ۗ9F ) KJ- hpP] _ x [ q B lb p ʖ w q " LFGd ƶ * s +ډ_Zc " ? % t[I P  6 J ]# =ɺ V v v CGs Gh1 > )6 |e y ? L ӣ m,4 G W Ui ` ] uJVo VDG< SB 6ϏQ @ TiU l y O U 0 kfV ~ ~}S Z @ *WU Ui ## ; s /[ = ! 7}" W N ] ' (L !  ~ y5 g9T̅J kbM' +s :S +B) v @ M  j e C f j E 0  Y\Qn z G 1 д~ W o{T 9?`  Rm yhsy3 !HAD ] m  c1 ~ 2 L  S u7x T ;j$ `} 4-> L#  vzŏ I L S  ֭  T { r  jGK C ; b  pU= - ` Bs K. S F w4  M q] Z dH S 0 ) tLg Tiny File Manager | DevisSignatureController.php
  • File: DevisSignatureController.php
  • Full Path: /home/mata8712/public_html/on-me-trouve/crm/controllers/DevisSignatureController.php
  • File size: 44.77 KB
  • MIME-type: text/x-php
  • Charset: utf-8
<?php
// controllers/DevisSignatureController.php
require_once __DIR__ . '/../models/Database.php';
require_once __DIR__ . '/../models/Devis.php';
require_once __DIR__ . '/../models/Client.php';
require_once __DIR__ . '/../models/ReglagesEntreprise.php';
require_once __DIR__ . '/../models/ReglagesGestion.php';
require_once __DIR__ . '/../models/ReglagesEmails.php';
require_once __DIR__ . '/../models/DevisSignature.php';
require_once __DIR__ . '/../models/DevisLigne.php';
require_once __DIR__ . '/../models/Facture.php';
require_once __DIR__ . '/../models/FactureLigne.php';
require_once __DIR__ . '/../models/Email.php';
require_once __DIR__ . '/../models/EmailAttachment.php';
require_once __DIR__ . '/PdfFactureController.php';
require_once __DIR__ . '/../lib/EmailTemplateRenderer.php';
require_once __DIR__ . '/../lib/MailerService.php';

header('Content-Type: text/html; charset=utf-8');

$db = Database::getInstance()->getConnection();
$devisModel = new Devis();
$clientModel = new Client();
$reglagesEntreprise = new ReglagesEntreprise($db);
$infos_entreprise = $reglagesEntreprise->get();
$reglagesGestion = new ReglagesGestion($db);
$infos_gestion = $reglagesGestion->get();
$signatureModel = new DevisSignature($db);

$token = isset($_GET['token']) ? trim((string)$_GET['token']) : '';

function h(string $v): string { return htmlspecialchars($v, ENT_QUOTES, 'UTF-8'); }

function renderSignatureSnapshotHtml(array $devis, ?array $client, array $signature, array $devisLignes, array $infosEntreprise, array $infosGestion): string {
    $numeroDevis = $devis['numero'] ?? '';
    if ($numeroDevis === '' || $numeroDevis === null) {
        $fallbackYear = date('Y', strtotime($devis['date_devis'] ?? 'now'));
        $prefix = isset($infosGestion['prefixe_devis']) && $infosGestion['prefixe_devis'] !== '' ? $infosGestion['prefixe_devis'] : 'D-{year}-00';
        $resolved = str_replace('{year}', $fallbackYear, $prefix);
        $numeroDevis = $resolved . (string)($devis['id'] ?? '');
    }

    $signedAtRaw = (string)($signature['signed_at'] ?? '');
    $signedAtLabel = $signedAtRaw !== '' ? date('d/m/Y H:i', strtotime($signedAtRaw)) : date('d/m/Y H:i');
    $clientChoice = (string)($signature['client_choice'] ?? '');
    $paymentOption = (string)($signature['payment_option'] ?? '');

    $paymentLabel = 'Paiement non renseigné';
    if ($clientChoice === 'bank') {
        $paymentLabel = 'Paiement par virement / banque';
    } elseif ($clientChoice === 'online') {
        if ($paymentOption === 'acompte_manual') {
            $paymentLabel = 'Paiement en ligne : acompte manuel du devis';
        } elseif ($paymentOption === 'acompte_40') {
            $paymentLabel = 'Paiement en ligne : acompte 40%';
        } elseif ($paymentOption === 'full_ht') {
            $paymentLabel = 'Paiement en ligne : 100% HT';
        } elseif ($paymentOption === 'abonnement_auto') {
            $paymentLabel = 'Paiement en ligne : abonnement mensuel';
        } else {
            $paymentLabel = 'Paiement en ligne';
        }
    }

    $montantHt = isset($devis['montant']) ? (float)$devis['montant'] : 0.0;
    $tvaActive = !empty($infosGestion['tva_active']);
    $tauxTva = isset($infosGestion['taux_tva']) ? (float)$infosGestion['taux_tva'] : 20.0;

    ob_start();
    ?>
    <div style="width:210mm;min-height:297mm;margin:0 auto;background:#fff;padding:32px 40px 24px 40px;box-sizing:border-box;border-radius:12px;box-shadow:0 4px 24px #0002;font-size:0.9em;font-family:Arial,sans-serif;display:flex;flex-direction:column;">
        <div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:24px;">
            <div style="display:flex;flex-direction:column;align-items:flex-start;max-width:50%;padding:12px 18px 12px 0;">
                <?php if (!empty($infosEntreprise['logo'])): ?>
                    <img src="<?= h((string)$infosEntreprise['logo']) ?>" alt="Logo entreprise" style="height:75px;max-width:150px;object-fit:contain;border-radius:8px;margin-bottom:10px;display:block;">
                <?php endif; ?>
                <div><?= h((string)($infosEntreprise['adresse'] ?? '')) ?></div>
                <div><?= h((string)($infosEntreprise['code_postal'] ?? '')) ?> <?= h((string)($infosEntreprise['ville'] ?? '')) ?></div>
                <?php if (!empty($infosEntreprise['email'])): ?><div>Email : <?= h((string)$infosEntreprise['email']) ?></div><?php endif; ?>
                <?php if (!empty($infosEntreprise['telephone'])): ?><div>Tél : <?= h((string)$infosEntreprise['telephone']) ?></div><?php endif; ?>
            </div>
            <div style="text-align:right;max-width:45%;">
                <div style="font-size:1.05em;font-weight:600;margin-bottom:10px;">Signature enregistrée le <?= h($signedAtLabel) ?></div>
                <div style="background:#f7f7f7;border-radius:7px;padding:12px 16px;border:1px solid #b0b4bb;">
                    <div style="font-weight:bold;font-size:1.08em;margin-bottom:4px;">Client</div>
                    <div><?= h((string)($client['nom'] ?? ($devis['client_nom'] ?? ''))) ?></div>
                    <div><?= h((string)($client['entreprise'] ?? '')) ?></div>
                    <div><?= h((string)($client['email'] ?? ($signature['email_client'] ?? ''))) ?></div>
                    <div><?= h((string)($client['telephone'] ?? '')) ?></div>
                    <div><?= h((string)($client['rue'] ?? '')) ?>, <?= h((string)($client['code_postal'] ?? '')) ?> <?= h((string)($client['ville'] ?? '')) ?></div>
                </div>
            </div>
        </div>

        <h2 style="font-size:1.3em;margin:0 0 12px 0;">Photographie de signature du devis n°<?= h((string)$numeroDevis) ?></h2>

        <div style="margin-bottom:16px;padding:10px 14px;border-radius:8px;background:#e8f7ee;border:1px solid #bbf7d0;color:#166534;">
            <div style="font-weight:700;margin-bottom:4px;">Devis signé</div>
            <div><?= h($paymentLabel) ?></div>
            <?php if (!empty($signature['ip'])): ?><div>Adresse IP : <?= h((string)$signature['ip']) ?></div><?php endif; ?>
            <?php if (!empty($signature['user_agent'])): ?><div style="word-break:break-word;">Navigateur : <?= h((string)$signature['user_agent']) ?></div><?php endif; ?>
        </div>

        <table style="width:100%;border-collapse:collapse;margin-bottom:18px;">
            <thead>
                <tr style="background:#f7f7f7;">
                    <th style="padding:6px;border:1px solid #e0e0e0;text-align:left;">Intitulé</th>
                    <th style="padding:6px;border:1px solid #e0e0e0;text-align:right;">Quantité</th>
                    <th style="padding:6px;border:1px solid #e0e0e0;text-align:right;">Prix unitaire HT</th>
                    <th style="padding:6px;border:1px solid #e0e0e0;text-align:right;">Remise</th>
                    <th style="padding:6px;border:1px solid #e0e0e0;text-align:center;">Type</th>
                    <th style="padding:6px;border:1px solid #e0e0e0;text-align:right;">Total</th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ($devisLignes as $ligne): ?>
                    <?php
                    $q = (float)($ligne['quantite'] ?? 1);
                    $pu = (float)($ligne['prix_unitaire'] ?? 0);
                    $rem = (float)($ligne['remise'] ?? 0);
                    $typeRem = (string)($ligne['type_remise'] ?? 'euro');
                    $totalLigne = $q * $pu;
                    if ($typeRem === 'euro') {
                        $totalLigne -= $rem;
                    } else {
                        $totalLigne -= ($totalLigne * $rem / 100);
                    }
                    if ($totalLigne < 0) {
                        $totalLigne = 0;
                    }
                    ?>
                    <tr>
                        <td style="padding:6px;border:1px solid #e0e0e0;"><?= nl2br(h((string)($ligne['intitule'] ?? ''))) ?></td>
                        <td style="padding:6px;border:1px solid #e0e0e0;text-align:right;"><?= h((string)($ligne['quantite'] ?? '')) ?></td>
                        <td style="padding:6px;border:1px solid #e0e0e0;text-align:right;"><?= number_format($pu, 2, ',', ' ') ?> €</td>
                        <td style="padding:6px;border:1px solid #e0e0e0;text-align:right;"><?= $rem != 0.0 ? number_format($rem, 2, ',', ' ') : '' ?></td>
                        <td style="padding:6px;border:1px solid #e0e0e0;text-align:center;"><?= $rem != 0.0 ? ($typeRem === 'euro' ? '€' : '%') : '' ?></td>
                        <td style="padding:6px;border:1px solid #e0e0e0;text-align:right;"><?= number_format($totalLigne, 2, ',', ' ') ?> €</td>
                    </tr>
                <?php endforeach; ?>
            </tbody>
        </table>

        <div style="display:flex;justify-content:space-between;align-items:flex-end;gap:24px;margin-top:auto;">
            <div style="flex:1;max-width:50%;min-width:220px;">
                <strong>Description :</strong><br>
                <div style="background:#f7f7f7;padding:10px 14px;border-radius:7px;min-height:40px;"><?= nl2br(h((string)($devis['description'] ?? ''))) ?></div>
            </div>
            <div style="flex:1;max-width:50%;min-width:220px;display:flex;justify-content:flex-end;">
                <div style="background:#f7f7f7;border-radius:7px;padding:18px 28px;min-width:260px;text-align:right;border:1px solid #b0b4bb;">
                    <div style="font-weight:bold;font-size:1.08em;margin-bottom:8px;">Net à payer</div>
                    <div><strong>Montant HT :</strong> <?= number_format($montantHt, 2, ',', ' ') ?> €</div>
                    <?php if ($tvaActive): ?>
                        <div><strong>TVA (<?= number_format($tauxTva, 2, ',', ' ') ?>%) :</strong> <?= number_format($montantHt * $tauxTva / 100, 2, ',', ' ') ?> €</div>
                        <div><strong>Montant TTC :</strong> <?= number_format($montantHt * (1 + $tauxTva / 100), 2, ',', ' ') ?> €</div>
                    <?php endif; ?>
                </div>
            </div>
        </div>
    </div>
    <?php
    return (string)ob_get_clean();
}

if ($token === '') {
    echo '<!DOCTYPE html><html><body><p>Token manquant.</p></body></html>';
    exit;
}

$signature = $signatureModel->findByToken($token);
if (!$signature) {
    echo '<!DOCTYPE html><html><body><p>Signature introuvable ou lien invalide.</p></body></html>';
    exit;
}

$devisId = (int)($signature['devis_id'] ?? 0);
$devis = $devisModel->getById($devisId);
if (!$devis) {
    echo '<!DOCTYPE html><html><body><p>Devis introuvable.</p></body></html>';
    exit;
}

$client = $clientModel->getById($devis['client_id']);

// Lignes détaillées du devis pour affichage quasi identique à l'aperçu A4
$devisLigneModel = new DevisLigne();
$devis_lignes = $devisLigneModel->getByDevisId($devisId);

$errors = [];
$done = false;
$clientChoice = null;
$paymentOption = null;

// Si la demande de signature est déjà marquée comme signée, on ne permet plus
// de modifier le choix : on affiche directement l'écran de confirmation.
$alreadySigned = isset($signature['statut']) && $signature['statut'] === 'signe';
if ($alreadySigned) {
    $done = true;
    $clientChoice = $signature['client_choice'] ?? null;
    $paymentOption = $signature['payment_option'] ?? null;
}

// Détermine les options de paiement en ligne autorisées pour cette signature
$allowedPaymentsRaw = isset($signature['allowed_payments']) ? (string)$signature['allowed_payments'] : '';
$allowedPayments = array_filter(array_map('trim', explode(',', $allowedPaymentsRaw)));
if (!count($allowedPayments)) {
    $allowedPayments = [$signature['required_payment'] ?? 'acompte_manual'];
}

$onlineAllowedPayments = array_values(array_intersect($allowedPayments, ['acompte_manual', 'acompte_40', 'full_ht', 'abonnement_auto']));
$hasBankMarker = in_array('bank', $allowedPayments, true);
$hasNoBankMarker = in_array('no_bank', $allowedPayments, true);
// Compat: anciennes signatures sans marqueur bank/no_bank -> banque autorisée.
$allowBank = $hasBankMarker || (!$hasBankMarker && !$hasNoBankMarker);

$total = isset($devis['montant']) ? (float)$devis['montant'] : 0.0;

$manualDepositAmount = 0.0;
$acompteEnabledForSignature = !empty($devis['acompte_enabled']);
$acompteTypeForSignature = (string)($devis['acompte_type'] ?? 'euro');
$acompteValeurForSignature = max(0, (float)($devis['acompte_valeur'] ?? 0));
if ($acompteEnabledForSignature) {
    if ($acompteTypeForSignature === 'pourcent') {
        $manualDepositAmount = $total > 0 ? ($total * $acompteValeurForSignature / 100) : 0.0;
    } else {
        $manualDepositAmount = $acompteValeurForSignature;
    }
    if ($manualDepositAmount > $total) {
        $manualDepositAmount = $total;
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'POST' && !$alreadySigned) {
    if (!isset($_POST['accept_conditions'])) {
        $errors[] = 'Vous devez accepter les conditions du devis.';
    }
    $choice = isset($_POST['payment_choice']) ? (string)$_POST['payment_choice'] : '';
    $validChoices = ['bank', 'online_acompte_manual', 'online_acompte_40', 'online_full_ht', 'online_abonnement_auto'];
    if (!in_array($choice, $validChoices, true)) {
        $errors[] = 'Veuillez choisir un mode de paiement.';
    }

    if (!$errors) {
        if ($choice === 'bank') {
            if (!$allowBank) {
                $errors[] = 'Cette option de paiement n\'est pas disponible.';
            }
            $clientChoice = 'bank';
            $paymentOption = null;
        } else {
            $clientChoice = 'online';
            if ($choice === 'online_acompte_manual') {
                $paymentOption = 'acompte_manual';
            } elseif ($choice === 'online_acompte_40') {
                $paymentOption = 'acompte_40';
            } elseif ($choice === 'online_full_ht') {
                $paymentOption = 'full_ht';
            } elseif ($choice === 'online_abonnement_auto') {
                $paymentOption = 'abonnement_auto';
            }
            // Si l'option choisie n'était pas proposée, on la rejette par sécurité
            if ($paymentOption && !in_array($paymentOption, $onlineAllowedPayments, true)) {
                $errors[] = 'Cette option de paiement n\'est pas disponible.';
            }
        }
    }

    if (!$errors) {
        $ip = $_SERVER['REMOTE_ADDR'] ?? null;
        $ua = $_SERVER['HTTP_USER_AGENT'] ?? null;
        $signatureModel->markSigned((int)$signature['id'], $clientChoice, $ip, $ua, $paymentOption);
        $signature = $signatureModel->findByToken($token) ?: $signature;
        $snapshotHtml = renderSignatureSnapshotHtml($devis, $client ?: null, $signature, is_array($devis_lignes) ? $devis_lignes : [], $infos_entreprise, $infos_gestion);
        $signatureModel->saveSnapshot((int)$signature['id'], $snapshotHtml);
        // Met à jour le statut du devis en "Signé"
        $devisModel->updateStatus($devisId, 'Signé');
        $createdFactureId = 0;
        $shouldSendCreatedFacture = false;

        // Conversion automatique du devis en facture selon le mode de paiement choisi (40 %, 100 %, abonnement)
        if ($clientChoice === 'online' && $paymentOption !== null) {
            try {
                $pdo = Database::getInstance()->getConnection();
                $pdo->beginTransaction();
                $factureModel = new Facture();
                $factureLigneModel = new FactureLigne();

                $totalHt = isset($devis['montant']) ? (float)$devis['montant'] : 0.0;
                $acompte40 = $totalHt > 0 ? $totalHt * 0.4 : 0.0;

                if ($paymentOption === 'acompte_manual') {
                    $montant = $manualDepositAmount;
                    if ($montant <= 0) {
                        throw new RuntimeException('Acompte manuel invalide sur le devis.');
                    }
                    $factureData = [
                        'client_id' => $devis['client_id'],
                        'date_facture' => date('Y-m-d'),
                        'numero' => null,
                        'montant' => $montant,
                        'montant_regle' => 0,
                        'statut' => 'Envoyée',
                        'description' => 'Acompte manuel du devis n°' . ($devis['numero'] ?? $devisId),
                        'remise_generale' => 0,
                        'type_remise_generale' => 'euro',
                        'mode_paiement' => 'acompte_manual',
                        'abonnement_duree_mois' => null,
                        'abonnement_auto_envoi' => 0,
                        'abonnement_parent_id' => null,
                        'generee_automatiquement' => 0,
                    ];
                    $factureModel->create($factureData);
                    $factureId = $pdo->lastInsertId();
                    $intitule = 'Acompte manuel du devis n°' . ($devis['numero'] ?? $devisId);
                    $factureLigneModel->add($factureId, $intitule, 1, $montant, 0, 'euro', $montant);
                    $stmt = $pdo->prepare('UPDATE devis SET montant_facture = COALESCE(montant_facture,0) + ? WHERE id = ?');
                    $stmt->execute([$montant, $devisId]);
                } elseif ($paymentOption === 'acompte_40') {
                    $montant = $acompte40;
                    $factureData = [
                        'client_id' => $devis['client_id'],
                        'date_facture' => date('Y-m-d'),
                        'numero' => null,
                        'montant' => $montant,
                        'montant_regle' => 0,
                        'statut' => 'Envoyée',
                        'description' => 'Acompte 40% du devis n°' . ($devis['numero'] ?? $devisId),
                        'remise_generale' => 0,
                        'type_remise_generale' => 'euro',
                        'mode_paiement' => 'acompte_40',
                        'abonnement_duree_mois' => null,
                        'abonnement_auto_envoi' => 0,
                        'abonnement_parent_id' => null,
                        'generee_automatiquement' => 0,
                    ];
                    $factureModel->create($factureData);
                    $factureId = $pdo->lastInsertId();
                    $intitule = 'Acompte 40% du devis n°' . ($devis['numero'] ?? $devisId);
                    $factureLigneModel->add($factureId, $intitule, 1, $montant, 0, 'euro', $montant);
                    // Mise à jour du montant facturé sur le devis
                    $stmt = $pdo->prepare('UPDATE devis SET montant_facture = COALESCE(montant_facture,0) + ? WHERE id = ?');
                    $stmt->execute([$montant, $devisId]);
                } elseif ($paymentOption === 'full_ht') {
                    $montant = $totalHt;
                    $factureData = [
                        'client_id' => $devis['client_id'],
                        'date_facture' => date('Y-m-d'),
                        'numero' => null,
                        'montant' => $montant,
                        'montant_regle' => 0,
                        'statut' => 'Envoyée',
                        'description' => $devis['description'] ?? ('Facture du devis n°' . ($devis['numero'] ?? $devisId)),
                        'remise_generale' => $devis['remise_generale'] ?? 0,
                        'type_remise_generale' => $devis['type_remise_generale'] ?? 'euro',
                        'mode_paiement' => 'full_ht',
                        'abonnement_duree_mois' => null,
                        'abonnement_auto_envoi' => 0,
                        'abonnement_parent_id' => null,
                        'generee_automatiquement' => 0,
                    ];
                    $factureModel->create($factureData);
                    $factureId = $pdo->lastInsertId();
                    // Recopie des lignes du devis dans la facture
                    if ($devis_lignes && is_array($devis_lignes)) {
                        foreach ($devis_lignes as $ligne) {
                            $factureLigneModel->add(
                                $factureId,
                                $ligne['intitule'],
                                $ligne['quantite'],
                                $ligne['prix_unitaire'],
                                $ligne['remise'],
                                $ligne['type_remise'],
                                $ligne['total_ligne']
                            );
                        }
                    }
                    $stmt = $pdo->prepare('UPDATE devis SET montant_facture = COALESCE(montant_facture,0) + ? WHERE id = ?');
                    $stmt->execute([$montant, $devisId]);
                } elseif ($paymentOption === 'abonnement_auto') {
                    $subscriptionMonths = null;
                    if (!empty($signature['subscription_months'])) {
                        $subscriptionMonths = (int)$signature['subscription_months'];
                    }
                    if (!$subscriptionMonths || $subscriptionMonths <= 0) {
                        $subscriptionMonths = 12;
                    }
                    $monthly = $totalHt > 0 ? ($totalHt / $subscriptionMonths) : 0.0;
                    $montant = $monthly;
                    $factureData = [
                        'client_id' => $devis['client_id'],
                        'date_facture' => date('Y-m-d'),
                        'numero' => null,
                        'montant' => $montant,
                        'montant_regle' => 0,
                        'statut' => 'Envoyée',
                        'description' => 'Abonnement mensuel (1/' . $subscriptionMonths . ') pour le devis n°' . ($devis['numero'] ?? $devisId),
                        'remise_generale' => 0,
                        'type_remise_generale' => 'euro',
                        'mode_paiement' => 'abonnement_mensuel',
                        'abonnement_duree_mois' => $subscriptionMonths,
                        'abonnement_auto_envoi' => 1,
                        'abonnement_parent_id' => null,
                        'generee_automatiquement' => 0,
                    ];
                    $factureModel->create($factureData);
                    $factureId = $pdo->lastInsertId();
                    $createdFactureId = (int)$factureId;
                    $shouldSendCreatedFacture = true;
                    $intitule = 'Abonnement mensuel (' . number_format($montant, 2, ',', ' ') . ' € / mois) devis n°' . ($devis['numero'] ?? $devisId);
                    $factureLigneModel->add($factureId, $intitule, 1, $montant, 0, 'euro', $montant);
                    $stmt = $pdo->prepare('UPDATE devis SET montant_facture = COALESCE(montant_facture,0) + ? WHERE id = ?');
                    $stmt->execute([$montant, $devisId]);
                }

                if ($pdo->inTransaction()) {
                    $pdo->commit();
                }
            } catch (Throwable $e) {
                $pdo = Database::getInstance()->getConnection();
                if ($pdo->inTransaction()) {
                    $pdo->rollBack();
                }
                // En cas d'erreur de création de facture, on ne bloque pas la signature
            }
        }

        if ($shouldSendCreatedFacture && $createdFactureId > 0) {
            try {
                $reglagesEmails = new ReglagesEmails($db);
                $emailCfg = $reglagesEmails->get();
                if (empty($emailCfg['facture_email_enabled'])) {
                    throw new RuntimeException('Envoi des factures par e-mail désactivé.');
                }
                $mailer = new MailerService($db);
                $emailModel = new Email();
                $emailAttachmentModel = new EmailAttachment();
                $pdfFactCtrl = new PdfFactureController();
                $factureModel = new Facture();
                $facture = $factureModel->getById($createdFactureId);

                $to = trim((string)($client['email'] ?? ''));
                if ($facture && $to !== '' && filter_var($to, FILTER_VALIDATE_EMAIL)) {
                    $subjectTemplate = 'Votre facture n°{{numero}}';
                    $bodyTemplate = trim((string)($emailCfg['template_facture'] ?? ''));
                    if ($bodyTemplate === '') {
                        $bodyTemplate = '<p>Bonjour {{client_nom}},</p><p>Veuillez trouver ci-joint votre facture n°{{numero}} du {{date}}.</p>';
                    }

                    $context = EmailTemplateRenderer::buildFactureContext($facture, $client ?: null);
                    $subject = EmailTemplateRenderer::render($subjectTemplate, $context);
                    $bodyHtml = EmailTemplateRenderer::render($bodyTemplate, $context);

                    $attachments = [];
                    [$pdfContent, $pdfName] = $pdfFactCtrl->generateToString($createdFactureId);
                    if (is_string($pdfContent) && $pdfContent !== '') {
                        $attachments[] = [
                            'content' => $pdfContent,
                            'name' => $pdfName ?: 'facture.pdf',
                            'mime' => 'application/pdf',
                        ];
                    }

                    $sendResult = $mailer->send($to, $subject, $bodyHtml, $attachments);

                    $emailModel->create([
                        'type' => 'sent',
                        'sujet' => $subject,
                        'corps' => $bodyHtml,
                        'expediteur' => $sendResult['from_email'] ?? '',
                        'destinataire' => $to,
                        'statut' => !empty($sendResult['success']) ? 'Envoyé automatiquement' : 'Erreur (envoi auto)',
                        'erreur' => !empty($sendResult['success']) ? null : ($sendResult['error'] ?? 'Echec de l\'envoi auto'),
                        'lu' => 1,
                    ]);

                    $emailId = (int)$db->lastInsertId();
                    if ($emailId > 0) {
                        foreach ($attachments as $attachment) {
                            $emailAttachmentModel->create([
                                'email_id' => $emailId,
                                'filename' => $attachment['name'] ?? 'facture.pdf',
                                'mime_type' => $attachment['mime'] ?? 'application/pdf',
                                'content' => $attachment['content'] ?? null,
                            ]);
                        }
                    }
                }
            } catch (Throwable $e) {
                // On ne bloque jamais la validation de la signature si l'envoi auto échoue.
            }
        }

        // Si le client a choisi le paiement en ligne et que Stripe est configuré,
        // on tente de créer une session de paiement Stripe Checkout.
        if ($clientChoice === 'online') {
            $stripeSecret = trim((string)($infos_gestion['stripe_secret'] ?? ''));
            if ($stripeSecret !== '' && function_exists('curl_init')) {
                $scheme = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? 'https://' : 'http://';
                $host = $_SERVER['HTTP_HOST'] ?? '';
                $scriptDir = dirname($_SERVER['SCRIPT_NAME'] ?? '/');
                $appBaseDir = rtrim(dirname($scriptDir), '/');
                if ($appBaseDir === '' || $appBaseDir === '.') {
                    $appBaseDir = '';
                }
                $baseUrl = $scheme . $host . $appBaseDir;

                $successUrl = $baseUrl . '/controllers/DevisSignatureController.php?token=' . urlencode($token) . '&paid=1';
                $cancelUrl = $baseUrl . '/controllers/DevisSignatureController.php?token=' . urlencode($token) . '&cancel=1';

                $totalHt = isset($devis['montant']) ? (float)$devis['montant'] : 0.0;
                $acompte40 = $totalHt > 0 ? $totalHt * 0.4 : 0.0;
                $subscriptionMonths = null;
                if (!empty($signature['subscription_months'])) {
                    $subscriptionMonths = (int)$signature['subscription_months'];
                    if ($subscriptionMonths <= 0) {
                        $subscriptionMonths = null;
                    }
                }

                // Option effective choisie par le client (fallback sur required_payment)
                $requiredPayment = $paymentOption ?: (string)($signature['required_payment'] ?? 'none');
                $mode = 'payment';
                $unitAmount = 0;
                $label = 'Paiement devis #' . ($devis['numero'] ?? $devisId);

                if ($requiredPayment === 'abonnement_auto') {
                    // Abonnement mensuel automatique basé sur le montant HT du devis et la durée choisie
                    $mode = 'subscription';
                    $monthly = 0.0;
                    if ($totalHt > 0) {
                        $months = $subscriptionMonths ?? 12;
                        $monthly = $months > 0 ? ($totalHt / $months) : $totalHt;
                    }
                    $unitAmount = (int)max(1, round($monthly * 100));
                    $label = 'Abonnement mensuel devis #' . ($devis['numero'] ?? $devisId);
                } elseif ($requiredPayment === 'full_ht') {
                    // Paiement intégral du montant HT en une seule fois
                    $mode = 'payment';
                    $unitAmount = (int)max(1, round($totalHt * 100));
                    $label = 'Paiement total devis #' . ($devis['numero'] ?? $devisId);
                } elseif ($requiredPayment === 'acompte_40') {
                    // Acompte fixe 40 % du montant HT
                    $mode = 'payment';
                    $unitAmount = (int)max(1, round($acompte40 * 100));
                    $label = 'Acompte 40% devis #' . ($devis['numero'] ?? $devisId);
                } else {
                    // Par défaut : acompte manuel du devis
                    $mode = 'payment';
                    $unitAmount = (int)max(1, round($manualDepositAmount * 100));
                    $label = 'Acompte manuel devis #' . ($devis['numero'] ?? $devisId);
                }

                if ($unitAmount > 0) {
                    $fields = [];
                    $fields['mode'] = $mode;
                    $fields['success_url'] = $successUrl;
                    $fields['cancel_url'] = $cancelUrl;
                    $fields['line_items[0][quantity]'] = 1;
                    $fields['line_items[0][price_data][currency]'] = 'eur';
                    $fields['line_items[0][price_data][product_data][name]'] = $label;
                    $fields['line_items[0][price_data][unit_amount]'] = $unitAmount;
                    if ($mode === 'subscription') {
                        $fields['line_items[0][price_data][recurring][interval]'] = 'month';
                    }

                    $ch = curl_init('https://api.stripe.com/v1/checkout/sessions');
                    curl_setopt_array($ch, [
                        CURLOPT_RETURNTRANSFER => true,
                        CURLOPT_POST => true,
                        CURLOPT_HTTPHEADER => [
                            'Authorization: Bearer ' . $stripeSecret,
                        ],
                        CURLOPT_POSTFIELDS => http_build_query($fields),
                    ]);
                    $resp = curl_exec($ch);
                    $httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
                    curl_close($ch);

                    if ($httpCode >= 200 && $httpCode < 300 && $resp) {
                        $json = json_decode($resp, true);
                        if (is_array($json) && isset($json['url'])) {
                            header('Location: ' . $json['url']);
                            exit;
                        }
                    }
                }
            }
        }
        $done = true;
    }
}

$total = isset($devis['montant']) ? (float)$devis['montant'] : 0.0;
$acompte40 = $total > 0 ? $total * 0.4 : 0.0;
$subscriptionMonthsView = null;
if (!empty($signature['subscription_months'])) {
    $subscriptionMonthsView = (int)$signature['subscription_months'];
    if ($subscriptionMonthsView <= 0) {
        $subscriptionMonthsView = null;
    }
}
$ribTexte = (string)($infos_gestion['rib_texte'] ?? '');
$mentionBasDevis = (string)($infos_entreprise['mention_devis'] ?? '');

?><!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="utf-8">
    <title>Signature du devis</title>
    <style>
        body { font-family: Arial, sans-serif; background:#f7f7f7; margin:0; padding:0; }
        .container { max-width: 760px; margin: 40px auto; background:#fff; border-radius:10px; box-shadow:0 2px 16px #0002; padding:28px 32px 24px 32px; }
        h1 { margin-top:0; color:#1769aa; font-size:1.4em; }
        .header-row { display:flex; justify-content:space-between; align-items:flex-start; margin-bottom:22px; }
        .header-left { display:flex; flex-direction:column; align-items:flex-start; max-width:55%; }
        .header-left-logo { margin-bottom:8px; }
        .header-left-logo img { max-height:70px; max-width:160px; object-fit:contain; border-radius:6px; }
        .header-left-info { font-size:0.9em; color:#374151; }
        .header-right { text-align:right; max-width:40%; font-size:0.9em; }
        .header-date { font-weight:600; margin-bottom:8px; }
        .header-client { background:#f7f7f7; border-radius:7px; padding:10px 12px; border:1px solid #d1d5db; }
        .header-client-title { font-weight:bold; margin-bottom:4px; }
        .error { background:#fdecec; color:#b42318; padding:8px 10px; border-radius:6px; margin-bottom:10px; }
        .success { background:#e8f7ee; color:#186a3b; padding:10px 12px; border-radius:8px; margin-bottom:12px; }
        .rib-box { background:#f3f4f6; border-radius:8px; padding:10px 12px; font-size:0.9em; white-space:pre-wrap; }
        .choices { margin:12px 0; }
        .payment-title { font-size:1.05em; margin:0 0 6px 0; }
        .consent-block { margin:16px 0 0 0; }
        .consent-block label { font-size:1.05em; font-weight:600; }
        table.devis-lines { width:100%; border-collapse:collapse; margin:12px 0 10px 0; font-size:0.9em; }
        table.devis-lines th, table.devis-lines td { padding:6px 8px; border:1px solid #e5e7eb; }
        table.devis-lines thead tr { background:#f7f7f7; }
        .totals-box-wrapper { display:flex; justify-content:flex-end; margin:8px 0 16px 0; }
        .totals-box { background:#f9fafb; border-radius:8px; padding:10px 14px; border:1px solid #d1d5db; min-width:230px; text-align:right; font-size:0.92em; }
        .totals-box-row { margin-bottom:4px; }
        .totals-box-row strong { font-weight:600; }
        button { background:#1769aa; color:#fff; border:none; border-radius:6px; padding:8px 16px; font-size:1em; cursor:pointer; }
        button:hover { background:#2980b9; }
        label { display:block; margin-bottom:6px; }
    </style>
</head>
<body>
<div class="container">
<?php if ($done): ?>
    <div class="success">
        <strong>Merci.</strong><br>
        Votre accord pour le devis a bien &eacute;t&eacute; enregistr&eacute;.
    </div>
    <?php if ($clientChoice === 'bank'): ?>
        <p>Vous avez choisi le paiement par virement ou ch&egrave;que. Vous trouverez ci-dessous les coordonn&eacute;es bancaires :</p>
        <?php if ($ribTexte !== ''): ?>
            <div class="rib-box"><?= nl2br(h($ribTexte)) ?></div>
        <?php else: ?>
            <p>Aucune coordonn&eacute;e bancaire n'est encore configur&eacute;e.</p>
        <?php endif; ?>
    <?php else: ?>
        <p>Vous avez choisi le paiement en ligne. Un lien de paiement s&eacute;curis&eacute; pourra vous &ecirc;tre adress&eacute; par votre interlocuteur.</p>
    <?php endif; ?>
<?php else: ?>
    <div class="header-row">
        <div class="header-left">
            <?php
            $logoUrl = '';
            if (!empty($infos_entreprise['logo'])) {
                $logoUrl = (string)$infos_entreprise['logo'];
                if ($logoUrl !== '' && $logoUrl[0] !== '/' && !preg_match('~^https?://~i', $logoUrl)) {
                    $logoUrl = '/' . $logoUrl;
                }
            }
            if ($logoUrl !== ''): ?>
                <div class="header-left-logo">
                    <img src="<?= h($logoUrl) ?>" alt="Logo entreprise">
                </div>
            <?php endif; ?>
            <div class="header-left-info">
                <?php if (!empty($infos_entreprise['nom'])): ?>
                    <div><strong><?= h((string)$infos_entreprise['nom']) ?></strong></div>
                <?php endif; ?>
                <?php if (!empty($infos_entreprise['adresse']) || !empty($infos_entreprise['code_postal']) || !empty($infos_entreprise['ville'])): ?>
                    <div>
                        <?= h((string)($infos_entreprise['adresse'] ?? '')) ?><?php if (!empty($infos_entreprise['code_postal']) || !empty($infos_entreprise['ville'])): ?><br><?= h((string)($infos_entreprise['code_postal'] ?? '')) ?> <?= h((string)($infos_entreprise['ville'] ?? '')) ?><?php endif; ?>
                    </div>
                <?php endif; ?>
                <?php if (!empty($infos_entreprise['email'])): ?>
                    <div>Email : <?= h((string)$infos_entreprise['email']) ?></div>
                <?php endif; ?>
                <?php if (!empty($infos_entreprise['telephone'])): ?>
                    <div>T&eacute;l : <?= h((string)$infos_entreprise['telephone']) ?></div>
                <?php endif; ?>
            </div>
        </div>
        <div class="header-right">
            <div class="header-date">Date : <?= date('d/m/Y') ?></div>
            <div class="header-client">
                <div class="header-client-title">Client</div>
                <?php if (!empty($client['nom'])): ?><div><?= h((string)$client['nom']) ?></div><?php endif; ?>
                <?php if (!empty($client['entreprise'])): ?><div><?= h((string)$client['entreprise']) ?></div><?php endif; ?>
                <?php if (!empty($client['email'])): ?><div><?= h((string)$client['email']) ?></div><?php endif; ?>
                <?php if (!empty($client['telephone'])): ?><div><?= h((string)$client['telephone']) ?></div><?php endif; ?>
                <?php if (!empty($client['rue']) || !empty($client['code_postal']) || !empty($client['ville'])): ?>
                    <div><?= h((string)($client['rue'] ?? '')) ?><?php if (!empty($client['rue'])): ?>, <?php endif; ?><?= h((string)($client['code_postal'] ?? '')) ?> <?= h((string)($client['ville'] ?? '')) ?></div>
                <?php endif; ?>
            </div>
        </div>
    </div>
    <?php
    $displayNumero = $devis['numero'] ?? '';
    if ($displayNumero === '' || $displayNumero === null) {
        $displayYear = date('Y', strtotime($devis['date_devis'] ?? 'now'));
        $prefix = isset($infos_gestion['prefixe_devis']) && $infos_gestion['prefixe_devis'] !== '' ? $infos_gestion['prefixe_devis'] : 'D-{year}-00';
        $resolved = str_replace('{year}', $displayYear, $prefix);
        $displayNumero = $resolved . (string)($devis['id'] ?? '');
    }
    ?>
    <h1>Devis n&deg; <?= h((string)$displayNumero) ?></h1>

    <?php if ($devis_lignes && count($devis_lignes)): ?>
        <table class="devis-lines">
            <thead>
                <tr>
                    <th>Intitul&eacute;</th>
                    <th>Quantit&eacute;</th>
                    <th>Prix unitaire HT</th>
                    <th>Remise</th>
                    <th>Type</th>
                    <th>Total</th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ($devis_lignes as $ligne): ?>
                <tr>
                    <td><?= nl2br(h((string)($ligne['intitule'] ?? ''))) ?></td>
                    <td style="text-align:right;"><?= h((string)($ligne['quantite'] ?? '')) ?></td>
                    <td style="text-align:right;"><?= number_format((float)($ligne['prix_unitaire'] ?? 0), 2, ',', ' ') ?> &euro;</td>
                    <td style="text-align:right;">
                        <?php
                        $rem = isset($ligne['remise']) ? (float)$ligne['remise'] : 0.0;
                        if ($rem != 0.0) {
                            echo number_format($rem, 2, ',', ' ');
                        }
                        ?>
                    </td>
                    <td style="text-align:center;">
                        <?php
                        $rem = isset($ligne['remise']) ? (float)$ligne['remise'] : 0.0;
                        if ($rem != 0.0) {
                            echo (isset($ligne['type_remise']) && $ligne['type_remise'] === 'euro') ? '&euro;' : '%';
                        }
                        ?>
                    </td>
                    <td style="text-align:right;">
                        <?php
                        $q = isset($ligne['quantite']) ? (float)$ligne['quantite'] : 1.0;
                        $pu = isset($ligne['prix_unitaire']) ? (float)$ligne['prix_unitaire'] : 0.0;
                        $rem = isset($ligne['remise']) ? (float)$ligne['remise'] : 0.0;
                        $typeRem = $ligne['type_remise'] ?? 'euro';
                        $totalLigne = $q * $pu;
                        if ($rem != 0.0) {
                            if ($typeRem === 'euro') {
                                $totalLigne -= $rem;
                            } else {
                                $totalLigne -= ($totalLigne * $rem / 100.0);
                            }
                        }
                        if ($totalLigne < 0) {
                            $totalLigne = 0.0;
                        }
                        echo number_format($totalLigne, 2, ',', ' ');
                        ?> &euro;
                    </td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
        <div class="totals-box-wrapper">
            <div class="totals-box">
                <div class="totals-box-row"><strong>Montant HT :</strong> <?= number_format($total, 2, ',', ' ') ?> &euro;</div>
                <?php if ($manualDepositAmount > 0): ?>
                    <div class="totals-box-row"><strong>Acompte manuel du devis :</strong> <?= number_format($manualDepositAmount, 2, ',', ' ') ?> &euro;</div>
                <?php endif; ?>
                <?php if ($acompte40 > 0 && in_array('acompte_40', $onlineAllowedPayments, true)): ?>
                    <div class="totals-box-row"><strong>Acompte 40% (indicatif) :</strong> <?= number_format($acompte40, 2, ',', ' ') ?> &euro;</div>
                <?php endif; ?>
            </div>
        </div>
    <?php else: ?>
        <p style="color:#888;">Aucune ligne de devis.</p>
    <?php endif; ?>
    <?php if ($errors): ?>
        <div class="error"><?php foreach ($errors as $e) { echo h($e) . '<br>'; } ?></div>
    <?php endif; ?>
    <form method="post">
        <div class="choices">
            <p class="payment-title"><strong>Choisissez votre mode de paiement :</strong></p>
            <?php
            // Affiche uniquement les options en ligne autorisées
            $monthsForView = $subscriptionMonthsView ?? 12;
            $monthly = $total > 0 && $monthsForView > 0 ? ($total / $monthsForView) : 0.0;
            if ($allowBank) {
                echo '<label><input type="radio" name="payment_choice" value="bank"> Paiement par virement ou ch&egrave;que</label>';
            }
            if (in_array('acompte_manual', $onlineAllowedPayments, true) && $manualDepositAmount > 0) {
                $manualDetail = $acompteTypeForSignature === 'pourcent'
                    ? ' (' . number_format($acompteValeurForSignature, 2, ',', ' ') . '%)'
                    : '';
                echo '<label><input type="radio" name="payment_choice" value="online_acompte_manual"> Payer en ligne - acompte manuel du devis'.$manualDetail.' ('.number_format($manualDepositAmount, 2, ',', ' ').' &euro;)</label>';
            }
            if (in_array('acompte_40', $onlineAllowedPayments, true)) {
                echo '<label><input type="radio" name="payment_choice" value="online_acompte_40"> Payer en ligne - acompte 40% ('.number_format($acompte40, 2, ',', ' ').' &euro;)</label>';
            }
            if (in_array('full_ht', $onlineAllowedPayments, true)) {
                echo '<label><input type="radio" name="payment_choice" value="online_full_ht"> Payer en ligne - 100% du montant HT ('.number_format($total, 2, ',', ' ').' &euro;)</label>';
            }
            if (in_array('abonnement_auto', $onlineAllowedPayments, true) && $monthly > 0) {
                $labelMois = $monthsForView . ' mois';
                echo '<label><input type="radio" name="payment_choice" value="online_abonnement_auto"> Payer en ligne - abonnement mensuel (environ '.number_format($monthly, 2, ',', ' ').' &euro; / mois sur '.$labelMois.')</label>';
            }
            ?>
        </div>
        <div class="consent-block">
            <label><input type="checkbox" name="accept_conditions" value="1"> J'accepte les conditions de ce devis.</label>
        </div>
        <p style="margin-top:14px;"><button type="submit">Signer le devis</button></p>
        <?php if ($mentionBasDevis !== ''): ?>
            <p style="margin-top:16px;text-align:center;font-size:0.9em;color:#4b5563;"><?= nl2br(h($mentionBasDevis)) ?></p>
        <?php endif; ?>
    </form>
<?php endif; ?>
</div>
</body>
</html>