PagarmeCardService.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <?php
  2. namespace App\Services\Pagarme;
  3. use App\Data\Pagarme\Request\Objects\PagarmeCardBillingAddressData;
  4. use App\Data\Pagarme\Request\PagarmeCardRequestData;
  5. use App\Data\Pagarme\Response\PagarmeCardResponseData;
  6. use App\Models\Address;
  7. use App\Models\ClientPaymentMethod;
  8. use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
  9. use Illuminate\Support\Facades\Log;
  10. class PagarmeCardService
  11. {
  12. use SendsPagarmeRequests;
  13. public function __construct(
  14. private readonly PagarmeCustomerService $pagarmeCustomerService,
  15. ) {}
  16. public function createCardForPaymentMethod(ClientPaymentMethod $paymentMethod): ?string
  17. {
  18. if (! empty($paymentMethod->gateway_card_id)) {
  19. return $paymentMethod->gateway_card_id;
  20. }
  21. if (empty($paymentMethod->token)) {
  22. throw new \InvalidArgumentException('Token do cartao e obrigatorio para salvar cartao no Pagar.me.');
  23. }
  24. $paymentMethod->loadMissing('client.user');
  25. $customerId = $this->pagarmeCustomerService->createCustomerForClient(
  26. $paymentMethod->client,
  27. []
  28. );
  29. if (empty($customerId)) {
  30. throw new \RuntimeException('Cliente precisa ter customer_id do Pagar.me para salvar cartao.');
  31. }
  32. $cardData = PagarmeCardResponseData::fromArray($this->pagarmeRequest(
  33. method: 'POST',
  34. path: "/customers/{$customerId}/cards",
  35. payload: new PagarmeCardRequestData(
  36. token: $paymentMethod->token,
  37. label: $paymentMethod->card_name,
  38. billingAddress: $this->buildBillingAddress($paymentMethod),
  39. ),
  40. idempotencyKey: $this->idempotencyKey($paymentMethod),
  41. errorMessage: 'Erro ao salvar cartao no Pagar.me.',
  42. ));
  43. $cardId = $cardData->id();
  44. if (empty($cardId)) {
  45. Log::channel('pagarme')->error('Pagar.me card creation returned empty id', [
  46. 'client_payment_method_id' => $paymentMethod->id,
  47. 'client_id' => $paymentMethod->client_id,
  48. 'customer_id' => $customerId,
  49. 'response' => $cardData->toArray(),
  50. ]);
  51. throw new \RuntimeException('Pagar.me card creation returned an empty id.');
  52. }
  53. $paymentMethod->forceFill([
  54. 'gateway_card_id' => $cardId,
  55. 'brand' => $paymentMethod->brand ?: $cardData->brand(),
  56. 'last_four_digits' => $paymentMethod->last_four_digits ?: $cardData->lastFourDigits(),
  57. ])->save();
  58. return $cardId;
  59. }
  60. //
  61. private function idempotencyKey(ClientPaymentMethod $paymentMethod): string
  62. {
  63. return "client-payment-method-{$paymentMethod->id}-card";
  64. }
  65. //
  66. private function buildBillingAddress(ClientPaymentMethod $paymentMethod): PagarmeCardBillingAddressData
  67. {
  68. $address = Address::query()
  69. ->with(['city.state', 'state'])
  70. ->where('source', 'client')
  71. ->where('source_id', $paymentMethod->client_id)
  72. ->orderByDesc('is_primary')
  73. ->latest('id')
  74. ->first();
  75. if (! $address) {
  76. throw new \InvalidArgumentException('Cliente precisa ter endereco para salvar cartao no Pagar.me.');
  77. }
  78. $state = $address->state?->code ?? $address->city?->state?->code;
  79. $city = $address->city?->name;
  80. $line1 = implode(', ', array_filter([
  81. $address->number ?: 'S/N',
  82. $address->address,
  83. $address->district,
  84. ]));
  85. foreach ([
  86. 'estado' => $state,
  87. 'cidade' => $city,
  88. 'cep' => $this->digits($address->zip_code),
  89. 'endereco' => $line1,
  90. ] as $field => $value) {
  91. if ($value === null || $value === '') {
  92. throw new \InvalidArgumentException("Cliente precisa ter {$field} valido para salvar cartao no Pagar.me.");
  93. }
  94. }
  95. return new PagarmeCardBillingAddressData(
  96. line1: $line1,
  97. line2: $address->complement ?: $address->instructions,
  98. zipCode: $this->digits($address->zip_code),
  99. city: $city,
  100. state: $state,
  101. country: 'BR',
  102. );
  103. }
  104. private function digits(?string $value): string
  105. {
  106. return preg_replace('/\D+/', '', (string) $value) ?? '';
  107. }
  108. private function filterFilledRecursive(array $data): array
  109. {
  110. $filtered = [];
  111. foreach ($data as $key => $value) {
  112. if (is_array($value)) {
  113. $value = $this->filterFilledRecursive($value);
  114. }
  115. if ($value !== null && $value !== '' && $value !== []) {
  116. $filtered[$key] = $value;
  117. }
  118. }
  119. return $filtered;
  120. }
  121. }