119 lines
5.6 KiB
PHP
119 lines
5.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1;
|
|
|
|
use App\Domain\Interests\Enums\InterestStatus;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\StoreInterestRequestRequest;
|
|
use App\Jobs\NotifyInterestReceived;
|
|
use App\Models\ExistingBusiness;
|
|
use App\Models\InterestRequest;
|
|
use App\Models\Opportunity;
|
|
use App\Services\IdempotencyConflict;
|
|
use App\Services\InterestSubmission;
|
|
use Illuminate\Database\QueryException;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Queue;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class InterestRequestController extends Controller
|
|
{
|
|
public function store(StoreInterestRequestRequest $request, InterestSubmission $submission): JsonResponse
|
|
{
|
|
$validated = $request->validated();
|
|
$key = $request->header('Idempotency-Key');
|
|
Validator::make(['idempotency_key' => $key], ['idempotency_key' => [$key === null ? 'nullable' : 'required', 'uuid']])->validate();
|
|
|
|
try {
|
|
$interestRequest = $submission->receive($validated, $key, function () use ($request, $validated) {
|
|
$opportunity = ! empty($validated['opportunityReference'])
|
|
? Opportunity::published()->where('reference', $validated['opportunityReference'])->first()
|
|
: null;
|
|
if (! empty($validated['opportunityReference']) && ! $opportunity) {
|
|
throw ValidationException::withMessages(['opportunityReference' => 'A oportunidade seleccionada já não está disponível.']);
|
|
}
|
|
|
|
$business = ! empty($validated['existingBusinessId'])
|
|
? ExistingBusiness::published()->whereKey($validated['existingBusinessId'])->first()
|
|
: null;
|
|
if (! empty($validated['existingBusinessId']) && ! $business) {
|
|
throw ValidationException::withMessages(['existingBusinessId' => 'A oportunidade seleccionada já não está disponível.']);
|
|
}
|
|
|
|
$interest = InterestRequest::create([
|
|
'opportunity_id' => $opportunity?->id,
|
|
'existing_business_id' => $business?->id,
|
|
'modality' => $business ? $validated['modality'] : null,
|
|
'reference' => $this->generateReference(),
|
|
'full_name' => trim($validated['fullName']),
|
|
'email' => strtolower(trim($validated['email'])),
|
|
'phone' => $validated['phone'] ?? null,
|
|
'investor_type' => $validated['investorType'],
|
|
'country' => $validated['country'],
|
|
'sector_interest' => $validated['sectorInterest'],
|
|
'opportunity_reference' => $validated['opportunityReference'] ?? null,
|
|
'investment_range' => $validated['investmentRange'] ?? null,
|
|
'message' => trim($validated['message']),
|
|
'privacy_consent' => (bool) $validated['privacyConsent'],
|
|
'consented_at' => now(),
|
|
'status' => InterestStatus::Received->value,
|
|
'source_page' => Str::limit($request->headers->get('referer', ''), 255, ''),
|
|
'ip_address' => $request->ip(),
|
|
'user_agent' => $request->userAgent(),
|
|
]);
|
|
if (config('portal.notifications_enabled')) {
|
|
$connection = config('queue.connections.database.connection');
|
|
if (config('queue.connections.database.after_commit') || ($connection && $connection !== config('database.default'))) {
|
|
throw new \RuntimeException('Portal notifications require the transactional database queue.');
|
|
}
|
|
foreach (array_unique(config('portal.notification_recipients')) as $recipient) {
|
|
if (filter_var($recipient, FILTER_VALIDATE_EMAIL)) {
|
|
Queue::connection('database')->push(new NotifyInterestReceived($interest->id, $recipient));
|
|
}
|
|
}
|
|
}
|
|
|
|
return $interest;
|
|
});
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Manifestação de interesse registada com sucesso.',
|
|
'data' => [
|
|
'reference' => $interestRequest->reference,
|
|
'status' => 'received',
|
|
],
|
|
], 201);
|
|
} catch (IdempotencyConflict) {
|
|
return response()->json(['success' => false, 'message' => 'A chave de envio já foi usada com dados diferentes.'], 409);
|
|
} catch (ValidationException $exception) {
|
|
throw $exception;
|
|
} catch (QueryException $exception) {
|
|
if ($exception->getCode() === '23505') {
|
|
return response()->json(['success' => false, 'message' => 'Já existe uma manifestação activa para esta oportunidade e modalidade.'], 409);
|
|
}
|
|
|
|
throw $exception;
|
|
} catch (\Throwable $exception) {
|
|
Log::error('Erro ao registar manifestação de interesse', [
|
|
'exception_type' => $exception::class,
|
|
]);
|
|
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Não foi possível registar o pedido. Tente novamente mais tarde.',
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
private function generateReference(): string
|
|
{
|
|
$year = now()->format('Y');
|
|
|
|
return 'IR-'.$year.'-'.Str::ulid();
|
|
}
|
|
}
|