@php use App\Support\Money; use App\Support\PdfText; use App\Enums\InvoiceVatMode; // $variant ('comptable'|'client'), $showWithholding et $stamp sont fournis par le contrôleur. $variant = $variant ?? 'comptable'; $showWithholding = $showWithholding ?? true; $stamp = $stamp ?? null; $hasVat = $invoice->vat_mode === InvoiceVatMode::Tva20; $hasWithholding = (float) $invoice->vat_withheld > 0; $hasIsWithholding = (float) $invoice->is_withheld > 0; $logo = \App\Support\Identite::cheminLogo(); $qty = static fn ($q): string => rtrim(rtrim(number_format((float) $q, 2, ',', ' '), '0'), ','); $rate = static fn ($r): string => rtrim(rtrim(number_format((float) $r, 2, ',', ' '), '0'), ','); // Normalisation des champs texte pour ne jamais afficher de « ? » (Prompt 23 §1). $marketReference = PdfText::clean($invoice->market_reference); $object = PdfText::clean($invoice->object); $hasPaymentBlock = $invoice->payment_method || $invoice->due_date || $company['bank_name'] || $company['rib']; // v3.13.0 §C — Éléments « à la carte » : chacun n'apparaît que s'il est renseigné ; une facture // qui n'en utilise aucun rend exactement comme avant. $orderReference = PdfText::clean($invoice->order_reference); $footerNote = PdfText::clean($invoice->footer_note); $vatExemptionReason = PdfText::clean($invoice->vat_exemption_reason); $periodStart = $invoice->service_period_start; $periodEnd = $invoice->service_period_end; // v3.13.2 §2 — N° de l'appel d'offres, imprimé seulement s'il est renseigné. $tenderReference = PdfText::clean($invoice->tender_reference); $hasRefBlock = $marketReference || $tenderReference || $object || $orderReference || $periodStart || $periodEnd || $invoice->delivery_date; // v3.13.2 §1 — Préférences d'affichage par facture (OUI par défaut = rendu historique). $showLineNumbers = (bool) ($invoice->show_line_numbers ?? true); $showSectionSubtotals = (bool) ($invoice->show_section_subtotals ?? true); // Remises : HT brut des lignes vs HT net porté par la facture (remises de ligne + globale). $grossHt = $invoice->grossLinesHt(); $totalDiscount = round($grossHt - (float) $invoice->total_ht, 2); $hasDiscount = $totalDiscount > 0.0; // Retenue de garantie et acompte : déduits du net. La variante client (RAS masquées) affiche // quand même ces déductions contractuelles — son « reste à payer » repart du TTC, sans RAS. $retention = (float) ($invoice->retention_amount ?? 0); $advance = (float) ($invoice->advance_amount ?? 0); $hasClientDeductions = $retention > 0 || $advance > 0; $netLabel = $advance > 0 ? 'RESTE À PAYER' : 'NET À ENCAISSER'; $displayNet = $showWithholding ? (float) $invoice->net_payable : round((float) $invoice->total_ttc - $retention - $advance, 2); // La colonne Unité se masque si aucune ligne n'en a ; la colonne N° suit la préférence. $showUnitColumn = $invoice->lines->contains(fn ($l): bool => filled($l->unit)); $colCount = ($showUnitColumn ? 6 : 5) - ($showLineNumbers ? 0 : 1); // v3.13.5 §B — deux préréglages de densité, choisis par DensitePdf (mesure du rendu réel) : // « confort » (aéré — l'esprit d'avant v3.13.3) et « compact » (la densité v3.13.3). // Rendu direct de la vue (tests, aperçus) sans densité → compact, le rendu en vigueur. $density = $density ?? 'compact'; $aere = $density === 'confort'; @endphp {{-- v3.13.5 §B — marqueur de la densité retenue (testable sur le HTML rendu). --}} {{-- (A) En-tête clair : logo + société à gauche, FACTURE à droite --}} {{-- v3.13.5 §A.1 — le numéro rejoint la ligne FACTURE ; dessous : Date (+ Échéance). --}}
@if ($logo !== null) @endif
{{ $company['name'] }}
@if ($company['phone']){{ $company['phone'] }}@endif @if ($company['email']) · {{ $company['email'] }}@endif @if ($company['address'])
{{ $company['address'] }}@endif
FACTURE N° {{ $invoice->number }}
Date : {{ $invoice->date?->format('d/m/Y') }} @if ($invoice->due_date)
Échéance : {{ $invoice->due_date->format('d/m/Y') }}@endif
 
{{-- (B) Émetteur / Facturé à --}}
Émetteur
{{ $company['name'] }}
@if ($company['address']){{ $company['address'] }}
@endif @if ($company['ice'])ICE : {{ $company['ice'] }}@endif @if ($company['if']) · IF : {{ $company['if'] }}@endif
Facturé à
{{ $invoice->client_name }}
@if ($invoice->client_address){!! nl2br(e($invoice->client_address)) !!}
@endif @if ($invoice->client_ice)ICE : {{ $invoice->client_ice }}@endif
{{-- (C) Référence marché + Objet + éléments à la carte (v3.13.0 §C : période, livraison, BC) --}} @if ($hasRefBlock) @php $refLines = []; if ($marketReference) { $refLines[] = 'Réf. marché : '.e($marketReference); } if ($tenderReference) { $refLines[] = 'N° AO : '.e($tenderReference); } if ($orderReference) { $refLines[] = 'N° de bon de commande / décompte : '.e($orderReference); } if ($object) { $refLines[] = 'Objet : '.e($object); } if ($periodStart && $periodEnd) { $refLines[] = 'Période de la prestation : du '.e($periodStart->format('d/m/Y')).' au '.e($periodEnd->format('d/m/Y')); } elseif ($periodStart) { $refLines[] = 'Période de la prestation : à compter du '.e($periodStart->format('d/m/Y')); } elseif ($periodEnd) { $refLines[] = 'Période de la prestation : jusqu\'au '.e($periodEnd->format('d/m/Y')); } if ($invoice->delivery_date) { $refLines[] = 'Date de livraison : '.e($invoice->delivery_date->format('d/m/Y')); } @endphp
{!! implode('
', $refLines) !!}
@endif {{-- (D) Tableau des prestations --}} {{-- v3.13.2 §1 — la colonne N° suit la préférence ; sa largeur revient à la désignation. v3.13.5 §A.2 — désignation ≥ 58 % (62 % sans numéros), prise sur N°/Qté/Unité ; PU HT et Total HT à 13 % restent larges pour les plus gros montants. --}} @if ($showLineNumbers) @endif {{-- v3.13.0 §C — la colonne Unité se masque si aucune ligne n'en a. --}} @if ($showUnitColumn) @else @endif {{-- v3.13.0 §B — lignes regroupées en sections consécutives (bandeau + sous-total HT), numérotation continue. Sans section, le rendu est identique à avant. --}} @php $groupes = \App\Support\SectionsDeLignes::grouper($invoice->lines); $i = 0; @endphp @foreach ($groupes as $groupe) @if ($groupe['title'] !== null) @endif @foreach ($groupe['lines'] as $line) @if ($showLineNumbers) @endif @if ($showUnitColumn) @endif @php $i++; @endphp @endforeach {{-- v3.13.2 §1 — sous-total masquable par facture ; le bandeau de section reste. --}} @if ($groupe['title'] !== null && $showSectionSubtotals) @endif @endforeach
N°Désignation Qté UnitéDésignation QtéPU HT Total HT
{{ PdfText::clean($groupe['title']) }}
{{ $i + 1 }}{!! nl2br(e(PdfText::clean($line->designation))) !!} {{ $qty($line->quantity) }}{{ $line->unit }}{{ Money::format($line->unit_price_ht, false) }} {{ Money::format($line->total_ht, false) }}
Sous-total HT - {{ PdfText::clean($groupe['title']) }}{{ Money::format($groupe['subtotal'], false) }}
{{-- (E) Totaux --}} {{-- v3.13.0 §C — Remise (par ligne et/ou globale) : HT brut, remise, puis HT net. --}} @if ($hasDiscount) @endif @if ($hasVat) @endif {{-- Bloc retenues : version comptable uniquement. La version acheteur public le masque (§2). --}} @if ($showWithholding && $hasWithholding) @endif @if ($showWithholding && $hasIsWithholding) @endif {{-- v3.13.0 §C — Déductions contractuelles, visibles dans les deux variantes. --}} @if ($retention > 0) @endif @if ($advance > 0) @endif @if ($showWithholding || $hasClientDeductions) @endif
TOTAL HT BRUT{{ Money::format($grossHt, false) }}
Remise− {{ Money::format($totalDiscount, false) }}
{{ $hasDiscount ? 'TOTAL HORS TAXE (NET)' : 'TOTAL HORS TAXE' }}{{ Money::format($invoice->total_ht, false) }}
TVA à {{ $rate($invoice->vat_rate) }}%{{ Money::format($invoice->total_vat, false) }}
TOTAL TTC EN DHS{{ Money::format($invoice->total_ttc, false) }}
Retenue TVA à la source ({{ $rate($invoice->vat_withholding_rate) }}%)− {{ Money::format($invoice->vat_withheld, false) }}
Retenue à la source IS ({{ $rate($invoice->is_withholding_rate) }}%)− {{ Money::format($invoice->is_withheld, false) }}
Retenue de garantie ({{ $rate($invoice->retention_rate) }}%)− {{ Money::format($retention, false) }}
Acompte déduit− {{ Money::format($advance, false) }}
{{ $netLabel }}{{ Money::format($displayNet, false) }}
{{-- v3.13.0 §C — Mention d'exonération de TVA (motif libre), régime « sans TVA » uniquement. --}} @if (! $hasVat && $vatExemptionReason)
Exonération de TVA : {{ $vatExemptionReason }}
@endif {{-- (F) Montant en toutes lettres --}}
Arrêtée la présente facture à la somme de {{ $amountInWords }}@if ($amountInWordsIsNet) (net à encaisser)@endif.
{{-- (G) Règlement + (H) Signature --}} {{-- v3.13.5 §A.4 — cadre du cachet élargi à 49 % ; le bloc Règlement garde son contenu. --}} @if ($hasPaymentBlock) @else @endif
Règlement
@if ($invoice->payment_method)Mode de règlement : {{ $invoice->payment_method }}
@endif @if ($invoice->due_date)Échéance : {{ $invoice->due_date->format('d/m/Y') }}
@endif @if ($company['bank_name'])Banque : {{ $company['bank_name'] }}
@endif @if ($company['rib'])RIB : {{ $company['rib'] }}@endif
Cachet et signature du prestataire
@if ($stamp && is_file($stamp)) Cachet @endif @if (($signature ?? null) && is_file($signature)) Signature @endif
{{-- v3.13.0 §C — Notes libres imprimées en pied de facture (distinctes des notes internes). --}} @if ($footerNote)
{!! nl2br(e($footerNote)) !!}
@endif {{-- (I) Pied de page fixe (répété en bas de chaque page) — v3.13.3 §1 : 2 lignes maximum (identité fiscale complète sur la première, banque/RIB sur la seconde). --}}