Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
AdminFundManagementService
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 9
380
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 createFund
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
30
 updateFund
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
42
 publishFund
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 unpublishFund
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 archiveFund
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getAllFunds
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPublishedFunds
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFundDetails
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3declare(strict_types=1);
4
5namespace App\Domain\Admin\Service;
6
7use App\Domain\Funds\Data\FundData;
8use App\Domain\Funds\Repository\FundsRepository;
9use InvalidArgumentException;
10
11final readonly class AdminFundManagementService
12{
13    public function __construct(
14        private FundsRepository $fundsRepository,
15    ) {
16    }
17
18    /**
19     * Create a new fund
20     */
21    public function createFund(array $fundData): FundData
22    {
23        $requiredFields = ['name', 'type', 'status', 'heroImageUrl', 'aum', 'minInvestment'];
24        foreach ($requiredFields as $field) {
25            if (empty($fundData[$field])) {
26                throw new InvalidArgumentException("Required field missing: $field");
27            }
28        }
29
30        // Validate fund type
31        $validTypes = ['private_equity', 'credit', 'real_assets', 'real_estate', 'hedge', 'other'];
32        if (!in_array($fundData['type'], $validTypes)) {
33            throw new InvalidArgumentException('Invalid fund type: ' . $fundData['type']);
34        }
35
36        // Validate status
37        $validStatuses = ['active', 'raising', 'closed', 'coming_soon'];
38        if (!in_array($fundData['status'], $validStatuses)) {
39            throw new InvalidArgumentException('Invalid status: ' . $fundData['status']);
40        }
41
42        return $this->fundsRepository->create($fundData);
43    }
44
45    /**
46     * Update existing fund
47     */
48    public function updateFund(string $fundId, array $updates): FundData
49    {
50        // Verify fund exists
51        $fund = $this->fundsRepository->findById($fundId);
52        if (!$fund) {
53            throw new InvalidArgumentException('Fund not found: ' . $fundId);
54        }
55
56        // Validate type if provided
57        if (isset($updates['type'])) {
58            $validTypes = ['private_equity', 'credit', 'real_assets', 'real_estate', 'hedge', 'other'];
59            if (!in_array($updates['type'], $validTypes)) {
60                throw new InvalidArgumentException('Invalid fund type: ' . $updates['type']);
61            }
62        }
63
64        // Validate status if provided
65        if (isset($updates['status'])) {
66            $validStatuses = ['active', 'raising', 'closed', 'coming_soon'];
67            if (!in_array($updates['status'], $validStatuses)) {
68                throw new InvalidArgumentException('Invalid status: ' . $updates['status']);
69            }
70        }
71
72        return $this->fundsRepository->update($fundId, $updates);
73    }
74
75    /**
76     * Publish a fund (make visible to investors)
77     */
78    public function publishFund(string $fundId): FundData
79    {
80        return $this->fundsRepository->update($fundId, ['published' => true]);
81    }
82
83    /**
84     * Unpublish a fund (hide from investors)
85     */
86    public function unpublishFund(string $fundId): FundData
87    {
88        return $this->fundsRepository->update($fundId, ['published' => false]);
89    }
90
91    /**
92     * Archive a fund (soft delete)
93     */
94    public function archiveFund(string $fundId): FundData
95    {
96        return $this->fundsRepository->update($fundId, [
97            'status' => 'closed',
98            'published' => false,
99        ]);
100    }
101
102    /**
103     * Get all funds including unpublished (admin view)
104     */
105    public function getAllFunds(): array
106    {
107        return $this->fundsRepository->findAll();
108    }
109
110    /**
111     * Get published funds only (investor view)
112     */
113    public function getPublishedFunds(): array
114    {
115        return $this->fundsRepository->findPublished();
116    }
117
118    /**
119     * Get fund by ID with full details
120     */
121    public function getFundDetails(string $fundId): FundData
122    {
123        $fund = $this->fundsRepository->findById($fundId);
124        if (!$fund) {
125            throw new InvalidArgumentException('Fund not found: ' . $fundId);
126        }
127        return $fund;
128    }
129}