| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- <?php
- namespace App\Services\Pagarme;
- use App\Models\Address;
- use App\Models\ClientPaymentMethod;
- use Illuminate\Support\Facades\Http;
- use Illuminate\Support\Facades\Log;
- class PagarmeCardService
- {
- public function __construct(
- private readonly PagarmeCustomerService $pagarmeCustomerService,
- ) {}
- public function createCardForPaymentMethod(ClientPaymentMethod $paymentMethod): ?string
- {
- if (! empty($paymentMethod->gateway_card_id)) {
- return $paymentMethod->gateway_card_id;
- }
- if (empty($paymentMethod->token)) {
- throw new \InvalidArgumentException('Token do cartao e obrigatorio para salvar cartao no Pagar.me.');
- }
- $paymentMethod->loadMissing('client.user');
- $customerId = $this->pagarmeCustomerService->createCustomerForClient(
- $paymentMethod->client,
- []
- );
- if (empty($customerId)) {
- throw new \RuntimeException('Cliente precisa ter customer_id do Pagar.me para salvar cartao.');
- }
- $payload = $this->filterFilledRecursive([
- 'token' => $paymentMethod->token,
- 'label' => $paymentMethod->card_name,
- 'billing_address' => $this->buildBillingAddress($paymentMethod),
- ]);
- $endpoint = $this->pagarmeUrl("/customers/{$customerId}/cards");
- PagarmeHttpLogger::logRequest('POST', $endpoint, $payload);
- $response = $this->pagarmeRequest($paymentMethod->id)
- ->post($endpoint, $payload);
- if ($response->failed()) {
- $responseBody = $response->json() ?? $response->body();
- Log::channel('pagarme')->error('Pagar.me card creation failed', [
- 'client_payment_method_id' => $paymentMethod->id,
- 'client_id' => $paymentMethod->client_id,
- 'customer_id' => $customerId,
- 'status' => $response->status(),
- 'body' => $responseBody,
- 'payload' => $payload,
- ]);
- throw new \RuntimeException($this->gatewayErrorMessage($responseBody));
- }
- $cardData = $response->json();
- $cardId = $cardData['id'] ?? null;
- if (empty($cardId)) {
- Log::channel('pagarme')->error('Pagar.me card creation returned empty id', [
- 'client_payment_method_id' => $paymentMethod->id,
- 'client_id' => $paymentMethod->client_id,
- 'customer_id' => $customerId,
- 'response' => $cardData,
- ]);
- throw new \RuntimeException('Pagar.me card creation returned an empty id.');
- }
- $paymentMethod->forceFill([
- 'gateway_card_id' => $cardId,
- 'brand' => $paymentMethod->brand ?: ($cardData['brand'] ?? null),
- 'last_four_digits' => $paymentMethod->last_four_digits ?: ($cardData['last_four_digits'] ?? null),
- ])->save();
- return $cardId;
- }
- //
- private function pagarmeRequest(int $paymentMethodId)
- {
- $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' => "client-payment-method-{$paymentMethodId}-card",
- 'Content-Type' => 'application/json',
- 'Accept' => 'application/json',
- ]);
- }
- private function pagarmeUrl(string $path): string
- {
- return rtrim(config('services.pagarme.base_url'), '/').'/'.ltrim($path, '/');
- }
- //
- private function buildBillingAddress(ClientPaymentMethod $paymentMethod): array
- {
- $address = Address::query()
- ->with(['city.state', 'state'])
- ->where('source', 'client')
- ->where('source_id', $paymentMethod->client_id)
- ->orderByDesc('is_primary')
- ->latest('id')
- ->first();
- if (! $address) {
- throw new \InvalidArgumentException('Cliente precisa ter endereco para salvar cartao no Pagar.me.');
- }
- $state = $address->state?->code ?? $address->city?->state?->code;
- $city = $address->city?->name;
- $line1 = implode(', ', array_filter([
- $address->number ?: 'S/N',
- $address->address,
- $address->district,
- ]));
- foreach ([
- 'estado' => $state,
- 'cidade' => $city,
- 'cep' => $this->digits($address->zip_code),
- 'endereco' => $line1,
- ] as $field => $value) {
- if ($value === null || $value === '') {
- throw new \InvalidArgumentException("Cliente precisa ter {$field} valido para salvar cartao no Pagar.me.");
- }
- }
- return [
- 'line_1' => $line1,
- 'line_2' => $address->complement ?: $address->instructions,
- 'zip_code' => $this->digits($address->zip_code),
- 'city' => $city,
- 'state' => $state,
- 'country' => 'BR',
- ];
- }
- private function digits(?string $value): string
- {
- return preg_replace('/\D+/', '', (string) $value) ?? '';
- }
- 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 gatewayErrorMessage(mixed $responseBody): string
- {
- $message = is_array($responseBody) ? ($responseBody['message'] ?? null) : null;
- if ($message === 'Token not found.') {
- return 'Token do cartao nao encontrado no Pagar.me. Gere o token com a public key do mesmo ambiente da secret key.';
- }
- return 'Erro ao salvar cartao no Pagar.me.';
- }
- }
|