| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- <?php
- namespace App\Services\Pagarme;
- use App\Data\Pagarme\Request\PagarmeBankAccountUpdateRequestData;
- use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientAutomaticAnticipationSettingsData;
- use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientBankAccountData;
- use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientAddressData;
- use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientPhoneNumbersData\PagarmeRecipientPhoneData;
- use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientPhoneNumbersData\PagarmeRecipientPhoneNumbersData;
- use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientRegisterInformationData;
- use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRequestData;
- use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientTransferSettingsData;
- use App\Data\Pagarme\Response\PagarmeRecipientResponseData\PagarmeRecipientResponseData;
- use App\Models\Provider;
- use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
- use Carbon\Carbon;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Str;
- class PagarmeRecipientService
- {
- use SendsPagarmeRequests;
- public function createRecipientForProvider(Provider $provider, array $data): string
- {
- if (! empty($provider->recipient_id)) {
- return $provider->recipient_id;
- }
- $bankAccountData = $data['recipient_default_bank_account'];
- $bankAccountData['holder_name'] = $this->normalizeBankAccountHolderName($bankAccountData['holder_name']);
- $metadata = $data['recipient_metadata'] ?? [];
- $paymentMode = $data['recipient_payment_mode'];
- $recipientType = $data['recipient_type'] ?? 'individual';
- $addressParts = $this->extractAddressParts($data);
- $monthlyIncome = isset($data['monthly_income']) ? (int) $data['monthly_income'] : 1000;
- $occupation = $data['professional_occupation'] ?? 'autonomo';
- $recipientCode = $this->ensureRecipientCode($provider);
- $defaultBankAccount = PagarmeRecipientBankAccountData::fromArray($bankAccountData);
- $payload = new PagarmeRecipientRequestData(
- code: $recipientCode,
- registerInformation: new PagarmeRecipientRegisterInformationData(
- name: $data['recipient_name'],
- email: $data['recipient_email'],
- document: preg_replace('/\D+/', '', $data['recipient_document']),
- type: $recipientType,
- birthdate: $this->formatBirthdate($data['birth_date'] ?? null),
- monthlyIncome: $monthlyIncome,
- professionalOccupation: $occupation,
- phoneNumbers: new PagarmeRecipientPhoneNumbersData($this->buildPhoneNumber($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: preg_replace('/\D+/', '', $data['zip_code']),
- referencePoint: $addressParts['reference_point'],
- ),
- ),
- defaultBankAccount: $defaultBankAccount,
- transferSettings: new PagarmeRecipientTransferSettingsData(
- transferEnabled: false,
- transferInterval: 'Daily',
- transferDay: 0,
- ),
- automaticAnticipationSettings: new PagarmeRecipientAutomaticAnticipationSettingsData(
- enabled: false,
- ),
- );
- $recipientData = PagarmeRecipientResponseData::fromArray($this->pagarmeRequest(
- method: 'POST',
- path: '/recipients',
- payload: $payload,
- idempotencyKey: $this->idempotencyKey($provider->id),
- errorMessage: 'Erro ao criar recebedor no Pagar.me.',
- ));
- $recipientId = $recipientData->id();
- if (! $recipientId) {
- Log::channel('pagarme')->error('Pagar.me recipient creation returned empty id', [
- 'response' => $recipientData->toArray(),
- ]);
- throw new \RuntimeException('Pagar.me recipient creation returned an empty id.');
- }
- $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' => $recipientType,
- '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
- {
- if (empty($provider->recipient_id)) {
- throw new \InvalidArgumentException('Prestador precisa ter recipient_id do Pagar.me para atualizar a conta bancaria.');
- }
- $bankAccountData = $this->normalizeBankAccountPayload($bankAccountData);
- $bankAccountData['holder_name'] = $this->normalizeBankAccountHolderName($bankAccountData['holder_name']);
- $payload = PagarmeBankAccountUpdateRequestData::fromArray($bankAccountData);
- $recipientData = PagarmeRecipientResponseData::fromArray($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.',
- ));
- $provider->forceFill([
- 'recipient_default_bank_account' => $recipientData->defaultBankAccount()?->toArray() ?: $bankAccountData,
- ])->save();
- return $provider->fresh();
- }
- //
- private function idempotencyKey(int $providerId, string $suffix = 'recipient'): string
- {
- return "provider-{$providerId}-{$suffix}";
- }
- private function buildPhoneNumber(?string $phone): PagarmeRecipientPhoneData
- {
- $digits = preg_replace('/\D+/', '', (string) $phone) ?? '';
- if (strlen($digits) < 10) {
- return new PagarmeRecipientPhoneData(
- ddd: '11',
- number: '999999999',
- type: 'mobile',
- );
- }
- if (str_starts_with($digits, '55')) {
- $digits = substr($digits, 2);
- }
- $areaCode = substr($digits, 0, 2);
- $number = substr($digits, 2);
- return new PagarmeRecipientPhoneData(
- ddd: $areaCode,
- number: $number,
- type: 'mobile',
- );
- }
- private function ensureRecipientCode(Provider $provider): string
- {
- if ($this->hasUuidCode($provider->recipient_code, 'provider')) {
- return $provider->recipient_code;
- }
- $recipientCode = 'provider-'.(string) Str::uuid();
- $provider->forceFill(['recipient_code' => $recipientCode])->save();
- return $recipientCode;
- }
- private function hasUuidCode(?string $code, string $prefix): bool
- {
- return is_string($code)
- && preg_match("/^{$prefix}-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i", $code) === 1;
- }
- private function extractAddressParts(array $data): array
- {
- $addressLine = trim((string) ($data['address'] ?? ''));
- $segments = array_map('trim', explode(',', $addressLine));
- $streetSegment = $segments[0] ?? '';
- $streetNumber = $data['number'] ?? null;
- $neighborhood = $data['district'] ?? null;
- $referencePoint = $data['reference_point'] ?? null;
- $complementary = $data['complement'] ?? null;
- if ($streetNumber === null) {
- preg_match('/^(\d+)/', $streetSegment, $matches);
- $streetNumber = $matches[1] ?? 'S/N';
- }
- if ($neighborhood === null) {
- $neighborhood = $segments[1] ?? 'N/A';
- }
- if ($referencePoint === null) {
- $referencePoint = 'N/A';
- }
- if ($complementary === null) {
- $complementary = 'N/A';
- }
- return [
- 'street_number' => (string) $streetNumber,
- 'neighborhood' => (string) $neighborhood,
- 'reference_point' => (string) $referencePoint,
- 'complementary' => (string) $complementary,
- ];
- }
- private function filterFilledRecursive(array $data): array
- {
- $filtered = [];
- foreach ($data as $key => $value) {
- if (is_array($value)) {
- $value = $this->filterFilledRecursive($value);
- }
- if ($value !== null && $value !== '' && $value !== []) {
- $filtered[$key] = $value;
- }
- }
- return $filtered;
- }
- 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 normalizeBankAccountHolderName(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 normalizeBankAccountPayload(array $bankAccountData): array
- {
- return [
- 'holder_name' => $bankAccountData['holder_name'],
- 'holder_type' => $bankAccountData['holder_type'],
- 'holder_document' => preg_replace('/\D+/', '', $bankAccountData['holder_document']),
- 'bank' => $bankAccountData['bank'],
- 'branch_number' => $bankAccountData['branch_number'],
- 'branch_check_digit' => $bankAccountData['branch_check_digit'] ?? null,
- 'account_number' => $bankAccountData['account_number'],
- 'account_check_digit' => $bankAccountData['account_check_digit'],
- 'type' => $bankAccountData['type'],
- 'metadata' => $bankAccountData['metadata'] ?? null,
- ];
- }
- }
|