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.'); } $cardData = PagarmeCardResponseData::fromArray($this->pagarmeRequest( method: 'POST', path: "/customers/{$customerId}/cards", payload: new PagarmeCardRequestData( token: $paymentMethod->token, label: $paymentMethod->card_name, billingAddress: $this->buildBillingAddress($paymentMethod), ), idempotencyKey: $this->idempotencyKey($paymentMethod), errorMessage: 'Erro ao salvar cartao no Pagar.me.', )); $cardId = $cardData->id(); 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->toArray(), ]); throw new \RuntimeException('Pagar.me card creation returned an empty id.'); } $paymentMethod->forceFill([ 'gateway_card_id' => $cardId, 'brand' => $paymentMethod->brand ?: $cardData->brand(), 'last_four_digits' => $paymentMethod->last_four_digits ?: $cardData->lastFourDigits(), ])->save(); return $cardId; } // private function idempotencyKey(ClientPaymentMethod $paymentMethod): string { return "client-payment-method-{$paymentMethod->id}-card"; } // private function buildBillingAddress(ClientPaymentMethod $paymentMethod): PagarmeCardBillingAddressData { $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 new PagarmeCardBillingAddressData( line1: $line1, line2: $address->complement ?: $address->instructions, zipCode: $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; } }