Files
e-ticket/templates/pdf/invoice.html.twig
Serreau Jovann be630e1c67 Add isInvitation field on BilletBuyer to distinguish invitations from free billets
- isInvitation (nullable bool) on BilletBuyer instead of checking totalHT == 0
- Set isInvitation=true when creating invitation in controller
- Email subject/content based on order.isInvitation
- Invoice shows organizer as buyer when order.isInvitation
- Invitations list filtered by isInvitation=true

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:14:45 +01:00

168 lines
8.0 KiB
Twig

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Facture {{ order.orderNumber }}</title>
<style>
@page { size: A4; margin: 0; }
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 11px;
color: #111;
margin: 0;
padding: 0;
width: 210mm;
}
.page { padding: 40px; }
.header-table { width: 100%; border-collapse: collapse; margin-bottom: 30px; }
.header-table td { vertical-align: top; }
.logo { width: 120px; }
.logo img { max-width: 100px; max-height: 60px; }
.title { font-size: 28px; font-weight: bold; text-transform: uppercase; text-align: right; letter-spacing: 2px; }
.subtitle { font-size: 10px; color: #666; text-align: right; margin-top: 4px; }
.info-table { width: 100%; border-collapse: collapse; margin-bottom: 24px; }
.info-table td { vertical-align: top; padding: 0; }
.info-block { padding: 16px; border: 1px solid #eee; background: #fafafa; }
.info-title { font-size: 8px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; color: #999; margin-bottom: 6px; }
.info-text { font-size: 10px; font-weight: bold; line-height: 1.6; }
.items-table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
.items-table th { background: #111827; color: #fff; padding: 10px 12px; font-size: 9px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; text-align: left; }
.items-table th:nth-child(2) { text-align: center; }
.items-table th:nth-child(3), .items-table th:nth-child(4) { text-align: right; }
.items-table td { padding: 10px 12px; border-bottom: 1px solid #eee; font-size: 11px; }
.items-table td:nth-child(2) { text-align: center; }
.items-table td:nth-child(3), .items-table td:nth-child(4) { text-align: right; }
.total-table { width: 300px; margin-left: auto; border-collapse: collapse; margin-bottom: 30px; }
.total-table td { padding: 6px 12px; font-size: 11px; }
.total-table .total-row td { border-top: 3px solid #111827; font-size: 14px; font-weight: bold; padding-top: 10px; }
.payment-block { padding: 14px 16px; border: 1px solid #eee; background: #fafafa; margin-bottom: 24px; }
.footer { padding: 20px 0; border-top: 2px solid #111827; margin-top: 30px; }
.footer-text { font-size: 10px; color: #666; line-height: 1.8; text-align: center; }
</style>
</head>
<body>
<div class="page">
<!-- HEADER -->
<table class="header-table">
<tr>
<td class="logo">
{% if logoBase64 %}
<img src="{{ logoBase64 }}" alt="E-Ticket">
{% endif %}
<div style="font-size: 12px; font-weight: bold; margin-top: 4px;">E-Ticket</div>
<div style="font-size: 8px; color: #666;">by E-Cosplay</div>
</td>
<td>
<div class="title">Facture</div>
<div class="subtitle">N&deg; {{ order.orderNumber }}</div>
<div class="subtitle">Date : {{ order.paidAt ? order.paidAt|date('d/m/Y') : order.createdAt|date('d/m/Y') }}</div>
</td>
</tr>
</table>
<!-- INFOS -->
<table class="info-table">
<tr>
<td style="width: 50%; padding-right: 8px;">
<div class="info-block">
<div class="info-title">Vendeur / Organisateur</div>
<div class="info-text">
{{ organizer.companyName ?? (organizer.firstName ~ ' ' ~ organizer.lastName) }}<br>
{% if organizer.siret %}SIRET : {{ organizer.siret }}<br>{% endif %}
{% if organizer.address %}{{ organizer.address }}<br>{% endif %}
{% if organizer.postalCode or organizer.city %}{{ organizer.postalCode }} {{ organizer.city }}<br>{% endif %}
{% if organizer.email %}{{ organizer.email }}<br>{% endif %}
{% if organizer.phone %}{{ organizer.phone }}{% endif %}
</div>
</div>
</td>
<td style="width: 50%; padding-left: 8px;">
<div class="info-block">
<div class="info-title">Acheteur</div>
<div class="info-text">
{% if order.invitation %}
{{ organizer.companyName ?? (organizer.firstName ~ ' ' ~ organizer.lastName) }}<br>
{% if organizer.email %}{{ organizer.email }}{% endif %}
{% else %}
{{ order.firstName }} {{ order.lastName }}<br>
{{ order.email }}
{% endif %}
</div>
<div class="info-title" style="margin-top: 10px;">Evenement</div>
<div class="info-text">
{{ order.event.title }}<br>
{{ order.event.startAt|date('d/m/Y') }}{{ order.event.startAt|date('H:i') }} a {{ order.event.endAt|date('H:i') }}<br>
{{ order.event.address }}, {{ order.event.zipcode }} {{ order.event.city }}
</div>
</div>
</td>
</tr>
</table>
<!-- ITEMS -->
<table class="items-table">
<thead>
<tr>
<th>Description</th>
<th>Quantite</th>
<th>Prix unitaire HT</th>
<th>Total HT</th>
</tr>
</thead>
<tbody>
{% for item in order.items %}
<tr>
<td style="font-weight: bold;">{{ item.billetName }}</td>
<td>{{ item.quantity }}</td>
<td>{{ item.unitPriceHTDecimal|number_format(2, ',', ' ') }} &euro;</td>
<td style="font-weight: bold;">{{ item.lineTotalHTDecimal|number_format(2, ',', ' ') }} &euro;</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- TOTALS -->
<table class="total-table">
<tr>
<td>Total HT</td>
<td style="text-align: right; font-weight: bold;">{{ order.totalHTDecimal|number_format(2, ',', ' ') }} &euro;</td>
</tr>
<tr>
<td style="color: #666;">TVA (0%)</td>
<td style="text-align: right; color: #666;">0,00 &euro;</td>
</tr>
<tr class="total-row">
<td>Total TTC</td>
<td style="text-align: right;">{{ order.totalHTDecimal|number_format(2, ',', ' ') }} &euro;</td>
</tr>
</table>
<!-- PAYMENT -->
{% if order.paymentMethod %}
<div class="payment-block">
<div class="info-title">Paiement</div>
<div style="font-size: 10px; font-weight: bold;">
{{ order.paymentMethod }}
{% if order.cardBrand and order.cardLast4 %}{{ order.cardBrand|upper }} **** {{ order.cardLast4 }}{% endif %}
{% if order.paidAt %} — Paye le {{ order.paidAt|date('d/m/Y H:i') }}{% endif %}
</div>
</div>
{% endif %}
<!-- FOOTER -->
<div class="footer">
<div class="footer-text">
Vente realisee via la plateforme E-Ticket, operee par l'association E-Cosplay<br>
42 rue de Saint-Quentin, 02800 Beautor, France — contact@e-cosplay.fr<br>
Cette facture est emise par l'organisateur {{ organizer.companyName ?? (organizer.firstName ~ ' ' ~ organizer.lastName) }}{% if organizer.siret %} — SIRET {{ organizer.siret }}{% endif %}
</div>
</div>
</div>
</body>
</html>