recipient_id)) { return $provider->recipient_id; } $metadata = $data['recipient_metadata'] ?? []; $paymentMode = $data['recipient_payment_mode']; $recipientCode = $this->ensureRecipientCode($provider); $addressParts = $this->extractAddressParts($data); $registerInformation = new PagarmeRecipientRegisterInformationData( name: $data['recipient_name'], email: $data['recipient_email'], document: $this->onlyDigits($data['recipient_document'] ?? null), type: $data['recipient_type'] ?? 'individual', birthdate: $this->formatBirthdate($data['birth_date'] ?? null), monthlyIncome: isset($data['monthly_income']) ? (int) $data['monthly_income'] : 1000, professionalOccupation: $data['professional_occupation'] ?? 'autonomo', phoneNumbers: new PagarmeRecipientPhoneNumbersData( $this->buildRecipientPhone($data['phone'] ?? null), ), address: new PagarmeRecipientAddressData( street: $data['address'], complementary: $addressParts['complementary'], streetNumber: $addressParts['street_number'], neighborhood: $addressParts['neighborhood'], city: $data['city'] ?? null, state: $data['state'] ?? null, zipCode: $this->onlyDigits($data['zip_code'] ?? null), referencePoint: $addressParts['reference_point'], ), ); $defaultBankAccount = $this->buildRecipientBankAccount( $data['recipient_default_bank_account'], ); $payload = new PagarmeRecipientRequestData( code: $recipientCode, registerInformation: $registerInformation, defaultBankAccount: $defaultBankAccount, transferSettings: new PagarmeRecipientTransferSettingsData( transferEnabled: false, transferInterval: 'Daily', transferDay: 0, ), automaticAnticipationSettings: new PagarmeRecipientAutomaticAnticipationSettingsData( enabled: false, ), ); $bankAccountData = $payload->defaultBankAccount->toArray(); $raw = $this->pagarmeRequest( method: 'POST', path: '/recipients', payload: $payload, idempotencyKey: $this->idempotencyKey($provider->id), errorMessage: 'Erro ao criar recebedor no Pagar.me.', ); $recipientData = $this->buildRecipientResponse($raw); $recipientId = $recipientData->requireId(); $provider->forceFill([ 'recipient_id' => $recipientId, 'recipient_name' => $data['recipient_name'], 'recipient_email' => $data['recipient_email'], 'recipient_description' => $data['recipient_description'], 'recipient_document' => $data['recipient_document'], 'recipient_type' => $payload->registerInformation->type, 'recipient_code' => $recipientCode, 'recipient_payment_mode' => $paymentMode, 'recipient_default_bank_account' => $bankAccountData, 'recipient_transfer_settings' => [ 'transfer_enabled' => false, 'transfer_interval' => 'daily', 'transfer_day' => 0, ], 'recipient_automatic_anticipation_settings' => [ 'enabled' => false, ], 'recipient_metadata' => $metadata, ])->save(); return $recipientId; } public function updateDefaultBankAccount(Provider $provider, array $bankAccountData): Provider { $payload = new PagarmeBankAccountUpdateRequestData( holderName: $this->normalizeHolderName($bankAccountData['holder_name']), holderType: $bankAccountData['holder_type'], holderDocument: $this->onlyDigits($bankAccountData['holder_document']), bank: $bankAccountData['bank'], branchNumber: $bankAccountData['branch_number'], branchCheckDigit: $bankAccountData['branch_check_digit'] ?? null, accountNumber: $bankAccountData['account_number'], accountCheckDigit: $bankAccountData['account_check_digit'], type: $bankAccountData['type'], ); $raw = $this->pagarmeRequest( method: 'PATCH', path: "/recipients/{$provider->recipient_id}/default-bank-account", payload: $payload, idempotencyKey: $this->idempotencyKey($provider->id, 'default-bank-account-'.sha1(json_encode($payload->toArray()))), errorMessage: 'Erro ao atualizar conta bancaria do recebedor no Pagar.me.', ); $recipientData = $this->buildRecipientResponse($raw); $provider->forceFill([ 'recipient_default_bank_account' => $recipientData->defaultBankAccount()?->toArray() ?: $payload->toArray()['bank_account'], ])->save(); return $provider->fresh(); } // private function buildRecipientBankAccount(array $data): PagarmeRecipientBankAccountData { return new PagarmeRecipientBankAccountData( holderName: $this->normalizeHolderName($data['holder_name']), holderType: $data['holder_type'], holderDocument: $this->onlyDigits($data['holder_document']), bank: $data['bank'], branchNumber: $data['branch_number'], branchCheckDigit: $data['branch_check_digit'] ?? null, accountNumber: $data['account_number'], accountCheckDigit: $data['account_check_digit'], type: $data['type'], ); } private function buildRecipientPhone(?string $phone): PagarmeRecipientPhoneData { $digits = $this->onlyDigits($phone); if (strlen($digits) < 10) { return new PagarmeRecipientPhoneData( ddd: '11', number: '999999999', type: 'mobile', ); } if (str_starts_with($digits, '55')) { $digits = substr($digits, 2); } return new PagarmeRecipientPhoneData( ddd: substr($digits, 0, 2), number: substr($digits, 2), type: 'mobile', ); } private function extractAddressParts(array $data): array { $addressLine = trim((string) ($data['address'] ?? '')); $segments = array_map('trim', explode(',', $addressLine)); $streetSegment = $segments[0] ?? ''; if (($data['number'] ?? null) === null) { preg_match('/^(\d+)/', $streetSegment, $matches); } return [ 'street_number' => (string) ($data['number'] ?? $matches[1] ?? 'S/N'), 'neighborhood' => (string) ($data['district'] ?? $segments[1] ?? 'N/A'), 'reference_point' => (string) ($data['reference_point'] ?? 'N/A'), 'complementary' => (string) ($data['complement'] ?? 'N/A'), ]; } private function formatBirthdate(mixed $birthdate): ?string { if ($birthdate === null || $birthdate === '') { return null; } if ($birthdate instanceof \DateTimeInterface) { return Carbon::instance($birthdate)->format('d/m/Y'); } $birthdate = trim((string) $birthdate); if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $birthdate) === 1) { return $birthdate; } if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $birthdate) === 1) { return Carbon::createFromFormat('Y-m-d', $birthdate)->format('d/m/Y'); } return Carbon::parse($birthdate)->format('d/m/Y'); } private function normalizeHolderName(string $holderName): string { $holderName = trim(preg_replace('/\s+/', ' ', $holderName) ?? ''); if (Str::length($holderName) < 30) { return $holderName; } $parts = explode(' ', $holderName); if (count($parts) >= 3) { $firstName = array_shift($parts); $lastName = array_pop($parts); $initials = array_map( static fn (string $part): string => Str::upper(Str::substr($part, 0, 1)), $parts ); $abbreviated = trim($firstName.' '.implode(' ', $initials).' '.$lastName); if (Str::length($abbreviated) < 30) { return $abbreviated; } $firstAndLast = trim($firstName.' '.$lastName); if (Str::length($firstAndLast) < 30) { return $firstAndLast; } } return Str::limit($holderName, 29, ''); } private function buildRecipientResponse(array $raw): PagarmeRecipientResponseData { return new PagarmeRecipientResponseData( id: $raw['id'] ?? null, name: $raw['name'] ?? null, email: $raw['email'] ?? null, document: $raw['document'] ?? null, type: $raw['type'] ?? null, status: $raw['status'] ?? null, defaultBankAccount: ! empty($raw['default_bank_account']) ? new PagarmeRecipientBankAccountResponseData( holderName: $raw['default_bank_account']['holder_name'] ?? null, holderType: $raw['default_bank_account']['holder_type'] ?? null, holderDocument: $raw['default_bank_account']['holder_document'] ?? null, bank: $raw['default_bank_account']['bank'] ?? null, branchNumber: $raw['default_bank_account']['branch_number'] ?? null, branchCheckDigit: $raw['default_bank_account']['branch_check_digit'] ?? null, accountNumber: $raw['default_bank_account']['account_number'] ?? null, accountCheckDigit: $raw['default_bank_account']['account_check_digit'] ?? null, type: $raw['default_bank_account']['type'] ?? null, ) : null, createdAt: $raw['created_at'] ?? null, updatedAt: $raw['updated_at'] ?? null, ); } private function onlyDigits(?string $value): string { return preg_replace('/\D+/', '', (string) $value) ?? ''; } // evita criacao duplica de recipient private function idempotencyKey(int $providerId, string $suffix = 'recipient'): string { return "provider-{$providerId}-{$suffix}"; } private function ensureRecipientCode(Provider $provider): string { if (! empty($provider->recipient_code)) { return $provider->recipient_code; } $recipientCode = 'provider-'.(string) Str::uuid(); $provider->forceFill(['recipient_code' => $recipientCode])->save(); return $recipientCode; } }