Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
38.64% covered (danger)
38.64%
17 / 44
57.14% covered (warning)
57.14%
4 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
AdminService
38.64% covered (danger)
38.64%
17 / 44
57.14% covered (warning)
57.14%
4 / 7
83.78
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
 getStats
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getInvestorsList
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 getInvestorDetail
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getAllTransactions
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 getLendingActivity
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 getAumHistory
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace App\Domain\Admin\Service;
6
7use App\Domain\Account\Data\BalanceHistoryPointData;
8use App\Domain\Admin\Data\AdminStatsData;
9use App\Domain\Admin\Repository\AdminRepository;
10use App\Domain\Exception\NotFoundException;
11
12use function ceil;
13use function max;
14use function min;
15
16/**
17 * Service for admin operations.
18 */
19final class AdminService
20{
21    private AdminRepository $repository;
22
23    public function __construct(AdminRepository $repository)
24    {
25        $this->repository = $repository;
26    }
27
28    /**
29     * Get platform statistics.
30     */
31    public function getStats(): AdminStatsData
32    {
33        return $this->repository->getStats();
34    }
35
36    /**
37     * Get paginated investors list.
38     *
39     * @param int $page
40     * @param int $limit
41     * @param string|null $search
42     * @param string|null $kycStatus
43     * @param string|null $status
44     *
45     * @return array{investors: array<mixed>, total: int, page: int, limit: int}
46     */
47    public function getInvestorsList(
48        int $page = 1,
49        int $limit = 20,
50        ?string $search = null,
51        ?string $kycStatus = null,
52        ?string $status = null,
53    ): array {
54        // Validate pagination
55        if ($page < 1) {
56            $page = 1;
57        }
58        if ($limit < 1 || $limit > 100) {
59            $limit = 20;
60        }
61
62        $result = $this->repository->getInvestorsList($page, $limit, $search, $kycStatus, $status);
63
64        return [
65            'investors' => $result['investors'],
66            'total' => $result['total'],
67            'page' => $page,
68            'limit' => $limit,
69        ];
70    }
71
72    /**
73     * Get detailed investor information.
74     *
75     * @param int $investorId
76     *
77     * @throws NotFoundException If investor not found
78     *
79     * @return array<mixed>
80     */
81    public function getInvestorDetail(int $investorId): array
82    {
83        $investor = $this->repository->getInvestorDetail($investorId);
84
85        if ($investor === null) {
86            throw new NotFoundException('Investor not found');
87        }
88
89        return $investor;
90    }
91
92    /**
93     * Get all transactions platform-wide (paginated, filterable).
94     *
95     * @param int $page
96     * @param int $limit
97     * @param string|null $type
98     * @param string|null $search
99     * @param string|null $startDate
100     * @param string|null $endDate
101     *
102     * @return array{data: array<mixed>, total: int, page: int, limit: int}
103     */
104    public function getAllTransactions(
105        int $page = 1,
106        int $limit = 25,
107        ?string $type = null,
108        ?string $search = null,
109        ?string $startDate = null,
110        ?string $endDate = null,
111    ): array {
112        if ($page < 1) {
113            $page = 1;
114        }
115        if ($limit < 1 || $limit > 100) {
116            $limit = 25;
117        }
118
119        $result = $this->repository->getAllTransactions($page, $limit, $type, $search, $startDate, $endDate);
120
121        return [
122            'data' => $result['data'],
123            'total' => $result['total'],
124            'page' => $page,
125            'limit' => $limit,
126        ];
127    }
128
129    /**
130     * Lending-side activity feed for admin reporting (disbursements + payments).
131     *
132     * @param int $page
133     * @param int $limit
134     * @return array{data: array<mixed>, total: int, page: int, limit: int}
135     */
136    public function getLendingActivity(int $page = 1, int $limit = 25): array
137    {
138        if ($page < 1) {
139            $page = 1;
140        }
141        if ($limit < 1 || $limit > 100) {
142            $limit = 25;
143        }
144
145        $result = $this->repository->getLendingActivity($page, $limit);
146
147        return [
148            'data' => $result['data'],
149            'total' => $result['total'],
150            'page' => $page,
151            'limit' => $limit,
152        ];
153    }
154
155    /**
156     * Get platform-wide AUM balance history for charting.
157     *
158     * @return BalanceHistoryPointData[]
159     */
160    public function getAumHistory(): array
161    {
162        $rows = $this->repository->getAumHistory();
163
164        return array_map(
165            static fn(array $row): BalanceHistoryPointData => new BalanceHistoryPointData($row),
166            $rows,
167        );
168    }
169}