@extends('layouts.finance')
@section('title', 'Monthly Report')
@section('subtitle', 'Closed month business report')
@section('content')
@php
$closing = $reportData['closing'];
$status = $reportData['status'];
$trend = $reportData['trend'];
$previous = $reportData['previous'];
$settings = $reportData['settings'];
$bankAccounts = $reportData['bank_accounts'];
$creditCards = $reportData['credit_cards'];
$debts = $reportData['debts'];
$collectibles = $reportData['collectibles'];
$inventory = $reportData['inventory'];
$products = $reportData['products'];
$providers = $reportData['providers'];
$expenseBreakdown = $reportData['expense_breakdown'];
$topClients = $reportData['top_clients'] ?? collect();
$b2c = $reportData['b2c'] ?? ['orders' => 0, 'orders_delta' => null, 'vouchers' => 0, 'revenue' => 0, 'profit' => 0, 'avg_profit_per_voucher' => 0, 'trend' => ['labels' => [], 'orders' => [], 'profit' => []], 'products' => collect()];
$points = $reportData['points'] ?? ['summary' => ['quarterly' => 0, 'yearly' => 0, 'total' => 0, 'redeemed' => 0], 'by_product' => collect(), 'agent_targets' => collect()];
$support = $reportData['support'] ?? ['connected' => false, 'tickets_opened' => 0, 'tickets_resolved' => 0, 'avg_first_response' => '-', 'avg_resolution_time' => '-'];
$assets = $reportData['assets'];
$factory = $reportData['factory'];
$periodStart = $closing->period_start?->format('d M Y') ?? $status['period_start']->format('d M Y');
$periodEnd = $closing->period_end?->format('d M Y') ?? $status['period_end']->format('d M Y');
$profitMargin = (float) $closing->total_sale > 0 ? ((float) $closing->net_profit / (float) $closing->total_sale) * 100 : 0;
$trendMax = max(1, collect($trend['revenue'])->merge($trend['expenses'])->max());
$netWorthItems = collect([
['label' => 'Inventory', 'amount' => (float) $inventory->sum('pkr_value'), 'class' => 'green'],
['label' => 'Bank balance', 'amount' => (float) $bankAccounts->sum('pkr_balance'), 'class' => 'blue'],
['label' => 'Collectible', 'amount' => (float) $collectibles->sum('pkr_outstanding'), 'class' => 'purple'],
['label' => 'In transit', 'amount' => (float) ($assets['in_transit_total'] ?? $assets['in_transit_amount'] ?? 0), 'class' => 'pink'],
['label' => 'Total debt', 'amount' => -1 * (float) ($assets['liabilities_total'] ?? 0), 'class' => 'red'],
]);
$netWorthMax = max(1, $netWorthItems->max(fn ($row) => abs((float) $row['amount'])));
$expenseTotal = max(1, (float) $expenseBreakdown->sum('amount_pkr'));
$expenseColors = ['#2f7ed8', '#008000', '#e576a7', '#f5a400', '#22b98f', '#fb6a3a', '#5142ad', '#94a3b8'];
$expenseStops = [];
$expenseCursor = 0.0;
foreach ($expenseBreakdown->take(8)->values() as $i => $row) {
$share = ((float) $row['amount_pkr'] / $expenseTotal) * 100;
$expenseStops[] = $expenseColors[$i % count($expenseColors)].' '.$expenseCursor.'% '.($expenseCursor + $share).'%';
$expenseCursor += $share;
}
$expenseDonut = $expenseStops ? 'conic-gradient('.implode(',', $expenseStops).')' : 'conic-gradient(#e5e7eb 0 100%)';
$productSoldRows = $products->filter(fn ($row) => (float) ($row['sold'] ?? 0) > 0)->sortByDesc('sold')->take(12)->values();
$productProfitRows = $products->filter(fn ($row) => abs((float) ($row['profit_pkr'] ?? 0)) > 0)->sortByDesc('profit_pkr')->take(8)->values();
$inventoryChartRows = $inventory->filter(fn ($row) => (float) ($row['pkr_value'] ?? 0) > 0)->sortByDesc('pkr_value')->take(14)->values();
$productSoldMax = max(1, (float) $productSoldRows->max('sold'));
$productProfitMax = max(1, (float) $productProfitRows->max(fn ($row) => abs((float) ($row['profit_pkr'] ?? 0))));
$inventoryChartMax = max(1, (float) $inventoryChartRows->max('pkr_value'));
$b2cOrderMax = max(1, collect($b2c['trend']['orders'] ?? [])->max());
$b2cProfitMax = max(1, collect($b2c['trend']['profit'] ?? [])->map(fn ($amount) => abs((float) $amount))->max());
$pointProductRows = collect($points['by_product'] ?? collect())->take(8)->values();
$pointProductMax = max(1, $pointProductRows->max(fn ($row) => max((float) ($row['quarterly'] ?? 0), (float) ($row['yearly'] ?? 0))));
$delta = fn ($current, $prev) => (float) $prev != 0.0 ? (((float) $current - (float) $prev) / abs((float) $prev)) * 100 : null;
$fmtDelta = function ($current, $prev) use ($delta) {
$value = $delta($current, $prev);
if ($value === null) {
return 'No previous month';
}
return ($value >= 0 ? '+' : '').number_format($value, 1).'% vs previous month';
};
@endphp
@push('styles')
@endpush
{{ $settings['business_name'] ?? 'Examism Voucher Business' }}
{{ $closing->month->format('F Y') }} Monthly Business Report
Covered period: {{ $periodStart }} to {{ $periodEnd }}
Closed {{ $closing->closed_at?->format('d M Y, H:i') }}
{{ $closing->accounts_closed_count }}/{{ $closing->accounts_required_count }} accounts closed
Print
Executive Summary Locked closing figures plus live balance-sheet detail
Revenue / Total Sale
{{ $metrics->money($closing->total_sale, 'PKR') }}
{{ $fmtDelta($closing->total_sale, $previous['total_sale']) }}
Expenses
{{ $metrics->money($closing->expense, 'PKR') }}
{{ $fmtDelta($closing->expense, $previous['expense']) }}
Net Profit
{{ $metrics->money($closing->net_profit, 'PKR') }}
{{ number_format($profitMargin, 1) }}% margin
Company Net Worth
{{ $metrics->money($closing->net_worth, 'PKR') }}
Captured at month close
Total Debt
{{ $metrics->money(($assets['liabilities_total'] ?? 0), 'PKR') }}
Cards + active debts
Inventory Value
{{ $metrics->money($inventory->sum('pkr_value'), 'PKR') }}
{{ number_format($inventory->sum('stock')) }} units in source inventory
Bank Balance
{{ $metrics->money($bankAccounts->sum('pkr_balance'), 'PKR') }}
{{ $bankAccounts->count() }} active accounts
Collectibles
{{ $metrics->money($collectibles->sum('pkr_outstanding'), 'PKR') }}
{{ $collectibles->count() }} open / partial
Store Credit Outstanding
{{ $metrics->money(($assets['store_credit_amount'] ?? 0), 'PKR') }}
From finance dashboard source
Financials & Growth Core Revenue, expenses and profit trend - last 6 months
Revenue vs Expenses
Monthly, last 6 months (PKR)
@foreach($trend['labels'] as $i => $label)
@php
$revenueHeight = max(3, ((float) $trend['revenue'][$i] / $trendMax) * 150);
$expenseHeight = max(3, ((float) $trend['expenses'][$i] / $trendMax) * 150);
@endphp
{{ \Illuminate\Support\Str::before($label, ' ') }}
@endforeach
Revenue
Expenses
Net Profit & Margin
Monthly profit bars with margin shown in the titles
@foreach($trend['labels'] as $i => $label)
@php
$net = (float) $trend['revenue'][$i] - (float) $trend['expenses'][$i];
$margin = (float) $trend['revenue'][$i] > 0 ? ($net / (float) $trend['revenue'][$i]) * 100 : 0;
$netHeight = max(3, (abs($net) / $trendMax) * 150);
@endphp
{{ \Illuminate\Support\Str::before($label, ' ') }}
@endforeach
Net Worth Composition
Assets minus liabilities = {{ $metrics->money($closing->net_worth, 'PKR') }}
@foreach($netWorthItems as $item)
@php
$width = max(3, (abs((float) $item['amount']) / $netWorthMax) * 100);
$isNegative = (float) $item['amount'] < 0;
@endphp
{{ $item['label'] }}
@if(abs((float) $item['amount']) > 0)
{{ $metrics->money(abs((float) $item['amount']), 'PKR') }}
@endif
{{ $isNegative ? '-' : '' }}{{ $metrics->money(abs((float) $item['amount']), 'PKR') }}
@endforeach
Net worth
{{ $metrics->money($closing->net_worth, 'PKR') }}
Expense Breakdown
This month, by category
@forelse($expenseBreakdown->take(8)->values() as $i => $row)
@php $share = ((float) $row['amount_pkr'] / $expenseTotal) * 100; @endphp
{{ $row['label'] }}
{{ $metrics->money($row['amount_pkr'], 'PKR') }}
@empty
No expenses recorded for this period.
@endforelse
Bank Balances by Account Live Across all regions, PKR-equivalent shown for comparison
@foreach($bankAccounts->groupBy('currency') as $currency => $rows)
{{ $currency === 'PKR' ? 'Pakistan Banks' : ($currency === 'AUD' ? 'Australian Banks' : 'US Banks') }} ({{ $currency }})
{{ $metrics->money($rows->sum('native_balance'), $currency) }}
{{ $metrics->money($rows->sum('pkr_balance'), 'PKR') }} equivalent - {{ $rows->count() }} accounts
@endforeach
Account Balances
Account Group Bank Native Balance PKR Eq.
@foreach($bankAccounts->sortByDesc('pkr_balance') as $row)
{{ $row['name'] }} {{ $row['category'] }} {{ $row['bank'] }} {{ $metrics->money($row['native_balance'], $row['currency']) }} {{ $metrics->money($row['pkr_balance'], 'PKR') }}
@endforeach
Credit Cards & Payment Providers Liability and settlement pipeline
Credit Card Utilisation
Card Payable Limit Util.
@foreach($creditCards as $card)
{{ $card['name'] }} {{ $metrics->money($card['payable'], $card['currency']) }} {{ $metrics->money($card['limit'], $card['currency']) }} {{ number_format($card['utilization'], 1) }}%
@endforeach
Payment Provider Pipeline
Provider Collected Today Pending Settlement
@foreach($providers as $provider)
{{ $provider['name'] }} {{ $metrics->money($provider['collected'], 'PKR') }} {{ $metrics->money($provider['pending'], 'PKR') }}
@endforeach
Product Performance Product Sales volume, profit, and inventory on month-end closing
Units Sold by Product
Vouchers sold this period
@forelse($productSoldRows as $row)
@php $width = max(2, ((float) $row['sold'] / $productSoldMax) * 100); @endphp
{{ $row['name'] }}
{{ number_format((float) $row['sold']) }} vouchers
@empty
No product sales found for this period.
@endforelse
Estimated Profit by Product
(Avg selling - avg buying - points) x sold (PKR)
@forelse($productProfitRows as $row)
@php
$profit = (float) ($row['profit_pkr'] ?? 0);
$width = max(2, (abs($profit) / $productProfitMax) * 100);
@endphp
{{ $row['name'] }}
{{ $profit < 0 ? '-' : '' }}{{ $metrics->money(abs($profit), 'PKR') }}
@empty
No product profit rows found for this period.
@endforelse
Inventory Value on Closing
Stock held at month-end, by product (PKR)
@forelse($inventoryChartRows as $row)
@php $width = max(2, ((float) $row['pkr_value'] / $inventoryChartMax) * 100); @endphp
{{ $row['name'] }}
{{ $metrics->money($row['pkr_value'], 'PKR') }}
@empty
No inventory value found.
@endforelse
Product Ledger
Product Orders Sold Revenue COGS Profit Avg Selling / Voucher
@forelse($products as $row)
{{ $row['name'] }}
{{ $row['orders'] }}
{{ number_format($row['sold']) }}
{{ $metrics->money($row['revenue_pkr'], 'PKR') }}
{{ $metrics->money($row['cogs_pkr'] ?? 0, 'PKR') }}
{{ $metrics->money($row['profit_pkr'] ?? 0, 'PKR') }}
{{ $metrics->money($row['avg_selling_pkr'], 'PKR') }}
@empty
No invoice product rows for this period.
@endforelse
Inventory Value On Closing
Product In Stock Avg Cost Inventory Value
@foreach($inventory->sortByDesc('pkr_value') as $row)
{{ $row['name'] }} {{ number_format($row['stock']) }} {{ $metrics->money($row['cost_price'], $row['currency']) }} {{ $metrics->money($row['pkr_value'], 'PKR') }}
@endforeach
Top Buying Clients Highest-volume clients per product
{{ $topClients->first()['product'] ?? 'Product' }} - Top Clients
{{ $topClients->count() }} active client{{ $topClients->count() === 1 ? '' : 's' }} ranked by voucher usage
Client Institute Orders Vouchers Last Order
@forelse($topClients as $row)
{{ $row['client'] }}
{{ $row['institute'] ?: '-' }}
{{ number_format((int) $row['orders']) }}
{{ number_format((float) $row['vouchers']) }}
{{ ! empty($row['last_order']) ? \Illuminate\Support\Carbon::parse($row['last_order'])->format('d M') : '-' }}
@empty
No portal client rows found for this period.
@endforelse
Client rows are pulled from the portal point ledger for this closed month.
Direct Student Sales (B2C) Retail Channel Vouchers sold directly to students, not through agents/institutes
Direct Student Orders
{{ number_format((int) $b2c['orders']) }}
@if($b2c['orders_delta'] !== null)
{{ (float) $b2c['orders_delta'] >= 0 ? '+' : '' }}{{ number_format((float) $b2c['orders_delta'], 1) }}% vs prev. month
@else
No previous month
@endif
Total B2C Profit (Mo.)
{{ $metrics->money($b2c['profit'], 'PKR') }}
From direct student orders
B2C Revenue (Mo.)
{{ $metrics->money($b2c['revenue'], 'PKR') }}
Gross sales to students
Avg Profit / Voucher
{{ $metrics->money($b2c['avg_profit_per_voucher'], 'PKR') }}
{{ number_format((int) $b2c['vouchers']) }} direct vouchers
B2C Orders by Month
Direct student orders - last 6 months
@foreach(($b2c['trend']['labels'] ?? []) as $i => $label)
@php $height = max(3, ((float) ($b2c['trend']['orders'][$i] ?? 0) / $b2cOrderMax) * 150); @endphp
{{ \Illuminate\Support\Str::before($label, ' ') }}
@endforeach
B2C Profit by Month
Profit from direct student sales - last 6 months (PKR)
@foreach(($b2c['trend']['labels'] ?? []) as $i => $label)
@php
$profit = (float) ($b2c['trend']['profit'][$i] ?? 0);
$height = max(3, (abs($profit) / $b2cProfitMax) * 150);
@endphp
{{ \Illuminate\Support\Str::before($label, ' ') }}
@endforeach
Per-Voucher Direct Profit by Product
Product Direct Orders Student Price Avg Buying Profit / Voucher Total Direct Profit
@forelse($b2c['products'] as $row)
{{ $row['product'] }}
{{ number_format((int) $row['direct_orders']) }}
{{ $metrics->money($row['student_price'], 'PKR') }}
{{ $metrics->money($row['avg_buying'], 'PKR') }}
{{ $metrics->money($row['profit_per_voucher'], 'PKR') }}
{{ $metrics->money($row['total_profit'], 'PKR') }}
@empty
No direct student sales found for this period.
@endforelse
Points Issued Quarterly / Yearly Product-wise and agent-wise points redemption tracking
Points by Product
Quarterly vs yearly issued (PKR)
@forelse($pointProductRows as $row)
@php
$quarterHeight = max(3, ((float) ($row['quarterly'] ?? 0) / $pointProductMax) * 150);
$yearHeight = max(3, ((float) ($row['yearly'] ?? 0) / $pointProductMax) * 150);
@endphp
{{ \Illuminate\Support\Str::limit($row['product'], 10) }}
@empty
No points issued for this period.
@endforelse
Quarterly
Yearly
{{ $pointProductRows->first()['product'] ?? 'Product' }} Points Summary
{{ $closing->month->format('F Y') }} issued and redeemed points
Quarterly Points
{{ $metrics->money($points['summary']['quarterly'] ?? 0, 'PKR') }}
Yearly Points
{{ $metrics->money($points['summary']['yearly'] ?? 0, 'PKR') }}
Total Points
{{ $metrics->money($points['summary']['total'] ?? 0, 'PKR') }}
Redeemed Points
{{ $metrics->money($points['summary']['redeemed'] ?? 0, 'PKR') }}
Profit / Voucher
{{ $metrics->money($pointProductRows->first()['profit_per_voucher'] ?? 0, 'PKR') }}
Total Profit
{{ $metrics->money($products->sum('profit_pkr'), 'PKR') }}
Agent-wise Targets & Achievement
Agent Institute Achieved Target Progress Yearly Target Avg Selling Profit / Voucher
@forelse($points['agent_targets'] as $row)
@php
$target = max(1, (float) ($row['target'] ?? 0));
$achieved = (float) ($row['achieved'] ?? 0);
$progress = min(100, ($achieved / $target) * 100);
@endphp
{{ $row['agent'] }}
{{ $row['institute'] ?: '-' }}
{{ number_format($achieved) }}/{{ number_format($target) }}
{{ number_format($progress, 0) }}%
{{ $metrics->money($row['yearly_target'] ?? 0, 'PKR') }}
{{ $metrics->money($row['avg_selling'] ?? 0, 'PKR') }}
{{ $metrics->money($row['profit_per_voucher'] ?? 0, 'PKR') }}
@empty
No agent point targets found for this period.
@endforelse
Support & Tickets Needs Support-Desk Feed Ticket volume, response and resolution SLAs
Tickets Opened
{{ number_format((int) $support['tickets_opened']) }}
Tickets Resolved
{{ number_format((int) $support['tickets_resolved']) }}
Avg First Response
{{ $support['avg_first_response'] }}
Avg Resolution Time
{{ $support['avg_resolution_time'] }}
@if(! $support['connected'])
No support-desk database/feed is connected in this app yet. The report section is ready and will populate when a ticket source is added.
@endif
Receivables, Debts & Giving Collectibles, active debts, factory, charity and zakaat
Factory Revenue
{{ $metrics->money($factory['revenue'], 'PKR') }}
Factory Expense
{{ $metrics->money($factory['expense'], 'PKR') }}
Zakaat Estimate
{{ $metrics->money($factory['zakat'], 'PKR') }}
2.5% of positive net worth
Charity Estimate
{{ $metrics->money($factory['charity'], 'PKR') }}
2% of positive net profit
Open Collectibles
Party Outstanding Due
@forelse($collectibles as $row)
{{ $row['party'] }}{{ $row['business'] ? ' · '.$row['business'] : '' }} {{ $metrics->money($row['outstanding'], $row['currency']) }} {{ $row['due'] }}
@empty
No open collectibles.
@endforelse
Active Debts
Debt Type Outstanding
@forelse($debts as $row)
{{ $row['name'] }}{{ $row['lender'] ? ' · '.$row['lender'] : '' }} {{ $row['type'] }} {{ $metrics->money($row['amount'], $row['currency']) }}
@empty
No active debts.
@endforelse
Closing Checklist
Account Type Status
@foreach($status['rows'] as $row)
{{ $row['name'] }}
{{ $row['subtitle'] }}
{{ $row['type_label'] ?? ($row['kind'] === 'bank' ? 'Bank' : 'Credit') }}
@if($row['is_closed'])Closed {{ $row['closing']?->closed_at?->format('d M Y') }} @elseOpen @endif
@endforeach
Report Notes
This report is generated from the locked monthly closing snapshot and the finance database records available for the same period.
Closing KPIs use the saved snapshot; live balance-sheet sections use current account, debt, card, inventory, provider and collectible records.
@endsection