@php // Price formatting helper function $priceFormat = $settings->price_format ?? null; function formatPrice($number, $decimals = 2, $priceFormat = null) { $number = (float) $number; $decimals = (int) $decimals; if (empty($priceFormat)) { return number_format($number, $decimals, '.', ','); } switch ($priceFormat) { case 'comma_dot': return number_format($number, $decimals, '.', ','); case 'dot_comma': return number_format($number, $decimals, ',', '.'); case 'space_comma': return number_format($number, $decimals, ',', ' '); default: return number_format($number, $decimals, '.', ','); } } @endphp @php // ---------- Helper: status badges (order/workflow) ---------- function pillSale($status) { $s = strtolower(trim((string)$status)); if (preg_match('/\b(completed|approved|fulfilled|closed)\b/', $s)) return 'pill success'; if (preg_match('/\b(pending|awaiting|on hold)\b/', $s)) return 'pill warn'; if (preg_match('/\b(sent|shipped|in transit)\b/', $s)) return 'pill info'; if (preg_match('/\b(canceled|cancelled|rejected|void)\b/', $s))return 'pill danger'; return 'pill'; } // ---------- Helper: payment badges (avoid "unpaid" -> "paid") ---------- function pillPayment($status) { $s = strtolower(trim((string)$status)); if (preg_match('/\b(unpaid|not\s*paid|overdue|failed|due)\b/', $s)) return 'pill danger'; if (preg_match('/\b(partial|partially\s*paid|part-?paid)\b/', $s)) return 'pill warn'; if (preg_match('/\b(paid|settled|paid\s*in\s*full)\b/', $s)) return 'pill success'; return 'pill'; } // ---------- Section totals ---------- $salesGrandSum = $sales->sum('GrandTotal'); $salesPaidSum = $sales->sum('paid_amount'); $salesDueSum = $sales->sum(function($s){ return (float)($s->GrandTotal ?? 0) - (float)($s->paid_amount ?? 0); }); $paymentsSum = $payments->sum('montant'); $quotesGrand = $quotations->sum('GrandTotal'); $retGrandSum = $returns->sum('GrandTotal'); $retPaidSum = $returns->sum('paid_amount'); $retDueSum = $returns->sum(function($r){ return (float)($r->GrandTotal ?? 0) - (float)($r->paid_amount ?? 0); }); // ---------- Safe fallbacks for quick stats ---------- $qsOpeningBalance = (float)($client->opening_balance ?? 0); $qsSalesGrand = (float)($client->salesGrand ?? $salesGrandSum); $qsSalesPaid = (float)($client->salesPaid ?? $salesPaidSum); $qsSaleDue = (float)($client->sale_due ?? ($qsSalesGrand - $qsSalesPaid)); $qsReturnsDue = (float)($client->return_due ?? $retDueSum); $qsPaymentsTot = (float)($client->paymentsTotal ?? $paymentsSum); $qsQuotesGrand = (float)($client->quotationsTotal ?? $quotesGrand); $qsNetBalance = isset($client->netBalance) ? (float)$client->netBalance : ($qsOpeningBalance + $qsSaleDue - $qsReturnsDue); @endphp
Customer Ledger
Generated at: {{ now()->format('Y-m-d H:i') }}
{{-- (Optional) Logo / Company Name --}}
{{ $client->name }}
Code: {{ $client->code ?? '-' }}
City: {{ $client->city ?? '-' }}, Country: {{ $client->country ?? '-' }}
Email: {{ $client->email ?? '-' }}
Phone: {{ $client->phone ?? '-' }}
Tax #: {{ $client->tax_number ?? '-' }}
Opening Balance
{{ formatPrice($qsOpeningBalance, 2, $priceFormat) }}
Sales (Grand)
{{ formatPrice($qsSalesGrand, 2, $priceFormat) }}
Sales (Paid)
{{ formatPrice($qsSalesPaid, 2, $priceFormat) }}
Sales (Due)
{{ formatPrice($qsSaleDue, 2, $priceFormat) }}
Returns (Due)
{{ formatPrice($qsReturnsDue, 2, $priceFormat) }}
Payments (Total)
{{ formatPrice($qsPaymentsTot, 2, $priceFormat) }}
Quotations (Grand)
{{ formatPrice($qsQuotesGrand, 2, $priceFormat) }}
Net Balance
{{ formatPrice($qsNetBalance, 2, $priceFormat) }}
@if($qsOpeningBalance != 0)

Opening Balance (Previous Dues)

Type Description Amount Notes
Opening Balance Previous Dues (Before System Start) {{ formatPrice($qsOpeningBalance, 2, $priceFormat) }} Balance carried forward from previous period
@endif

Sales

@forelse ($sales as $s) @empty @endforelse
Date Ref Warehouse Status Grand Total Paid Due Payment Status
@php $dateFormat = $settings->date_format ?? 'YYYY-MM-DD'; $dateTime = \Carbon\Carbon::parse($s->date); $phpDateFormat = str_replace(['YYYY', 'MM', 'DD'], ['Y', 'm', 'd'], $dateFormat); // Check if original date string contains time $hasTime = strpos($s->date, ' ') !== false && preg_match('/\d{1,2}:\d{2}/', $s->date); if ($hasTime) { $formattedDate = $dateTime->format($phpDateFormat . ' H:i'); // Preserve seconds if they exist if (preg_match('/:\d{2}:\d{2}/', $s->date)) { $formattedDate = $dateTime->format($phpDateFormat . ' H:i:s'); } } else { $formattedDate = $dateTime->format($phpDateFormat); } @endphp {{$formattedDate}} {{ $s->Ref }} {{ optional($s->warehouse)->name }} {{ $s->statut }} {{ formatPrice($s->GrandTotal, 2, $priceFormat) }} {{ formatPrice($s->paid_amount, 2, $priceFormat) }} {{ formatPrice(($s->GrandTotal - $s->paid_amount), 2, $priceFormat) }} {{ $s->payment_statut }}
No sales found.
Totals {{ formatPrice($salesGrandSum, 2, $priceFormat) }} {{ formatPrice($salesPaidSum, 2, $priceFormat) }} {{ formatPrice($salesDueSum, 2, $priceFormat) }}

Payments

@forelse ($payments as $p) @empty @endforelse
Date Payment Ref Type Sale Ref Method Amount
@php $dateFormat = $settings->date_format ?? 'YYYY-MM-DD'; $dateTime = \Carbon\Carbon::parse($p->date); $phpDateFormat = str_replace(['YYYY', 'MM', 'DD'], ['Y', 'm', 'd'], $dateFormat); // Check if original date string contains time $hasTime = strpos($p->date, ' ') !== false && preg_match('/\d{1,2}:\d{2}/', $p->date); if ($hasTime) { $formattedDate = $dateTime->format($phpDateFormat . ' H:i'); // Preserve seconds if they exist if (preg_match('/:\d{2}:\d{2}/', $p->date)) { $formattedDate = $dateTime->format($phpDateFormat . ' H:i:s'); } } else { $formattedDate = $dateTime->format($phpDateFormat); } @endphp {{$formattedDate}} {{ $p->Ref }} @if(isset($p->payment_type) && $p->payment_type === 'opening_balance') Opening Balance @else Sale @endif {{ $p->Sale_Ref ?? '-' }} {{ $p->payment_method }} {{ formatPrice($p->montant, 2, $priceFormat) }}
No payments found.
Total Payments {{ formatPrice($paymentsSum, 2, $priceFormat) }}

Quotations

@forelse ($quotations as $q) @empty @endforelse
Date Ref Status Warehouse Grand Total
@php $dateFormat = $settings->date_format ?? 'YYYY-MM-DD'; $dateTime = \Carbon\Carbon::parse($q->date); $phpDateFormat = str_replace(['YYYY', 'MM', 'DD'], ['Y', 'm', 'd'], $dateFormat); // Check if original date string contains time $hasTime = strpos($q->date, ' ') !== false && preg_match('/\d{1,2}:\d{2}/', $q->date); if ($hasTime) { $formattedDate = $dateTime->format($phpDateFormat . ' H:i'); // Preserve seconds if they exist if (preg_match('/:\d{2}:\d{2}/', $q->date)) { $formattedDate = $dateTime->format($phpDateFormat . ' H:i:s'); } } else { $formattedDate = $dateTime->format($phpDateFormat); } @endphp {{$formattedDate}} {{ $q->Ref }} {{ $q->statut }} {{ optional($q->warehouse)->name }} {{ formatPrice($q->GrandTotal, 2, $priceFormat) }}
No quotations found.
Total Quotations {{ formatPrice($quotesGrand, 2, $priceFormat) }}

Returns

@forelse ($returns as $r) @empty @endforelse
Ref Status Sale Ref Warehouse Grand Total Paid Due Payment Status
{{ $r->Ref }} {{ $r->statut }} {{ optional($r->sale)->Ref ?? '---' }} {{ optional($r->warehouse)->name }} {{ number_format($r->GrandTotal, 2) }} {{ number_format($r->paid_amount, 2) }} {{ number_format(($r->GrandTotal - $r->paid_amount), 2) }} {{ $r->payment_statut }}
No returns found.
Totals {{ formatPrice($retGrandSum, 2, $priceFormat) }} {{ formatPrice($retPaidSum, 2, $priceFormat) }} {{ formatPrice($retDueSum, 2, $priceFormat) }}