389 lines
11 KiB
PHP
389 lines
11 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../includes/init_praticien.php';
|
|
|
|
$paiement_id = intval($_GET['id'] ?? 0);
|
|
|
|
$stmt = $pdo->prepare("
|
|
SELECT p.*, a.nom AS formule
|
|
FROM paiement p
|
|
JOIN abonnement a ON p.abonnement_id = a.id
|
|
WHERE p.id = ? AND p.praticien_id = ?
|
|
");
|
|
$stmt->execute([$paiement_id, $_SESSION['reference_id']]);
|
|
$paiement = $stmt->fetch();
|
|
|
|
if (!$paiement) {
|
|
die(htmlspecialchars($translations['facture_introuvable']));
|
|
}
|
|
|
|
$methodeMap = [
|
|
'cb' => $translations['methode_carte'] ?? 'CB',
|
|
'virement' => $translations['methode_virement'] ?? 'Virement',
|
|
'paypal' => $translations['methode_paypal'] ?? 'PayPal',
|
|
'stripe' => $translations['methode_stripe'] ?? 'Stripe',
|
|
];
|
|
|
|
$statutMap = [
|
|
'paye' => $translations['statut_paye'] ?? 'Payé',
|
|
'payé' => $translations['statut_paye'] ?? 'Payé',
|
|
'succeeded' => $translations['statut_paye'] ?? 'Payé',
|
|
'pending' => $translations['statut_en_attente'] ?? 'En attente',
|
|
'en_attente' => $translations['statut_en_attente'] ?? 'En attente',
|
|
'failed' => $translations['statut_echoue'] ?? 'Échoué',
|
|
'echoue' => $translations['statut_echoue'] ?? 'Échoué',
|
|
'échoué' => $translations['statut_echoue'] ?? 'Échoué',
|
|
'refunded' => $translations['statut_rembourse'] ?? 'Remboursé',
|
|
'rembourse' => $translations['statut_rembourse'] ?? 'Remboursé',
|
|
'remboursé' => $translations['statut_rembourse'] ?? 'Remboursé',
|
|
];
|
|
|
|
$methode = strtolower($paiement['methode'] ?? '');
|
|
$translationKey = 'methode_' . $methode;
|
|
$libMethode = $translations[$translationKey] ?? ucfirst($methode);
|
|
$libStatut = $statutMap[strtolower($paiement['statut'] ?? '')] ?? ($paiement['statut'] ?? '');
|
|
|
|
$numero = str_pad((string)$paiement['id'], 6, '0', STR_PAD_LEFT);
|
|
$datePaiement = !empty($paiement['date_paiement']) ? date('d/m/Y', strtotime($paiement['date_paiement'])) : '';
|
|
$montant = number_format((float)$paiement['montant'], 2, ',', ' ') . ' €';
|
|
|
|
$formuleKey = trim((string)($paiement['formule'] ?? ''));
|
|
$formuleTxt = $formuleKey !== '' ? ($translations[$formuleKey] ?? $formuleKey) : '';
|
|
|
|
$statutLower = strtolower((string)($paiement['statut'] ?? ''));
|
|
$badgeClass =
|
|
in_array($statutLower, ['paye','payé','succeeded'], true) ? 'badge--paid' :
|
|
(in_array($statutLower, ['pending','en_attente'], true) ? 'badge--pending' :
|
|
(in_array($statutLower, ['failed','echoue','échoué'], true) ? 'badge--failed' :
|
|
(in_array($statutLower, ['refunded','rembourse','remboursé'], true) ? 'badge--refunded' : 'badge--neutral')));
|
|
|
|
?>
|
|
<!doctype html>
|
|
<html lang="<?= htmlspecialchars($_SESSION['lang'] ?? 'fr') ?>">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title><?= htmlspecialchars($translations['titre_facture']) ?> #<?= htmlspecialchars($numero) ?></title>
|
|
|
|
<style>
|
|
:root{
|
|
--brand:#38378B; /* même vibe que la capture */
|
|
--bg:#f3f4f6; /* gris clair */
|
|
--card:#ffffff;
|
|
--text:#111827;
|
|
--muted:#6b7280;
|
|
--line:#d9dde6;
|
|
--shadow:0 14px 40px rgba(17,24,39,.10);
|
|
--radius:18px;
|
|
|
|
--paid:#16a34a;
|
|
--pending:#f59e0b;
|
|
--failed:#dc2626;
|
|
--refunded:#2563eb;
|
|
--neutral:#6b7280;
|
|
|
|
--btn:#e53935; /* rouge bouton comme capture */
|
|
--btnHover:#cf2f2b;
|
|
}
|
|
|
|
*{box-sizing:border-box}
|
|
body{
|
|
margin:0;
|
|
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, "Noto Sans", sans-serif;
|
|
color:var(--text);
|
|
background:var(--bg);
|
|
}
|
|
|
|
.wrap{
|
|
max-width: 980px;
|
|
margin: 0 auto;
|
|
padding: 28px 18px 40px;
|
|
}
|
|
|
|
/* Carte principale */
|
|
.card{
|
|
background:var(--card);
|
|
border-radius: var(--radius);
|
|
box-shadow: var(--shadow);
|
|
overflow:hidden; /* pour arrondi de la bande top */
|
|
border: 1px solid rgba(17,24,39,.06);
|
|
}
|
|
|
|
/* Bande violette top */
|
|
.topbar{
|
|
background: var(--brand);
|
|
height: 90px;
|
|
position: relative;
|
|
}
|
|
|
|
.brand{
|
|
position:absolute;
|
|
left: 28px;
|
|
bottom: 22px;
|
|
display:flex;
|
|
align-items:center;
|
|
gap: 14px;
|
|
}
|
|
|
|
.brand__logo{
|
|
height: 46px;
|
|
width:auto;
|
|
display:block;
|
|
filter: drop-shadow(0 2px 0 rgba(0,0,0,.08));
|
|
}
|
|
|
|
/* Contenu */
|
|
.content{
|
|
padding: 34px 34px 18px;
|
|
}
|
|
|
|
.title{
|
|
margin:0 0 14px;
|
|
font-size: 28px;
|
|
font-weight: 800;
|
|
letter-spacing: .2px;
|
|
}
|
|
|
|
.subtitle{
|
|
margin:0 0 24px;
|
|
color:var(--muted);
|
|
font-size: 16px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* Ligne en-tête reçu */
|
|
.meta{
|
|
display:flex;
|
|
flex-wrap:wrap;
|
|
align-items:flex-start;
|
|
justify-content:space-between;
|
|
gap: 14px;
|
|
margin: 6px 0 18px;
|
|
}
|
|
|
|
.receipt-id{
|
|
display:flex;
|
|
flex-direction:column;
|
|
gap: 6px;
|
|
}
|
|
|
|
.receipt-id .k{
|
|
color:var(--muted);
|
|
font-size: 13px;
|
|
}
|
|
.receipt-id .v{
|
|
font-size: 18px;
|
|
font-weight: 800;
|
|
letter-spacing: .6px;
|
|
}
|
|
|
|
.badge{
|
|
display:inline-flex;
|
|
align-items:center;
|
|
gap: 8px;
|
|
padding: 10px 14px;
|
|
border-radius: 999px;
|
|
font-weight: 700;
|
|
font-size: 14px;
|
|
border: 1px solid rgba(17,24,39,.10);
|
|
background: #fff;
|
|
white-space:nowrap;
|
|
}
|
|
.dot{
|
|
width:10px; height:10px; border-radius:999px;
|
|
background: var(--neutral);
|
|
}
|
|
.badge--paid .dot{background:var(--paid)}
|
|
.badge--pending .dot{background:var(--pending)}
|
|
.badge--failed .dot{background:var(--failed)}
|
|
.badge--refunded .dot{background:var(--refunded)}
|
|
.badge--neutral .dot{background:var(--neutral)}
|
|
|
|
/* Bloc infos encadré (comme capture) */
|
|
.box{
|
|
border:1px solid var(--line);
|
|
border-radius: 14px;
|
|
overflow:hidden;
|
|
margin: 18px 0 24px;
|
|
}
|
|
|
|
.row{
|
|
display:grid;
|
|
grid-template-columns: 260px 1fr;
|
|
gap: 0;
|
|
padding: 16px 18px;
|
|
border-top: 1px solid var(--line);
|
|
}
|
|
.row:first-child{border-top:none}
|
|
|
|
.label{
|
|
color:var(--muted);
|
|
font-size: 16px;
|
|
padding-right: 18px;
|
|
border-right: 1px solid var(--line);
|
|
display:flex;
|
|
align-items:center;
|
|
min-height: 28px;
|
|
}
|
|
.value{
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
padding-left: 18px;
|
|
display:flex;
|
|
align-items:center;
|
|
min-height: 28px;
|
|
word-break: break-word;
|
|
}
|
|
|
|
/* Total */
|
|
.total{
|
|
display:flex;
|
|
align-items:center;
|
|
justify-content:space-between;
|
|
gap: 14px;
|
|
padding: 18px 18px;
|
|
border-top: 1px solid var(--line);
|
|
background: rgba(56,55,139,.04);
|
|
}
|
|
.total .k{ color:var(--muted); font-weight:700; }
|
|
.total .v{ font-size: 22px; font-weight: 900; }
|
|
|
|
/* Bouton */
|
|
.actions{
|
|
display:flex;
|
|
justify-content:center;
|
|
padding: 6px 0 18px;
|
|
}
|
|
.btn{
|
|
border:0;
|
|
background: var(--btn);
|
|
color:#fff;
|
|
font-weight: 800;
|
|
padding: 16px 26px;
|
|
border-radius: 999px;
|
|
cursor:pointer;
|
|
font-size: 16px;
|
|
box-shadow: 0 10px 22px rgba(229,57,53,.22);
|
|
transition: transform .05s ease, background .15s ease;
|
|
}
|
|
.btn:hover{ background: var(--btnHover); }
|
|
.btn:active{ transform: translateY(1px); }
|
|
|
|
/* Footer carte */
|
|
.card-footer{
|
|
padding: 16px 34px 28px;
|
|
color: var(--muted);
|
|
font-size: 14px;
|
|
border-top: 1px solid rgba(17,24,39,.06);
|
|
}
|
|
|
|
/* Footer page (comme capture) */
|
|
.page-footer{
|
|
text-align:center;
|
|
color:#9ca3af;
|
|
padding: 18px 6px 0;
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* Mobile */
|
|
@media (max-width: 720px){
|
|
.topbar{height: 90px}
|
|
.brand{left: 18px; bottom: 18px}
|
|
.content{padding: 26px 18px 12px}
|
|
.card-footer{padding: 14px 18px 22px}
|
|
.row{grid-template-columns: 1fr; padding: 14px 14px}
|
|
.label{border-right:none; padding-right:0; margin-bottom:6px}
|
|
.value{padding-left:0}
|
|
.title{font-size:24px}
|
|
}
|
|
|
|
/* Impression */
|
|
@media print{
|
|
body{background:#fff}
|
|
.wrap{padding:0; max-width:100%}
|
|
.card{box-shadow:none; border:1px solid #e5e7eb}
|
|
.page-footer{display:none}
|
|
.btn{display:none}
|
|
.topbar{height: 90px}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="wrap">
|
|
<div class="card">
|
|
<div class="topbar">
|
|
<div class="brand">
|
|
<img class="brand__logo" src="/public/uploads/img/logo_mail.png" alt="Logo">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="content">
|
|
<h1 class="title">
|
|
<?= htmlspecialchars($translations['titre_facture']) ?>
|
|
</h1>
|
|
|
|
<p class="subtitle">
|
|
<?= htmlspecialchars($translations['facture_prefix'] ?? 'Reçu') ?>
|
|
#<?= htmlspecialchars($numero) ?> —
|
|
<?= htmlspecialchars($translations['facture_date'] ?? 'Date') ?> : <?= htmlspecialchars($datePaiement) ?>
|
|
</p>
|
|
|
|
<div class="meta">
|
|
<div class="receipt-id">
|
|
<div class="k"><?= htmlspecialchars($translations['facture_prefix'] ?? 'Reçu') ?></div>
|
|
<div class="v">#<?= htmlspecialchars($numero) ?></div>
|
|
</div>
|
|
|
|
<div class="badge <?= $badgeClass ?>">
|
|
<span class="dot"></span>
|
|
<span><?= htmlspecialchars($libStatut) ?></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="box">
|
|
<div class="row">
|
|
<div class="label"><?= htmlspecialchars($translations['facture_date']) ?></div>
|
|
<div class="value"><?= htmlspecialchars($datePaiement) ?></div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="label"><?= htmlspecialchars($translations['facture_formule']) ?></div>
|
|
<div class="value"><?= htmlspecialchars($formuleTxt) ?></div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="label"><?= htmlspecialchars($translations['facture_methode']) ?></div>
|
|
<div class="value"><?= htmlspecialchars($libMethode) ?></div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="label"><?= htmlspecialchars($translations['facture_statut']) ?></div>
|
|
<div class="value"><?= htmlspecialchars($libStatut) ?></div>
|
|
</div>
|
|
|
|
<div class="total">
|
|
<div class="k"><?= htmlspecialchars($translations['facture_montant']) ?></div>
|
|
<div class="v"><?= htmlspecialchars($montant) ?></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="actions">
|
|
<button class="btn" onclick="window.print()">
|
|
<?= htmlspecialchars($translations['btn_imprimer_facture']) ?>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-footer">
|
|
<div>
|
|
<?= htmlspecialchars($translations['facture_note'] ?? 'Merci pour votre paiement. Conservez ce reçu pour vos archives.') ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="page-footer">
|
|
© <?= date('Y') ?> УСЛУГИ.ФР — <?= htmlspecialchars($translations['merci'] ?? 'Спасибо.') ?>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|