Jelajahi Sumber

feat: add integracao customer - client com pagarme

Gustavo Mantovani 1 bulan lalu
induk
melakukan
b5e4a53129

+ 2 - 0
app/Models/Client.php

@@ -46,6 +46,8 @@ class Client extends Model
 
     protected $fillable = [
         'document',
+        'external_customer_id',
+        'external_customer_code',
         'user_id',
     ];
 

+ 24 - 0
app/Models/Provider.php

@@ -32,6 +32,18 @@ use Illuminate\Database\Eloquent\SoftDeletes;
  * @property string|null $document_front_media_base64
  * @property string|null $document_back_media_base64
  * @property ApprovalStatusEnum $approval_status
+ * @property string|null $recipient_id
+ * @property string|null $recipient_name
+ * @property string|null $recipient_email
+ * @property string|null $recipient_description
+ * @property string|null $recipient_document
+ * @property string|null $recipient_type
+ * @property string|null $recipient_code
+ * @property string|null $recipient_payment_mode
+ * @property array<array-key, mixed>|null $recipient_default_bank_account
+ * @property array<array-key, mixed>|null $recipient_transfer_settings
+ * @property array<array-key, mixed>|null $recipient_automatic_anticipation_settings
+ * @property array<array-key, mixed>|null $recipient_metadata
  * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Address> $addresses
  * @property-read int|null $addresses_count
  * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ClientProviderBlock> $blockedByClients
