PagarmeRecipientService.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <?php
  2. namespace App\Services\Pagarme;
  3. use App\Data\Pagarme\Recipient\BankAccountUpdateRequestData;
  4. use App\Data\Pagarme\Recipient\Parts\Request\AddressData;
  5. use App\Data\Pagarme\Recipient\Parts\Request\AutomaticAnticipationSettingsData;
  6. use App\Data\Pagarme\Recipient\Parts\Request\BankAccountData;
  7. use App\Data\Pagarme\Recipient\Parts\Request\PhoneData;
  8. use App\Data\Pagarme\Recipient\Parts\Request\PhoneNumbersData;
  9. use App\Data\Pagarme\Recipient\Parts\Request\RegisterInformationData;
  10. use App\Data\Pagarme\Recipient\Parts\Request\TransferSettingsData;
  11. use App\Data\Pagarme\Recipient\RecipientRequestData;
  12. use App\Data\Pagarme\Recipient\RecipientResponseData;
  13. use App\Models\Provider;
  14. use App\Services\Pagarme\Concerns\FormatsPagarmeData;
  15. use App\Services\Pagarme\Concerns\MocksPagarmeRequests;
  16. use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
  17. class PagarmeRecipientService
  18. {
  19. use FormatsPagarmeData;
  20. use MocksPagarmeRequests;
  21. use SendsPagarmeRequests;
  22. public function createRecipientForProvider(Provider $provider, array $data): string
  23. {
  24. if (! empty($provider->recipient_id)) {
  25. return $provider->recipient_id;
  26. }
  27. $metadata = data_get($data, 'recipient_metadata', []);
  28. $paymentMode = data_get($data, 'recipient_payment_mode');
  29. $recipientCode = $provider->ensureGatewayCode();
  30. $addressParts = $this->extractAddressParts($data);
  31. $registerInformation = new RegisterInformationData(
  32. name: data_get($data, 'recipient_name'),
  33. email: data_get($data, 'recipient_email'),
  34. document: $this->digits(data_get($data, 'recipient_document')),
  35. type: data_get($data, 'recipient_type', 'individual'),
  36. birthdate: $this->formatBirthdate(data_get($data, 'birth_date')),
  37. monthlyIncome: data_get($data, 'monthly_income') !== null ? (int) data_get($data, 'monthly_income') : 1000,
  38. professionalOccupation: data_get($data, 'professional_occupation', 'autonomo'),
  39. phoneNumbers: new PhoneNumbersData(
  40. $this->buildRecipientPhone(data_get($data, 'phone')),
  41. ),
  42. address: new AddressData(
  43. street: data_get($addressParts, 'street'),
  44. complementary: data_get($addressParts, 'complementary'),
  45. streetNumber: data_get($addressParts, 'street_number'),
  46. neighborhood: data_get($addressParts, 'neighborhood'),
  47. city: data_get($data, 'city'),
  48. state: data_get($data, 'state'),
  49. zipCode: $this->digits(data_get($data, 'zip_code')),
  50. referencePoint: data_get($addressParts, 'reference_point'),
  51. ),
  52. );
  53. $defaultBankAccount = $this->buildRecipientBankAccount(
  54. data_get($data, 'recipient_default_bank_account'),
  55. );
  56. $payload = new RecipientRequestData(
  57. code: $recipientCode,
  58. registerInformation: $registerInformation,
  59. defaultBankAccount: $defaultBankAccount,
  60. transferSettings: new TransferSettingsData(
  61. transferEnabled: false,
  62. transferInterval: 'Daily',
  63. transferDay: 0,
  64. ),
  65. automaticAnticipationSettings: new AutomaticAnticipationSettingsData(
  66. enabled: true,
  67. type: '1025', // isso significa que vai ser feita de acordo com o delay (dias)
  68. delay: 1,
  69. ),
  70. );
  71. $bankAccountData = $payload->defaultBankAccount->toArray();
  72. if ($this->shouldMockPagarmeRequest()) {
  73. $recipientId = $this->mockPagarmeId('re', $provider->id);
  74. $provider->forceFill([
  75. 'recipient_id' => $recipientId,
  76. 'recipient_name' => data_get($data, 'recipient_name'),
  77. 'recipient_email' => data_get($data, 'recipient_email'),
  78. 'recipient_description' => data_get($data, 'recipient_description', ''),
  79. 'recipient_document' => data_get($data, 'recipient_document'),
  80. 'recipient_type' => $payload->registerInformation->type,
  81. 'recipient_code' => $recipientCode,
  82. 'recipient_payment_mode' => $paymentMode,
  83. 'recipient_default_bank_account' => $bankAccountData,
  84. 'recipient_transfer_settings' => [
  85. 'transfer_enabled' => false,
  86. 'transfer_interval' => 'daily',
  87. 'transfer_day' => 0,
  88. ],
  89. 'recipient_automatic_anticipation_settings' => [
  90. 'enabled' => true,
  91. 'type' => 'full',
  92. 'delay' => 1,
  93. ],
  94. 'recipient_metadata' => array_merge($metadata, ['mocked' => true]),
  95. ])->save();
  96. return $recipientId;
  97. }
  98. $raw = $this->pagarmeRequest(
  99. method: 'POST',
  100. path: '/recipients',
  101. payload: $payload,
  102. idempotencyKey: $this->idempotencyKey($provider, '', $data),
  103. errorMessage: 'Erro ao criar recebedor no Pagar.me.',
  104. );
  105. $recipientData = RecipientResponseData::fromArray($raw);
  106. $recipientId = $recipientData->requireId();
  107. $provider->forceFill([
  108. 'recipient_id' => $recipientId,
  109. 'recipient_name' => data_get($data, 'recipient_name'),
  110. 'recipient_email' => data_get($data, 'recipient_email'),
  111. 'recipient_description' => data_get($data, 'recipient_description', ''),
  112. 'recipient_document' => data_get($data, 'recipient_document'),
  113. 'recipient_type' => $payload->registerInformation->type,
  114. 'recipient_code' => $recipientCode,
  115. 'recipient_payment_mode' => $paymentMode,
  116. 'recipient_default_bank_account' => $bankAccountData,
  117. 'recipient_transfer_settings' => [
  118. 'transfer_enabled' => false,
  119. 'transfer_interval' => 'daily',
  120. 'transfer_day' => 0,
  121. ],
  122. 'recipient_automatic_anticipation_settings' => [
  123. 'enabled' => true,
  124. 'type' => 'full',
  125. 'delay' => 1,
  126. ],
  127. 'recipient_metadata' => $metadata,
  128. ])->save();
  129. return $recipientId;
  130. }
  131. public function updateDefaultBankAccount(Provider $provider, array $bankAccountData): Provider
  132. {
  133. $payload = new BankAccountUpdateRequestData(
  134. holderName: $this->normalizeHolderName(data_get($bankAccountData, 'holder_name')),
  135. holderType: data_get($bankAccountData, 'holder_type'),
  136. holderDocument: $this->digits(data_get($bankAccountData, 'holder_document')),
  137. bank: data_get($bankAccountData, 'bank'),
  138. branchNumber: data_get($bankAccountData, 'branch_number'),
  139. branchCheckDigit: data_get($bankAccountData, 'branch_check_digit'),
  140. accountNumber: data_get($bankAccountData, 'account_number'),
  141. accountCheckDigit: data_get($bankAccountData, 'account_check_digit'),
  142. type: data_get($bankAccountData, 'type'),
  143. );
  144. if ($this->shouldMockPagarmeRequest()) {
  145. $provider->forceFill([
  146. 'recipient_default_bank_account' => $payload->toArray()['bank_account'],
  147. ])->save();
  148. return $provider->fresh();
  149. }
  150. $this->pagarmeRequest(
  151. method: 'PATCH',
  152. path: "/recipients/{$provider->recipient_id}/default-bank-account",
  153. payload: $payload,
  154. idempotencyKey: $this->idempotencyKey($provider, 'default-bank-account-'.sha1(json_encode($payload->toArray()))),
  155. errorMessage: 'Erro ao atualizar conta bancaria do recebedor no Pagar.me.',
  156. );
  157. $provider->forceFill([
  158. 'recipient_default_bank_account' => $payload->toArray()['bank_account'],
  159. ])->save();
  160. return $provider->fresh();
  161. }
  162. //
  163. private function buildRecipientBankAccount(array $data): BankAccountData
  164. {
  165. return new BankAccountData(
  166. holderName: $this->normalizeHolderName(data_get($data, 'holder_name')),
  167. holderType: data_get($data, 'holder_type'),
  168. holderDocument: $this->digits(data_get($data, 'holder_document')),
  169. bank: data_get($data, 'bank'),
  170. branchNumber: data_get($data, 'branch_number'),
  171. branchCheckDigit: data_get($data, 'branch_check_digit'),
  172. accountNumber: data_get($data, 'account_number'),
  173. accountCheckDigit: data_get($data, 'account_check_digit'),
  174. type: data_get($data, 'type'),
  175. );
  176. }
  177. private function buildRecipientPhone(?string $phone): PhoneData
  178. {
  179. $digits = $this->digits($phone);
  180. if (strlen($digits) < 10) {
  181. return new PhoneData(
  182. ddd: '11',
  183. number: '999999999',
  184. type: 'mobile',
  185. );
  186. }
  187. if (str_starts_with($digits, '55')) {
  188. $digits = substr($digits, 2);
  189. }
  190. return new PhoneData(
  191. ddd: substr($digits, 0, 2),
  192. number: substr($digits, 2),
  193. type: 'mobile',
  194. );
  195. }
  196. // evita criacao duplica de recipient
  197. // formato: recipient-{email}-{documento} (tudo minusculo e sem acento)
  198. private function idempotencyKey(Provider $provider, string $suffix = '', array $data = []): string
  199. {
  200. $baseKey = $provider->idempotency_key;
  201. if (empty($baseKey)) {
  202. $provider->loadMissing('user');
  203. $baseKey = $this->pagarmeIdempotencyKey('recipient', [
  204. data_get($data, 'recipient_email', $provider->recipient_email ?? $provider->user?->email ?? "provider-{$provider->id}"),
  205. $this->customerDocument(data_get($data, 'recipient_document', $provider->recipient_document ?? $provider->document))
  206. ?: "document-provider-{$provider->id}",
  207. ]);
  208. $provider->forceFill(['idempotency_key' => $baseKey])->save();
  209. }
  210. return $suffix ? "{$baseKey}-{$suffix}" : $baseKey;
  211. }
  212. }