Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
15.38% covered (danger)
15.38%
6 / 39
60.00% covered (warning)
60.00%
6 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
AccountLedgerReport
15.38% covered (danger)
15.38%
6 / 39
60.00% covered (warning)
60.00%
6 / 10
132.74
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 key
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 label
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 group
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 feature
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 description
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 filters
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 columns
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 rows
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
6
 summary
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace App\Reports\Finance;
4
5use App\Models\Account;
6use App\Reports\Report;
7use App\Services\Accounting\AccountingService;
8use Illuminate\Support\Carbon;
9use Illuminate\Support\Collection;
10
11/** The same running ledger as CashBook/Bank Book, but as an exportable report with a date range. */
12class AccountLedgerReport extends Report
13{
14    public function __construct(private readonly AccountingService $accounting) {}
15
16    public function key(): string
17    {
18        return 'account-ledger';
19    }
20
21    public function label(): string
22    {
23        return 'Account Ledger';
24    }
25
26    public function group(): string
27    {
28        return 'Finance';
29    }
30
31    public function feature(): ?string
32    {
33        return 'accounting';
34    }
35
36    public function description(): ?string
37    {
38        return 'Date, particulars, in, out and running balance for one account.';
39    }
40
41    public function filters(): array
42    {
43        $first = Account::orderBy('name')->value('id');
44
45        return [
46            'account_id' => [
47                'type' => 'select', 'label' => 'Account',
48                'options' => Account::orderBy('name')->pluck('name', 'id')->all(),
49                'default' => $first,
50            ],
51        ] + $this->dateRangeFilters();
52    }
53
54    public function columns(): array
55    {
56        return [
57            ['key' => 'date', 'label' => 'Date'],
58            ['key' => 'particulars', 'label' => 'Particulars'],
59            ['key' => 'in', 'label' => 'In', 'align' => 'right', 'render' => fn ($r) => $r->in > 0 ? money($r->in) : '—'],
60            ['key' => 'out', 'label' => 'Out', 'align' => 'right', 'render' => fn ($r) => $r->out > 0 ? money($r->out) : '—'],
61            ['key' => 'balance', 'label' => 'Balance', 'align' => 'right', 'render' => fn ($r) => money($r->balance)],
62        ];
63    }
64
65    public function rows(array $filters): Collection
66    {
67        $account = Account::find($filters['account_id'] ?? null);
68
69        if (! $account) {
70            return collect();
71        }
72
73        $from = Carbon::parse($filters['from']);
74        $to = Carbon::parse($filters['to']);
75
76        return $this->accounting->ledger($account, $from, $to)->map(function ($row) use ($account) {
77            $signed = $row['transaction']->signedAmountFor($account->id);
78
79            return (object) [
80                'date' => $row['transaction']->date->format('d M, Y'),
81                'particulars' => $row['transaction']->category->name ?? ucfirst($row['transaction']->type),
82                'in' => max($signed, 0),
83                'out' => max(-$signed, 0),
84                'balance' => $row['balance'],
85            ];
86        });
87    }
88
89    public function summary(Collection $rows, array $filters): array
90    {
91        return [
92            'Closing Balance' => $rows->isNotEmpty() ? money($rows->last()->balance) : '—',
93        ];
94    }
95}