@@ -60,6 +72,18 @@ use Illuminate\Database\Eloquent\SoftDeletes;
  * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereDocumentVerified($value)
  * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereId($value)
  * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereProfileMediaId($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientAutomaticAnticipationSettings($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientCode($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientDefaultBankAccount($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientDescription($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientDocument($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientEmail($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientId($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientMetadata($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientName($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientPaymentMode($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientTransferSettings($value)
+ * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRecipientType($value)
  * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereRg($value)
  * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereSelfieMediaBase64($value)
  * @method static \Illuminate\Database\Eloquent\Builder<static>|Provider whereSelfieVerified($value)

+ 4 - 0
app/Services/ClientService.php

@@ -7,6 +7,7 @@ use App\Models\City;
 use App\Models\Client;
 use App\Models\State;
 use App\Models\User;
+use App\Services\Pagarme\PagarmeCustomerService;
 use Illuminate\Database\Eloquent\Collection;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Log;
@@ -15,6 +16,7 @@ class ClientService
 {
   public function __construct(
     private readonly AuthService $authService,
+    private readonly PagarmeCustomerService $pagarmeCustomerService,
   ) {}
 
   public function getAll(): Collection
@@ -107,6 +109,8 @@ class ClientService
         $addressData
       );
 
+      $this->pagarmeCustomerService->createCustomerForClient($client, $data);
+
       $registrationComplete = !empty($user->name)
         && !empty($client->document)
         && Address::where('source', 'client')->where('source_id', $client->id)->exists();

+ 185 - 0
app/Services/Pagarme/PagarmeCustomerService.php

@@ -0,0 +1,185 @@
+<?php
+
+namespace App\Services\Pagarme;
+
+use App\Models\Client;
+use Illuminate\Support\Facades\Log;
+use PagarmeApiSDKLib\Authentication\BasicAuthCredentialsBuilder;
+use PagarmeApiSDKLib\Models\CreateAddressRequest;
+use PagarmeApiSDKLib\Models\CreatePhonesRequest;
+use PagarmeApiSDKLib\Models\Builders\CreateAddressRequestBuilder;
+use PagarmeApiSDKLib\Models\Builders\CreateCustomerRequestBuilder;
+use PagarmeApiSDKLib\Models\Builders\CreatePhoneRequestBuilder;
+use PagarmeApiSDKLib\Models\Builders\CreatePhonesRequestBuilder;
+use PagarmeApiSDKLib\PagarmeApiSDKClient;
+use PagarmeApiSDKLib\PagarmeApiSDKClientBuilder;
+
+class PagarmeCustomerService
+{
+    private ?PagarmeApiSDKClient $client = null;
+
+    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::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 = $client->external_customer_code ?? "client-{$client->id}";
+
+        $customerRequest = CreateCustomerRequestBuilder::init(
+            $name,
+            $email,
+            $document,
+            $this->personType($document),
+            $address,
+            [
+                'client_id' => (string) $client->id,
+                'user_id' => (string) ($client->user_id ?? ''),
+            ],
+            $phones,
+            $code
+        )
+            ->documentType($this->documentType($document))
+            ->build();
+
+        $customer = $this->client()->getCustomersController()->createCustomer(
+            $customerRequest,
+            $this->idempotencyKey($client->id)
+        );
+
+        $customerId = $customer->getId();
+        if (!$customerId) {
+            throw new \RuntimeException('Customer creation returned an empty id.');
+        }
+
+        $client->forceFill([
+            'external_customer_id' => $customerId,
+            'external_customer_code' => $code,
+        ])->save();
+
+        return $customerId;
+    }
+
+    private function buildAddress(array $data): CreateAddressRequest
+    {
+        $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 CreateAddressRequestBuilder::init(
+            $street,
+            $number,
+            $zipCode,
+            $neighborhood,
+            $city,
+            $state,
+            $country,
+            $complement,
+            $line1,
+            $line2
+        )
+            ->metadata([
+                'source' => 'register-client',
+            ])
+            ->build();
+    }
+
+    private function buildPhones(?string $phone): CreatePhonesRequest
+    {
+        $digits = $this->sanitizeDigits($phone);
+        $phonesBuilder = CreatePhonesRequestBuilder::init();
+
+        if (empty($digits)) {
+            return $phonesBuilder->build();
+        }
+
+        $countryCode = '55';
+        $areaCode = substr($digits, 0, 2);
+        $number = substr($digits, 2);
+
+        if (strlen($digits) <= 2) {
+            $areaCode = '';
+            $number = $digits;
+        }
+
+        $mobilePhone = CreatePhoneRequestBuilder::init()
+            ->countryCode($countryCode)
+            ->areaCode($areaCode)
+            ->number($number)
+            ->type('mobile')
+            ->build();
+
+        return $phonesBuilder
+            ->mobilePhone($mobilePhone)
+            ->build();
+    }
+
+    private function documentType(string $document): string
+    {
+        return strlen($document) === 14 ? 'CNPJ' : 'CPF';
+    }
+
+    private function personType(string $document): string
+    {
+        return strlen($document) === 14 ? 'company' : 'individual';
+    }
+
+    private function sanitizeDigits(?string $value): string
+    {
+        return preg_replace('/\D+/', '', (string) $value) ?? '';
+    }
+
+    private function client(): PagarmeApiSDKClient
+    {
+        if ($this->client) {
+            return $this->client;
+        }
+
+        $secretKey = config('services.pagarme.secret_key');
+        if (empty($secretKey)) {
+            throw new \RuntimeException('PAGARME_SECRET_KEY is not configured.');
+        }
+
+        $serviceRefererName = (string) config('services.pagarme.service_referer_name', config('app.name'));
+
+        $this->client = PagarmeApiSDKClientBuilder::init()
+            ->basicAuthCredentials(
+                BasicAuthCredentialsBuilder::init($secretKey, '')
+            )
+            ->serviceRefererName($serviceRefererName)
+            ->build();
+
+        return $this->client;
+    }
+
+    private function idempotencyKey(int $clientId): string
+    {
+        return "client-{$clientId}-customer";
+    }
+}

+ 28 - 0
database/migrations/2026_05_15_000003_add_external_customer_fields_to_clients_table.php

@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        Schema::table('clients', function (Blueprint $table) {
+            $table->string('external_customer_id')->nullable()->after('user_id')->unique();
+            $table->string('external_customer_code')->nullable()->after('external_customer_id')->unique();
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::table('clients', function (Blueprint $table) {
+            $table->dropUnique(['external_customer_id']);
+            $table->dropUnique(['external_customer_code']);
+            $table->dropColumn([
+                'external_customer_id',
+                'external_customer_code',
+            ]);
+        });
+    }
+};