Commit 99c1d2b6 authored by Claude's avatar Claude

Itemise financial expenses and stop double-counting refunds

Three separate defects made the financial figures wrong.

1. Refunds were counted as revenue. Eighteen queries summed payments on
   status='confirmed' with no direction filter, so outbound refunds were
   added to income across the dashboard, the revenue/product/subscription
   widgets, the financial report, the print report and ReportService.
   That inflated revenue by 40,048 EGP all-time, 32,510 this month.

2. Refunds were simultaneously counted as an expense. The refunded
   original already drops out of revenue when its status becomes
   'refunded', so adding the outbound payment to expenses deducted the
   same money a second time. Refunds are now contra-revenue: the revenue
   card shows gross collected, refunds, and the net, and the expense side
   no longer includes them.

3. Expenses were presented as vague lumps, the worst being "مدفوعات أخرى"
   — which was in fact customer refunds. The breakdown is now one line
   per real cost (payroll, facility rent, purchases, and each expense
   category separately), sorted by size, each stating where it comes
   from.

Payroll was missing from expenses entirely; approved and paid payslips
plus trainer compensation are now included, scoped by branch through the
trainer's employee record.
Co-Authored-By: 's avatarClaude Opus 5 <noreply@anthropic.com>
parent 944c5001
......@@ -27,7 +27,7 @@ class ReportService
public function dailyRevenue(string $from, string $to, ?int $branchId = null): Collection
{
return Payment::where('status', 'confirmed')
return Payment::where('direction', 'inbound')->where('status', 'confirmed')
->whereBetween('payment_date', [$from, $to])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->select(
......@@ -65,7 +65,7 @@ public function outstandingBalances(string $from, string $to, ?int $branchId = n
public function paymentMethodBreakdown(string $from, string $to, ?int $branchId = null): Collection
{
return Payment::where('status', 'confirmed')
return Payment::where('direction', 'inbound')->where('status', 'confirmed')
->whereBetween('payment_date', [$from, $to])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->select('method', DB::raw('SUM(amount) as total'), DB::raw('COUNT(*) as count'))
......@@ -621,7 +621,7 @@ public function branchComparison(string $from, string $to): Collection
->groupBy('branches.id', 'branches.name_ar')
->get()
->map(function ($branch) use ($from, $to) {
$revenue = Payment::where('status', 'confirmed')
$revenue = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->where('branch_id', $branch->id)
->whereBetween('payment_date', [$from, $to])
->sum('amount');
......@@ -709,14 +709,14 @@ public function financialSummary(string $from, string $to, ?int $branchId = null
return [
'total_invoiced' => Invoice::whereBetween('created_at', [$from, $to])
->when($branchId, fn ($q) => $q->whereHasMorph('billable', [Participant::class], fn ($p) => $p->where('branch_id', $branchId)))->sum('total_amount'),
'total_collected' => Payment::where('status', 'confirmed')
'total_collected' => Payment::where('direction', 'inbound')->where('status', 'confirmed')
->whereBetween('created_at', [$from, $to])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('amount'),
'total_outstanding' => Invoice::whereIn('status', ['sent', 'partially_paid', 'overdue'])
->when($branchId, fn ($q) => $q->whereHasMorph('billable', [Participant::class], fn ($p) => $p->where('branch_id', $branchId)))->sum('due_amount'),
'pos_revenue' => POSTransaction::whereBetween('processed_at', [$from, $to])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))->sum('total_amount'),
'payment_methods' => Payment::where('status', 'confirmed')
'payment_methods' => Payment::where('direction', 'inbound')->where('status', 'confirmed')
->whereBetween('created_at', [$from, $to])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->select('method', DB::raw('SUM(amount) as total'), DB::raw('COUNT(*) as count'))
......
......@@ -28,8 +28,8 @@ public function __invoke(Request $request): JsonResponse
'new_today' => Enrollment::whereDate('created_at', $today)->count(),
],
'financial' => [
'revenue_today' => Payment::where('status', 'confirmed')->whereDate('created_at', $today)->sum('amount'),
'revenue_month' => Payment::where('status', 'confirmed')->where('created_at', '>=', now()->startOfMonth())->sum('amount'),
'revenue_today' => Payment::where('direction', 'inbound')->where('status', 'confirmed')->whereDate('created_at', $today)->sum('amount'),
'revenue_month' => Payment::where('direction', 'inbound')->where('status', 'confirmed')->where('created_at', '>=', now()->startOfMonth())->sum('amount'),
'outstanding' => Invoice::whereIn('status', ['sent', 'partially_paid', 'overdue'])->sum('due_amount'),
'overdue_count' => Invoice::where('status', 'overdue')->count(),
],
......
......@@ -16,7 +16,7 @@ public function dailyFinancial(Request $request)
$date = $request->get('date', now()->toDateString());
$branchId = session('active_branch_id');
$payments = Payment::where('status', 'confirmed')
$payments = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->whereDate('payment_date', $date)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->with(['createdBy', 'invoice'])
......
......@@ -68,7 +68,7 @@ public function render()
->whereIn('status', [AttendanceStatus::Present, AttendanceStatus::Late])
->count();
$paymentsToday = Payment::where('status', 'confirmed')
$paymentsToday = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->whereDate('created_at', $today)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->sum('amount');
......@@ -86,7 +86,7 @@ public function render()
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->sum('amount');
$cashCollectionsThisMonth = Payment::where('status', 'confirmed')
$cashCollectionsThisMonth = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->where('method', 'cash')
->whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
......@@ -177,7 +177,7 @@ public function render()
// --- Row 3 Right: Recent Payments ---
$canViewFinancials = auth()->user()->hasPermission('invoices.list');
$recentPayments = $canViewFinancials ? Payment::where('status', 'confirmed')
$recentPayments = $canViewFinancials ? Payment::where('direction', 'inbound')->where('status', 'confirmed')
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->with(['invoice.billable', 'payer'])
->orderByDesc('created_at')
......
......@@ -49,7 +49,7 @@ public function render()
$byProduct = $this->getRevenueByProduct($startDate, $academyId, $branchId, $productType);
// Total confirmed payments this period
$totalRevenue = Payment::where('status', 'confirmed')
$totalRevenue = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->where('created_at', '>=', $startDate)
->when($academyId, fn ($q) => $q->where('academy_id', $academyId))
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
......
......@@ -25,7 +25,7 @@ public function render()
default => now()->startOfMonth(),
};
$revenue = Payment::where('status', 'confirmed')
$revenue = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->where('created_at', '>=', $startDate)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->sum('amount');
......@@ -38,7 +38,7 @@ public function render()
default => now()->subMonth()->startOfMonth(),
};
$previousRevenue = Payment::where('status', 'confirmed')
$previousRevenue = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->whereBetween('created_at', [$previousStart, $startDate])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->sum('amount');
......@@ -47,7 +47,7 @@ public function render()
? round(($revenue - $previousRevenue) / $previousRevenue * 100, 1)
: ($revenue > 0 ? 100 : 0);
$byMethod = Payment::where('status', 'confirmed')
$byMethod = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->where('created_at', '>=', $startDate)
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->select('method', DB::raw('SUM(amount) as total'))
......
......@@ -67,7 +67,7 @@ public function render()
->count();
// Total confirmed payments this period
$totalRevenue = Payment::where('status', 'confirmed')
$totalRevenue = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->where('created_at', '>=', $startDate)
->when($academyId, fn ($q) => $q->where('academy_id', $academyId))
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
......
......@@ -11,6 +11,9 @@
use App\Domain\Financial\Models\Invoice;
use App\Domain\Financial\Models\Payment;
use App\Domain\Financial\Models\Transaction;
use App\Domain\HR\Enums\PayslipStatus;
use App\Domain\HR\Models\Payslip;
use App\Domain\HR\Models\TrainerCompensation;
use App\Domain\Identity\Models\Branch;
use App\Domain\Inventory\Models\PurchaseOrder;
use App\Domain\Participant\Models\Participant;
......@@ -154,8 +157,35 @@ private function getRevenue($from, $to): array
->groupBy('method')
->get();
// Money actually collected in the period, including payments that were
// later refunded — the refund is subtracted below rather than hidden.
$grossRevenue = Payment::where('direction', 'inbound')
->whereIn('status', ['confirmed', 'refunded'])
->whereBetween('payment_date', [$from, $to])
->when($this->branch_id, fn ($q) => $q->where('branch_id', $this->branch_id))
->sum('amount');
// Refunds are contra-revenue, not an operating expense. Counting them
// as an expense while the refunded original already drops out of
// revenue would deduct the same money twice.
$refunds = Payment::where('direction', 'outbound')
->where('status', 'confirmed')
->whereBetween('payment_date', [$from, $to])
->when($this->branch_id, fn ($q) => $q->where('branch_id', $this->branch_id))
->sum('amount');
$refundCount = Payment::where('direction', 'outbound')
->where('status', 'confirmed')
->whereBetween('payment_date', [$from, $to])
->when($this->branch_id, fn ($q) => $q->where('branch_id', $this->branch_id))
->count();
return [
'total' => $totalRevenue,
'total' => max(0, $grossRevenue - $refunds),
'gross' => $grossRevenue,
'refunds' => $refunds,
'refund_count' => $refundCount,
'collected' => $totalRevenue,
'by_method' => $byMethod->map(fn ($p) => [
'method' => $p->method?->value ?? $p->method,
'total' => $p->total,
......@@ -167,24 +197,34 @@ private function getRevenue($from, $to): array
private function getExpenses($from, $to): array
{
$outboundPayments = Payment::where('direction', 'outbound')
->where('status', 'confirmed')
->whereBetween('payment_date', [$from, $to])
->when($this->branch_id, fn ($q) => $q->where('branch_id', $this->branch_id))
$branchId = $this->branch_id;
// Payroll: approved/paid payslips plus trainer compensation earned in
// the period. Neither table carries branch_id, so both scope through
// the trainer's employee record.
$payroll = Payslip::whereIn('status', [PayslipStatus::Approved->value, PayslipStatus::Paid->value])
->whereBetween('created_at', [$from, $to])
->when($branchId, fn ($q) => $q->whereHas('trainer.employee', fn ($e) => $e->forBranch($branchId)))
->sum('net_amount');
$trainerDues = TrainerCompensation::whereIn('status', ['approved', 'paid'])
->whereBetween('created_at', [$from, $to])
->when($branchId, fn ($q) => $q->whereHas('trainer.employee', fn ($e) => $e->forBranch($branchId)))
->sum('amount');
$payrollTotal = (int) $payroll + (int) $trainerDues;
$purchaseOrders = PurchaseOrder::whereIn('status', ['confirmed', 'received', 'partially_received'])
->whereBetween('created_at', [$from, $to])
->when($this->branch_id, fn ($q) => $q->where('branch_id', $this->branch_id))
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->sum('total_amount');
$facilityCostsThisPeriod = $this->calculateProRatedFacilityCost($from, $to);
// Direct expenses from the expenses table
$directExpensesQuery = Expense::whereBetween('expense_date', [$from, $to]);
if ($this->branch_id) {
$directExpensesQuery->where('branch_id', $this->branch_id);
}
$directExpensesQuery = Expense::whereBetween('expense_date', [$from, $to])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId));
$directExpensesTotal = (clone $directExpensesQuery)->sum('amount');
// Breakdown by category
......@@ -200,22 +240,47 @@ private function getExpenses($from, $to): array
'count' => (int) $e->count,
])->toArray();
// Recent expenses
$recentExpenses = Expense::whereBetween('expense_date', [$from, $to])
->when($this->branch_id, fn ($q) => $q->where('branch_id', $this->branch_id))
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->with('creator')
->orderByDesc('expense_date')
->limit(10)
->get();
$total = $payrollTotal + $purchaseOrders + $facilityCostsThisPeriod + $directExpensesTotal;
// One itemised line per real cost, so nothing is presented as a vague
// lump. Each line says where the number comes from.
$lines = [];
if ($payrollTotal > 0) {
$lines[] = ['key' => 'payroll', 'label' => 'رواتب ومستحقات المدربين', 'total' => $payrollTotal,
'source' => 'كشوف الرواتب ومستحقات المدربين المعتمدة', 'color' => 'bg-amber-500', 'count' => null];
}
if ($facilityCostsThisPeriod > 0) {
$lines[] = ['key' => 'facility', 'label' => 'إيجارات المنشآت', 'total' => (int) $facilityCostsThisPeriod,
'source' => 'الإيجار الشهري للمنشآت موزّعاً على أيام الفترة', 'color' => 'bg-blue-500', 'count' => null];
}
if ($purchaseOrders > 0) {
$lines[] = ['key' => 'purchases', 'label' => 'مشتريات ومخزون', 'total' => (int) $purchaseOrders,
'source' => 'أوامر الشراء المؤكدة والمستلمة', 'color' => 'bg-emerald-500', 'count' => null];
}
foreach ($byCategory as $cat) {
$lines[] = ['key' => 'cat_' . $cat['category'], 'label' => $cat['label'], 'total' => $cat['total'],
'source' => 'مصروفات مسجلة يدوياً — ' . $cat['label'], 'color' => 'bg-rose-500', 'count' => $cat['count']];
}
usort($lines, fn ($a, $b) => $b['total'] <=> $a['total']);
return [
'outbound_payments' => $outboundPayments,
'purchase_orders' => $purchaseOrders,
'facility_costs' => $facilityCostsThisPeriod,
'direct_expenses' => $directExpensesTotal,
'payroll' => $payrollTotal,
'purchase_orders' => (int) $purchaseOrders,
'facility_costs' => (int) $facilityCostsThisPeriod,
'direct_expenses' => (int) $directExpensesTotal,
'by_category' => $byCategory,
'recent_expenses' => $recentExpenses,
'total' => $outboundPayments + $purchaseOrders + $facilityCostsThisPeriod + $directExpensesTotal,
'lines' => $lines,
'total' => (int) $total,
];
}
......@@ -241,18 +306,31 @@ private function getMonthlyPL(): array
$start = $month->copy()->startOfMonth();
$end = $month->copy()->endOfMonth();
$income = Payment::where('direction', 'inbound')
->where('status', 'confirmed')
// Gross collected, then refunds netted off — same treatment as
// getRevenue(), so the chart and the cards cannot disagree.
$gross = Payment::where('direction', 'inbound')
->whereIn('status', ['confirmed', 'refunded'])
->whereBetween('payment_date', [$start, $end])
->when($this->branch_id, fn ($q) => $q->where('branch_id', $this->branch_id))
->sum('amount');
$outbound = Payment::where('direction', 'outbound')
$refunds = Payment::where('direction', 'outbound')
->where('status', 'confirmed')
->whereBetween('payment_date', [$start, $end])
->when($this->branch_id, fn ($q) => $q->where('branch_id', $this->branch_id))
->sum('amount');
$income = max(0, $gross - $refunds);
$payrollMonth = (int) Payslip::whereIn('status', [PayslipStatus::Approved->value, PayslipStatus::Paid->value])
->whereBetween('created_at', [$start, $end])
->when($this->branch_id, fn ($q) => $q->whereHas('trainer.employee', fn ($e) => $e->forBranch($this->branch_id)))
->sum('net_amount')
+ (int) TrainerCompensation::whereIn('status', ['approved', 'paid'])
->whereBetween('created_at', [$start, $end])
->when($this->branch_id, fn ($q) => $q->whereHas('trainer.employee', fn ($e) => $e->forBranch($this->branch_id)))
->sum('amount');
$purchases = PurchaseOrder::whereIn('status', ['confirmed', 'received', 'partially_received'])
->whereBetween('created_at', [$start, $end])
->when($this->branch_id, fn ($q) => $q->where('branch_id', $this->branch_id))
......@@ -268,7 +346,7 @@ private function getMonthlyPL(): array
->when($this->branch_id, fn ($q) => $q->where('branch_id', $this->branch_id))
->sum('amount');
$totalExpenses = $outbound + $purchases + $facilityCost + $directExpenses;
$totalExpenses = $payrollMonth + $purchases + $facilityCost + $directExpenses;
$months[] = [
'label' => $month->translatedFormat('M Y'),
......
......@@ -63,7 +63,7 @@ public function updatedPeriod(): void
public function render()
{
$branchId = $this->getActiveBranchId();
$payments = Payment::where('status', 'confirmed')
$payments = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->whereBetween('created_at', [$this->dateFrom, $this->dateTo . ' 23:59:59'])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->get();
......@@ -79,7 +79,7 @@ public function render()
$totalOutstanding = $invoices->whereIn('status', ['sent', 'partially_paid', 'overdue'])->sum('due_amount');
$overdueCount = $invoices->where('status', 'overdue')->count();
$dailyRevenue = Payment::where('status', 'confirmed')
$dailyRevenue = Payment::where('direction', 'inbound')->where('status', 'confirmed')
->whereBetween('created_at', [$this->dateFrom, $this->dateTo . ' 23:59:59'])
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
->select(DB::raw('DATE(created_at) as date'), DB::raw('SUM(amount) as total'))
......
......@@ -88,7 +88,20 @@ class="inline-flex items-center gap-1.5 px-3 py-2 bg-amber-50 border border-ambe
<p class="text-lg sm:text-xl font-bold text-emerald-700 truncate" dir="ltr">{{ number_format($revenue['total'] / 100, 2) }} <span class="text-sm font-normal">{{ __('ج.م') }}</span></p>
</div>
</div>
@if($revenue['refunds'] > 0)
<div class="mt-2 pt-2 border-t border-gray-100 space-y-0.5">
<div class="flex justify-between text-xs text-gray-500">
<span>{{ __('إجمالي المحصّل') }}</span>
<span dir="ltr">{{ number_format($revenue['gross'] / 100, 0) }}</span>
</div>
<div class="flex justify-between text-xs text-orange-600">
<span>− {{ __('استردادات للعملاء') }} ({{ $revenue['refund_count'] }})</span>
<span dir="ltr">{{ number_format($revenue['refunds'] / 100, 0) }}</span>
</div>
</div>
@else
<p class="text-xs text-gray-400 mt-2" dir="ltr">{{ number_format($revenue['transaction_count']) }} {{ __('عملية') }}</p>
@endif
</div>
{{-- Total Expenses --}}
......@@ -104,7 +117,7 @@ class="inline-flex items-center gap-1.5 px-3 py-2 bg-amber-50 border border-ambe
<p class="text-lg sm:text-xl font-bold text-red-700 truncate" dir="ltr">{{ number_format($expenses['total'] / 100, 2) }} <span class="text-sm font-normal">{{ __('ج.م') }}</span></p>
</div>
</div>
<p class="text-xs text-gray-400 mt-2">{{ __('إيجارات + مشتريات + مدفوعات') }}</p>
<p class="text-xs text-gray-400 mt-2">{{ __('رواتب + إيجارات + مشتريات + مصروفات تشغيلية') }}</p>
</div>
{{-- Net Profit/Loss --}}
......@@ -215,61 +228,26 @@ class="inline-flex items-center gap-1.5 px-3 py-2 bg-amber-50 border border-ambe
</div>
@if($expenses['total'] > 0)
<div class="space-y-4">
{{-- Direct Expenses (from expenses table) --}}
@if($expenses['direct_expenses'] > 0)
@php $pct = round(($expenses['direct_expenses'] / $expenses['total']) * 100); @endphp
{{-- One itemised line per real cost, largest first. Every line
states its source so no figure is unexplained. --}}
@foreach($expenses['lines'] as $line)
@php $pct = $expenses['total'] > 0 ? round(($line['total'] / $expenses['total']) * 100) : 0; @endphp
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600 font-medium">{{ __('مصروفات مسجلة') }}</span>
<span class="font-medium" dir="ltr">{{ number_format($expenses['direct_expenses'] / 100, 0) }} {{ __('ج.م') }} <span class="text-gray-400">({{ $pct }}%)</span></span>
</div>
<div class="w-full bg-gray-100 rounded-full h-2.5">
<div class="bg-red-500 h-2.5 rounded-full" style="width: {{ $pct }}%"></div>
</div>
</div>
@endif
{{-- Facility Costs --}}
@if($expenses['facility_costs'] > 0)
@php $pct = round(($expenses['facility_costs'] / $expenses['total']) * 100); @endphp
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">{{ __('إيجارات المنشآت') }}</span>
<span class="font-medium" dir="ltr">{{ number_format($expenses['facility_costs'] / 100, 0) }} {{ __('ج.م') }} <span class="text-gray-400">({{ $pct }}%)</span></span>
</div>
<div class="w-full bg-gray-100 rounded-full h-2.5">
<div class="bg-amber-500 h-2.5 rounded-full" style="width: {{ $pct }}%"></div>
</div>
</div>
@endif
{{-- Purchase Orders --}}
@if($expenses['purchase_orders'] > 0)
@php $pct = round(($expenses['purchase_orders'] / $expenses['total']) * 100); @endphp
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">{{ __('مشتريات المخزون') }}</span>
<span class="font-medium" dir="ltr">{{ number_format($expenses['purchase_orders'] / 100, 0) }} {{ __('ج.م') }} <span class="text-gray-400">({{ $pct }}%)</span></span>
</div>
<div class="w-full bg-gray-100 rounded-full h-2.5">
<div class="bg-blue-500 h-2.5 rounded-full" style="width: {{ $pct }}%"></div>
</div>
</div>
@endif
{{-- Outbound Payments --}}
@if($expenses['outbound_payments'] > 0)
@php $pct = round(($expenses['outbound_payments'] / $expenses['total']) * 100); @endphp
<div>
<div class="flex justify-between text-sm mb-1">
<span class="text-gray-600">{{ __('مدفوعات أخرى') }}</span>
<span class="font-medium" dir="ltr">{{ number_format($expenses['outbound_payments'] / 100, 0) }} {{ __('ج.م') }} <span class="text-gray-400">({{ $pct }}%)</span></span>
<div class="flex justify-between items-start text-sm mb-1 gap-3">
<div class="min-w-0">
<span class="text-gray-700 font-medium">{{ __($line['label']) }}</span>
@if($line['count'])
<span class="text-xs text-gray-400">({{ $line['count'] }} {{ __('عملية') }})</span>
@endif
<p class="text-xs text-gray-400 mt-0.5 truncate">{{ __($line['source']) }}</p>
</div>
<span class="font-medium whitespace-nowrap" dir="ltr">{{ number_format($line['total'] / 100, 0) }} {{ __('ج.م') }} <span class="text-gray-400">({{ $pct }}%)</span></span>
</div>
<div class="w-full bg-gray-100 rounded-full h-2.5">
<div class="bg-purple-500 h-2.5 rounded-full" style="width: {{ $pct }}%"></div>
<div class="{{ $line['color'] }} h-2.5 rounded-full" style="width: {{ $pct }}%"></div>
</div>
</div>
@endif
@endforeach
{{-- Total Bar --}}
<div class="pt-3 border-t border-gray-100">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment