Preserve selected portfolio context through investment preparation

This commit is contained in:
2026-10-23 14:35:50 +02:00
parent 6948ed62fc
commit 3d877ec745
16 changed files with 271 additions and 28 deletions
@@ -11,6 +11,19 @@ use Inertia\Inertia;
final class InvestorContextController extends Controller
{
private function entryChoices(Request $r, InvestorContext $context): array
{
$data = $r->validate(['source' => 'nullable|string|max:100', 'from_dossier' => 'nullable|uuid', 'opportunities' => 'sometimes|array|max:100', 'opportunities.*' => 'integer|distinct|min:1',
'province_id' => 'nullable|uuid', 'district_id' => 'nullable|uuid', 'admin_post_id' => 'nullable|uuid', 'locality_id' => 'nullable|uuid']);
$source = !empty($data['source']) ? $context->reference($data['source']) : null;
$ids = $data['opportunities'] ?? (($source['kind'] ?? '') === 'opportunity' ? [$source['id']] : []);
abort_if(!empty($data['from_dossier']) && !$ids, 422, 'Escolha a oportunidade associada à ficha da carteira.');
$path = app(InvestmentGeography::class)->selection($data);
$input = array_map(fn($id) => ['source' => 'opportunity:'.$id, ...($path ? ['territory' => 'territory:'.$path[array_key_last($path)]->id] : [])], $ids);
if (!empty($data['from_dossier'])) $input[0]['portfolio_origins'] = [$data['from_dossier']];
return app(\App\Services\InvestmentOpportunityChoices::class)->resolve($input, [], true);
}
public function current(Request $r, InvestorContext $context)
{
return response()->json($context->current($r->user()));
@@ -51,22 +64,27 @@ final class InvestorContextController extends Controller
$data = $context->view($r->user(), $id);
abort_unless($data['can_write'], 403);
$ids = $r->validate(['opportunities' => 'sometimes|array|max:100', 'opportunities.*' => 'integer|distinct|min:1'])['opportunities'] ?? [];
$choices = $ids ? app(\App\Services\InvestmentOpportunityChoices::class)->resolve(array_map(fn ($id) => ['source' => 'opportunity:'.$id], $ids)) : null;
$entries = $this->entryChoices($r, $context);
$choices = $entries ?: null;
$source = $r->query('source') ? $context->reference($r->validate(['source' => 'required|string|max:100'])['source']) : null;
if ($choices === null && ($source['kind'] ?? '') === 'opportunity') $choices = app(\App\Services\InvestmentOpportunityChoices::class)->resolve([['source' => $source['key']]]);
$explicitChoices=$choices;
$selectionKey=$r->validate(['selection_key'=>'nullable|uuid'])['selection_key']??null;
$entryKey=fn($c)=>$c['opportunity']['key'].($selectionKey?'@'.$selectionKey:'');
$entrySources=array_map($entryKey,$explicitChoices??[]);
if ($choices !== null) $choices = collect([...($data['context']['opportunity_choices'] ?? []), ...$choices])->unique(fn ($choice) => $choice['opportunity']['key'])->values()->all();
if ($choices !== null) $choices = app(\App\Services\InvestmentOpportunityChoices::class)->mergeEntries($data['context']['opportunity_choices'] ?? [], $choices);
$draft = $context->draft($r->user(), $id);
if ($draft && isset($draft['opportunity_choices'])) {
$recovered = app(\App\Services\InvestmentOpportunityChoices::class)->resolve($draft['opportunity_choices'], $data['context']['opportunity_choices'] ?? [], true);
$new=array_filter($explicitChoices??[],fn($c)=>!in_array($entryKey($c),$draft['entry_sources']??[],true));
$choices = collect([...$recovered, ...$new])->unique(fn($c)=>$c['opportunity']['key'])->values()->all();
$choices = app(\App\Services\InvestmentOpportunityChoices::class)->mergeEntries($recovered, array_values($new));
}
return Inertia::render('investor-path/context', ['entrySources'=>$entrySources,'draft' => $draft, 'requestedChoices' => $choices, 'initial' => $data, 'options' => $context->options(), 'source' => $source, 'territorySelection' => isset($data['context']['selection']['territory']) ? app(InvestmentGeography::class)->path($data['context']['selection']['territory']['id']) : []]);
$differences = [];
foreach ($explicitChoices ?? [] as $entry) {
$kept = collect($choices ?? [])->firstWhere('opportunity.key', $entry['opportunity']['key']);
if ($kept && ($kept['territory']['key'] ?? null) !== ($entry['territory']['key'] ?? null)) $differences[] = ['title'=>$entry['opportunity']['title'],'saved'=>$kept['territory']['title']??'Por definir','requested'=>$entry['territory']['title']??'Por definir'];
}
return Inertia::render('investor-path/context', ['entryLocationDifferences'=>$differences,'entrySources'=>$entrySources,'draft' => $draft, 'requestedChoices' => $choices, 'initial' => $data, 'options' => $context->options(), 'source' => $source, 'territorySelection' => isset($data['context']['selection']['territory']) ? app(InvestmentGeography::class)->path($data['context']['selection']['territory']['id']) : []]);
}
public function preview(Request $r, string $id, InvestorContext $context)
@@ -84,9 +102,8 @@ final class InvestorContextController extends Controller
$d = $r->validate(['source' => 'nullable|string|max:100', 'step' => ['nullable', 'regex:/^S(0[1-9]|1[0-9])$/']]);
$ref = isset($d['source']) ? $context->reference($d['source']) : null;
$ids = $r->validate(['opportunities' => 'sometimes|array|max:100', 'opportunities.*' => 'integer|distinct|min:1'])['opportunities'] ?? [];
$choices = $ids ? app(\App\Services\InvestmentOpportunityChoices::class)->resolve(array_map(fn ($id) => ['source' => 'opportunity:'.$id], $ids)) : [];
return Inertia::render('investor-path/context-start', ['opportunityChoices' => $choices, 'contexts' => $path->contexts($r->user()), 'source' => $ref, 'step' => $d['step'] ?? null]);
$choices = $this->entryChoices($r, $context);
return Inertia::render('investor-path/context-start', ['entryQuery' => $r->only(['from_dossier', 'province_id', 'district_id', 'admin_post_id', 'locality_id']), 'opportunityChoices' => $choices, 'contexts' => $path->contexts($r->user()), 'source' => $ref, 'step' => $d['step'] ?? null]);
}
public function installation(Request $r, InvestorContextInstallation $install)