72 lines
3.8 KiB
PHP
72 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\EducationInvestmentProposal;
|
|
use App\Models\LabourDemand;
|
|
use App\Models\Opportunity;
|
|
use App\Services\InvestmentGeography;
|
|
use App\Services\PortalAudit;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class EducationInvestmentController extends Controller
|
|
{
|
|
public function store(Request $request, string $id): RedirectResponse
|
|
{
|
|
$data = $request->validate([
|
|
'demand_version' => ['required', 'integer', 'min:1'],
|
|
'sector_id' => ['required', 'integer', Rule::exists('sectors', 'id')->whereNull('deleted_at')],
|
|
'title' => ['required', 'string', 'max:200'],
|
|
'intervention' => ['required', 'string', 'min:20', 'max:10000'],
|
|
'equipment_needs' => ['nullable', 'string', 'max:5000'],
|
|
'trainer_needs' => ['nullable', 'string', 'max:5000'],
|
|
'funding_plan' => ['nullable', 'string', 'max:5000'],
|
|
'risks' => ['required', 'string', 'min:10', 'max:5000'],
|
|
'source' => ['required', 'string', 'min:10', 'max:5000'],
|
|
'currency' => ['required', Rule::in(['MZN', 'USD', 'EUR', 'ZAR'])],
|
|
'province_id' => ['required', 'uuid'],
|
|
'district_id' => ['nullable', 'uuid'],
|
|
'admin_post_id' => ['nullable', 'uuid'],
|
|
'locality_id' => ['nullable', 'uuid'],
|
|
]);
|
|
|
|
DB::transaction(function () use ($request, $id, $data): void {
|
|
$demand = LabourDemand::whereKey($id)->lockForUpdate()->firstOrFail();
|
|
abort_unless((int) $demand->getAttribute('version_no') === $data['demand_version'], 409, 'A procura foi alterada. Recarregue a análise.');
|
|
abort_unless($demand->getAttribute('status') === 'reviewed' && $demand->getAttribute('valid_until') >= now()->toDateString(),
|
|
422, 'A proposta exige procura revista e fonte vigente.');
|
|
// Serialising on the demand and unique FKs make repeated submissions safe.
|
|
if (EducationInvestmentProposal::withTrashed()->where('labour_demand_id', $id)->exists()) {
|
|
return;
|
|
}
|
|
$territory = app(InvestmentGeography::class)->selection($data, true);
|
|
$province = $territory[0];
|
|
$district = $territory[1] ?? null;
|
|
$primaryTerritory = $territory[array_key_last($territory)];
|
|
$reference = 'EDU-'.Str::uuid();
|
|
$opportunity = new Opportunity;
|
|
PortalAudit::save($opportunity, [
|
|
'sector_id' => $data['sector_id'], 'reference' => $reference,
|
|
'slug' => strtolower($reference), 'title' => $data['title'],
|
|
'summary' => 'Proposta educativa em preparação. Lacuna e viabilidade pendentes de validação institucional.',
|
|
'description' => $data['intervention'], 'estimated_investment_currency' => $data['currency'],
|
|
'province' => $province->name, 'district' => $district?->name,
|
|
'primary_territory_id' => $primaryTerritory->id, 'territory_version' => 1,
|
|
'status' => 'draft', 'is_featured' => false,
|
|
], $request->user()->id);
|
|
PortalAudit::save(new EducationInvestmentProposal, [
|
|
'labour_demand_id' => $id, 'demand_version' => $data['demand_version'],
|
|
'opportunity_id' => $opportunity->id, 'created_by' => $request->user()->id,
|
|
...array_intersect_key($data, array_flip(['intervention', 'equipment_needs', 'trainer_needs', 'funding_plan', 'risks', 'source'])),
|
|
], $request->user()->id);
|
|
});
|
|
|
|
return redirect('/management/education/demands/'.$id.'/analysis')
|
|
->with('success', 'Ficha educativa guardada em rascunho. Publicação sujeita a validação institucional.');
|
|
}
|
|
}
|