PagarmeAnticipationService.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <?php
  2. namespace App\Services\Pagarme;
  3. use App\Data\Pagarme\Anticipation\AnticipationLimitData;
  4. use App\Data\Pagarme\Anticipation\BulkAnticipationLimitsResponseData;
  5. use App\Data\Pagarme\Anticipation\BulkAnticipationRequestData;
  6. use App\Data\Pagarme\Anticipation\BulkAnticipationResponseData;
  7. use App\Data\Pagarme\Order\OrderRequestData;
  8. use App\Models\Payment;
  9. use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
  10. use Illuminate\Support\Facades\Http;
  11. use Illuminate\Support\Facades\Log;
  12. use Throwable;
  13. class PagarmeAnticipationService
  14. {
  15. use SendsPagarmeRequests;
  16. public function createBulkAnticipation(Payment $payment): ?BulkAnticipationResponseData
  17. {
  18. $provider = $payment->provider()->first();
  19. if (! $provider) {
  20. return null;
  21. }
  22. $recipientId = $provider->recipient_id;
  23. if (empty($recipientId)) {
  24. return null;
  25. }
  26. $providerSplit = $payment->splits()
  27. ->where('provider_id', $payment->provider_id)
  28. ->first();
  29. if (! $providerSplit) {
  30. return null;
  31. }
  32. $requestedAmount = OrderRequestData::amountInCents((float) $providerSplit->gross_amount);
  33. if ($requestedAmount <= 0) {
  34. return null;
  35. }
  36. $paymentDate = $this->getAnticipationPaymentDate();
  37. $limits = $this->fetchAnticipationLimits($recipientId, $paymentDate);
  38. if ($limits && $limits->minimum->amount > 0 && $requestedAmount < $limits->minimum->amount) {
  39. Log::channel('pagarme')->warning('Antecipacao ignorada: valor abaixo do minimo do recebedor.', [
  40. 'payment_id' => $payment->id,
  41. 'provider_id' => $payment->provider_id,
  42. 'recipient_id' => $recipientId,
  43. 'requested_amount' => $requestedAmount,
  44. 'minimum_amount' => $limits->minimum->amount,
  45. 'maximum_amount' => $limits->maximum->amount,
  46. ]);
  47. return null;
  48. }
  49. try {
  50. $response = BulkAnticipationResponseData::fromArray($this->pagarmeRequest(
  51. method: 'POST',
  52. path: "/recipients/{$recipientId}/bulk_anticipations",
  53. payload: new BulkAnticipationRequestData(
  54. paymentDate: $paymentDate,
  55. timeframe: 'start',
  56. requestedAmount: $requestedAmount,
  57. automaticTransfer: false,
  58. ),
  59. idempotencyKey: "bulk-ant-{$payment->id}-{$payment->provider_id}",
  60. errorMessage: 'Erro ao criar antecipacao no Pagar.me.',
  61. ));
  62. $response->requireId();
  63. return $response;
  64. } catch (Throwable $e) {
  65. Log::channel('pagarme')->warning('Falha ao criar antecipacao no Pagar.me.', [
  66. 'payment_id' => $payment->id,
  67. 'provider_id' => $payment->provider_id,
  68. 'recipient_id' => $recipientId,
  69. 'requested_amount' => $requestedAmount,
  70. 'minimum_amount' => $limits?->minimum->amount,
  71. 'maximum_amount' => $limits?->maximum->amount,
  72. 'error' => $e->getMessage(),
  73. ]);
  74. return null;
  75. }
  76. }
  77. private function fetchAnticipationLimits(string $recipientId, string $paymentDate): ?BulkAnticipationLimitsResponseData
  78. {
  79. try {
  80. $secretKey = config('services.pagarme.secret_key');
  81. if (empty($secretKey)) {
  82. return null;
  83. }
  84. $endpoint = $this->pagarmeUrl("/recipients/{$recipientId}/bulk_anticipations/limits");
  85. $response = Http::withBasicAuth($secretKey, '')
  86. ->withHeaders([
  87. 'Content-Type' => 'application/json',
  88. 'Accept' => 'application/json',
  89. ])
  90. ->get($endpoint, [
  91. 'payment_date' => $paymentDate,
  92. 'timeframe' => 'start',
  93. ])
  94. ->throw();
  95. $body = $response->json() ?? [];
  96. return BulkAnticipationLimitsResponseData::fromArray($body);
  97. } catch (Throwable $e) {
  98. Log::channel('pagarme')->warning('Falha ao consultar limites de antecipacao.', [
  99. 'recipient_id' => $recipientId,
  100. 'payment_date' => $paymentDate,
  101. 'error' => $e->getMessage(),
  102. ]);
  103. return null;
  104. }
  105. }
  106. private function getAnticipationPaymentDate(): string
  107. {
  108. $now = now()->timezone('America/Sao_Paulo');
  109. if ($now->hour < 11) {
  110. return $now->toISOString();
  111. }
  112. $nextBusinessDay = $now->copy()->addDay();
  113. while ($nextBusinessDay->isWeekend()) {
  114. $nextBusinessDay->addDay();
  115. }
  116. return $nextBusinessDay->startOfDay()->toISOString();
  117. }
  118. }