| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- <?php
- namespace App\Services\Pagarme;
- use App\Data\Pagarme\Request\PagarmeCustomerRequestData\PagarmeCustomerAddressRequestData;
- use App\Data\Pagarme\Request\PagarmeCustomerRequestData\PagarmeCustomerPhonesRequestData\PagarmeCustomerPhoneData;
- use App\Data\Pagarme\Request\PagarmeCustomerRequestData\PagarmeCustomerPhonesRequestData\PagarmeCustomerPhonesRequestData;
- use App\Data\Pagarme\Request\PagarmeCustomerRequestData\PagarmeCustomerRequestData;
- use App\Data\Pagarme\Request\PagarmeCustomerRequestData\PagarmeCustomerUpdateRequestData;
- use App\Data\Pagarme\Response\PagarmeCustomerResponseData\PagarmeCustomerResponseData;
- use App\Models\Client;
- use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Str;
- class PagarmeCustomerService
- {
- use SendsPagarmeRequests;
- public function createCustomerForClient(Client $client, array $data): ?string
- {
- if (! empty($client->external_customer_id)) {
- return $client->external_customer_id;
- }
- $client->loadMissing('user');
- $name = $client->user?->name ?? $data['name'] ?? 'Cliente';
- $email = $client->user?->email ?? $data['email'] ?? null;
- $document = $this->sanitizeDigits($client->document ?? $data['document'] ?? null);
- if (empty($email) || empty($document)) {
- Log::channel('pagarme')->warning(
- 'Skipping customer creation because the client is missing email or document.',
- [
- 'client_id' => $client->id,
- 'user_id' => $client->user_id,
- ]
- );
- return null;
- }
- $address = $this->buildAddress($data);
- $phones = $this->buildPhones($client->user?->phone ?? $data['phone'] ?? null);
- $code = $this->ensureCustomerCode($client);
- $customerData = PagarmeCustomerResponseData::fromArray($this->pagarmeRequest(
- method: 'POST',
- path: '/customers',
- payload: new PagarmeCustomerRequestData(
- name: $name,
- email: $email,
- document: $document,
- type: $this->personType($document),
- documentType: $this->documentType($document),
- code: $code,
- address: $address,
- phones: $phones,
- ),
- idempotencyKey: $this->idempotencyKey($client->id),
- errorMessage: 'Erro ao criar cliente no Pagar.me.',
- ));
- $customerId = $customerData->id();
- if (! $customerId) {
- Log::channel('pagarme')->error('Customer creation returned an empty id.', [
- 'client_id' => $client->id,
- 'response' => $customerData->toArray(),
- ]);
- throw new \RuntimeException('Customer creation returned an empty id.');
- }
- $client->forceFill([
- 'external_customer_id' => $customerId,
- 'external_customer_code' => $code,
- ])->save();
- return $customerId;
- }
- public function updateCustomer(string $customerId, int $clientId, array $data): void
- {
- $payload = new PagarmeCustomerUpdateRequestData(
- name: $data['name'] ?? null,
- email: $data['email'] ?? null,
- document: $this->sanitizeDigits($data['document'] ?? null),
- type: $data['type'] ?? null,
- documentType: $data['document_type'] ?? null,
- code: $data['code'] ?? null,
- address: $this->addressFromPayload($data['address'] ?? null),
- phones: $this->phonesFromPayload($data['phones'] ?? null),
- );
- if (empty($payload->toArray())) {
- return;
- }
- $this->pagarmeRequest(
- method: 'PATCH',
- path: "/customers/{$customerId}",
- payload: $payload,
- idempotencyKey: $this->idempotencyKey($clientId, "customer-update-{$customerId}"),
- errorMessage: 'Erro ao atualizar cliente no Pagar.me.',
- );
- }
- private function idempotencyKey(int $clientId, string $suffix = 'customer'): string
- {
- return "client-{$clientId}-{$suffix}";
- }
- private function ensureCustomerCode(Client $client): string
- {
- if ($this->hasUuidCode($client->external_customer_code, 'client')) {
- return $client->external_customer_code;
- }
- $code = 'client-'.(string) Str::uuid();
- $client->forceFill(['external_customer_code' => $code])->save();
- return $code;
- }
- 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 buildAddress(array $data): PagarmeCustomerAddressRequestData
- {
- $zipCode = $this->sanitizeDigits($data['zip_code'] ?? null);
- $street = (string) ($data['address'] ?? '');
- $number = (string) ($data['number'] ?? '0');
- $neighborhood = (string) ($data['district'] ?? '');
- $city = (string) ($data['city'] ?? '');
- $state = (string) ($data['state'] ?? '');
- $country = (string) ($data['country'] ?? 'BR');
- $complement = (string) ($data['complement'] ?? '');
- $line1Parts = array_filter([$number, $street, $neighborhood], static fn ($value) => $value !== '');
- $line1 = implode(', ', $line1Parts);
- $line2 = $complement ?: (string) ($data['instructions'] ?? '');
- return new PagarmeCustomerAddressRequestData(
- line1: $line1,
- line2: $line2,
- zipCode: $zipCode,
- city: $city,
- state: $state,
- country: $country,
- );
- }
- private function buildPhones(?string $phone): PagarmeCustomerPhonesRequestData
- {
- $digits = $this->sanitizeDigits($phone);
- if (empty($digits)) {
- return new PagarmeCustomerPhonesRequestData;
- }
- $countryCode = '55';
- $areaCode = substr($digits, 0, 2);
- $number = substr($digits, 2);
- if (strlen($digits) <= 2) {
- $areaCode = '';
- $number = $digits;
- }
- return new PagarmeCustomerPhonesRequestData(
- mobilePhone: new PagarmeCustomerPhoneData(
- countryCode: $countryCode,
- areaCode: $areaCode,
- number: $number,
- ),
- );
- }
- private function addressFromPayload(mixed $address): ?PagarmeCustomerAddressRequestData
- {
- if (! is_array($address) || empty($address)) {
- return null;
- }
- return new PagarmeCustomerAddressRequestData(
- line1: $address['line_1'] ?? null,
- line2: $address['line_2'] ?? null,
- zipCode: $address['zip_code'] ?? null,
- city: $address['city'] ?? null,
- state: $address['state'] ?? null,
- country: $address['country'] ?? null,
- );
- }
- private function phonesFromPayload(mixed $phones): ?PagarmeCustomerPhonesRequestData
- {
- if (! is_array($phones) || empty($phones)) {
- return null;
- }
- return new PagarmeCustomerPhonesRequestData(
- homePhone: $this->phoneFromPayload($phones['home_phone'] ?? null),
- mobilePhone: $this->phoneFromPayload($phones['mobile_phone'] ?? null),
- );
- }
- private function phoneFromPayload(mixed $phone): ?PagarmeCustomerPhoneData
- {
- if (! is_array($phone) || empty($phone)) {
- return null;
- }
- return new PagarmeCustomerPhoneData(
- countryCode: (string) ($phone['country_code'] ?? ''),
- areaCode: (string) ($phone['area_code'] ?? ''),
- number: (string) ($phone['number'] ?? ''),
- );
- }
- private function documentType(string $document): string
- {
- return strlen($document) === 14 ? 'CNPJ' : 'CPF';
- }
- 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 personType(string $document): string
- {
- return strlen($document) === 14 ? 'company' : 'individual';
- }
- private function sanitizeDigits(?string $value): string
- {
- return preg_replace('/\D+/', '', (string) $value) ?? '';
- }
- }
|