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 = $client->external_customer_code ?? "client-{$client->id}"; $payload = [ 'name' => $name, 'email' => $email, 'document' => $document, 'type' => $this->personType($document), 'document_type' => $this->documentType($document), 'code' => $code, 'address' => $address, ]; if (! empty($phones)) { $payload['phones'] = $phones; } $response = $this->pagarmeRequest($client->id) ->post($this->pagarmeUrl('/customers'), $payload); if ($response->failed()) { Log::channel('pagarme')->error('Pagar.me customer creation failed', [ 'status' => $response->status(), 'body' => $response->json() ?? $response->body(), 'payload' => $payload, ]); throw new \RuntimeException('Erro ao criar cliente no Pagar.me.'); } $customerData = $response->json(); $customerId = $customerData['id'] ?? null; if (! $customerId) { Log::channel('pagarme')->error('Customer creation returned an empty id.', [ 'client_id' => $client->id, 'response' => $customerData, ]); throw new \RuntimeException('Customer creation returned an empty id.'); } $client->forceFill([ 'external_customer_id' => $customerId, 'external_customer_code' => $code, ])->save(); return $customerId; } // private function pagarmeUrl(string $path): string { return rtrim(config('services.pagarme.base_url'), '/').'/'.ltrim($path, '/'); } private function idempotencyKey(int $clientId): string { return "client-{$clientId}-customer"; } // private function buildAddress(array $data): array { $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 [ 'line_1' => $line1, 'line_2' => $line2, 'zip_code' => $zipCode, 'city' => $city, 'state' => $state, 'country' => $country, ]; } private function buildPhones(?string $phone): array { $digits = $this->sanitizeDigits($phone); if (empty($digits)) { return []; } $countryCode = '55'; $areaCode = substr($digits, 0, 2); $number = substr($digits, 2); if (strlen($digits) <= 2) { $areaCode = ''; $number = $digits; } return [ 'mobile_phone' => [ 'country_code' => $countryCode, 'area_code' => $areaCode, 'number' => $number, ], ]; } // 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 pagarmeRequest(int $clientId) { $secretKey = config('services.pagarme.secret_key'); if (empty($secretKey)) { Log::channel('pagarme')->error('PAGARME_SECRET_KEY is not configured.'); throw new \RuntimeException('PAGARME_SECRET_KEY is not configured.'); } return Http::withBasicAuth($secretKey, '') ->withHeaders([ 'Idempotency-Key' => $this->idempotencyKey($clientId), 'Content-Type' => 'application/json', 'Accept' => 'application/json', ]); } }