Init Git Prod Mars 2026
This commit is contained in:
commit
d81efe93b1
362 files changed
+86627
No files matched your search
@@ -0,0 +1,389 @@
|
||||
<?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>
|
||||
Reference in new issue
Block a user