> */ public function rules(): array { $key = $this->header('Idempotency-Key'); $knownKey = is_string($key) && Str::isUuid($key) && DB::table('interest_submission_receipts')->where('key_hash', hash('sha256', strtolower($key)))->exists(); return [ 'fullName' => ['required', 'string', 'min:3', 'max:150'], 'email' => ['required', 'email:rfc,dns', 'max:150'], 'phone' => ['nullable', 'string', 'max:30'], 'investorType' => ['required', 'string', Rule::in([ 'individual', 'empresa', 'fundo', 'entidade_publica', 'outro', ])], 'country' => ['required', 'string', 'max:100'], 'sectorInterest' => ['required', 'string', 'max:150'], // A known receipt can replay after withdrawal; the service verifies the payload hash. 'opportunityReference' => ['nullable', 'string', 'max:80', ...($knownKey ? [] : [ Rule::exists('opportunities', 'reference')->where(fn ($query) => $query ->where('status', 'published')->whereNotNull('published_at') ->where('published_at', '<=', now())->whereNull('deleted_at')), ])], 'existingBusinessId' => ['nullable', 'uuid', ...($knownKey ? [] : [ Rule::exists('existing_businesses', 'id')->where(fn ($query) => $query ->where('status', 'published')->whereNotNull('published_at')->where('published_at', '<=', now())->whereNull('deleted_at')), ])], 'modality' => ['nullable', 'required_with:existingBusinessId', 'string', 'max:50', Rule::in(ExistingBusinessDrafts::MODALITIES)], 'investmentRange' => ['nullable', 'string', 'max:80'], 'message' => ['required', 'string', 'min:20', 'max:2000'], 'privacyConsent' => ['required', 'accepted'], 'shareWithProponent' => ['sometimes', 'boolean'], ]; } /** @return list */ public function after(): array { return [function (Validator $validator): void { if ($this->filled('existingBusinessId') && $this->filled('opportunityReference')) { $validator->errors()->add('existingBusinessId', 'Seleccione apenas uma oportunidade.'); } }]; } public function messages(): array { return [ 'opportunityReference.exists' => 'A oportunidade seleccionada já não está disponível.', 'fullName.required' => 'O nome completo é obrigatório.', 'email.required' => 'O email é obrigatório.', 'email.email' => 'Indique um email válido.', 'investorType.required' => 'Seleccione o tipo de investidor.', 'country.required' => 'O país é obrigatório.', 'sectorInterest.required' => 'O sector de interesse é obrigatório.', 'message.required' => 'A mensagem é obrigatória.', 'message.min' => 'A mensagem deve ter pelo menos 20 caracteres.', 'privacyConsent.accepted' => 'É necessário aceitar a política de privacidade.', ]; } }