Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
81.48% covered (warning)
81.48%
22 / 27
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
GetDisbursementHistoryAction
81.48% covered (warning)
81.48%
22 / 27
50.00% covered (danger)
50.00%
1 / 2
11.77
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
 __invoke
80.77% covered (warning)
80.77%
21 / 26
0.00% covered (danger)
0.00%
0 / 1
10.71
1<?php
2
3declare(strict_types=1);
4
5namespace App\Action\Disbursement;
6
7use App\Domain\Disbursement\Service\DisbursementService;
8use App\Domain\Exception\ForbiddenException;
9use App\Domain\Exception\ValidationException;
10use App\Renderer\JsonRenderer;
11use App\Support\Row;
12use Psr\Http\Message\ResponseInterface;
13use Psr\Http\Message\ServerRequestInterface;
14
15final readonly class GetDisbursementHistoryAction
16{
17    private const array ALLOWED_STATUSES = ['disbursed', 'cancelled'];
18
19    public function __construct(
20        private DisbursementService $disbursementService,
21        private JsonRenderer $renderer,
22    ) {}
23
24    public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
25    {
26        $attributes = $request->getAttributes();
27        $role = Row::nullableString($attributes, 'userRole') ?? '';
28        if ($role !== 'admin' && $role !== 'super_admin') {
29            throw new ForbiddenException('Admin access required');
30        }
31
32        $params = $request->getQueryParams();
33        $status = isset($params['status']) && is_string($params['status']) ? $params['status'] : 'disbursed';
34        if (!in_array($status, self::ALLOWED_STATUSES, true)) {
35            throw new ValidationException(sprintf(
36                'status must be one of: %s',
37                implode(', ', self::ALLOWED_STATUSES),
38            ));
39        }
40
41        $page = isset($params['page']) && is_numeric($params['page']) ? (int)$params['page'] : 1;
42        $perPage = isset($params['perPage']) && is_numeric($params['perPage']) ? (int)$params['perPage'] : 20;
43
44        $items = $this->disbursementService->listHistory($status, $page, $perPage);
45        $total = $this->disbursementService->countByStatus($status);
46
47        return $this->renderer->json($response, [
48            'success' => true,
49            'data' => [
50                'disbursements' => array_map(static fn($d): array => $d->toArray(), $items),
51                'pagination' => [
52                    'page' => $page,
53                    'perPage' => $perPage,
54                    'total' => $total,
55                ],
56            ],
57        ]);
58    }
59}