Selaa lähdekoodia

Merge branch 'development' of gogs.softpar.inf.br:Softpar/sfp_api_laravel_diarista into development

Gustavo Zanatta 1 viikko sitten
vanhempi
commit
31d14853b5
100 muutettua tiedostoa jossa 3024 lisäystä ja 2308 poistoa
  1. 62 0
      app/Data/Pagarme/PagarmeResponseData.php
  2. 46 0
      app/Data/Pagarme/Request/BankAccountUpdateRequestData.php
  3. 14 13
      app/Data/Pagarme/Request/CardRequestData/CardBillingAddressData.php
  4. 4 4
      app/Data/Pagarme/Request/CardRequestData/CardRequestData.php
  5. 29 0
      app/Data/Pagarme/Request/CustomerRequestData/CustomerAddressRequestData.php
  6. 2 2
      app/Data/Pagarme/Request/CustomerRequestData/CustomerPhonesRequestData/CustomerPhoneData.php
  7. 19 0
      app/Data/Pagarme/Request/CustomerRequestData/CustomerPhonesRequestData/CustomerPhonesRequestData.php
  8. 5 27
      app/Data/Pagarme/Request/CustomerRequestData/CustomerRequestData.php
  9. 29 0
      app/Data/Pagarme/Request/OrderRequestData/OrderItemData.php
  10. 27 0
      app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderCreditCardData.php
  11. 74 0
      app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderPaymentData.php
  12. 24 0
      app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderPixAdditionalInformationData.php
  13. 31 0
      app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderPixData.php
  14. 29 0
      app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderSplitData.php
  15. 23 0
      app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderSplitOptionsData.php
  16. 113 0
      app/Data/Pagarme/Request/OrderRequestData/OrderRequestData.php
  17. 0 100
      app/Data/Pagarme/Request/PagarmeBankAccountUpdateRequestData.php
  18. 0 47
      app/Data/Pagarme/Request/PagarmeCustomerRequestData/PagarmeCustomerAddressRequestData.php
  19. 0 47
      app/Data/Pagarme/Request/PagarmeCustomerRequestData/PagarmeCustomerPhonesRequestData/PagarmeCustomerPhonesRequestData.php
  20. 0 41
      app/Data/Pagarme/Request/PagarmeCustomerRequestData/PagarmeCustomerUpdateRequestData.php
  21. 0 269
      app/Data/Pagarme/Request/PagarmeOrderRequestData/PagarmeOrderRequestData.php
  22. 0 98
      app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientBankAccountData.php
  23. 0 17
      app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientRegisterInformationData/PagarmeRecipientPhoneNumbersData/PagarmeRecipientPhoneNumbersData.php
  24. 0 140
      app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientRequestData.php
  25. 2 2
      app/Data/Pagarme/Request/RecipientRequestData/RecipientAutomaticAnticipationSettingsData.php
  26. 44 0
      app/Data/Pagarme/Request/RecipientRequestData/RecipientBankAccountData.php
  27. 8 8
      app/Data/Pagarme/Request/RecipientRequestData/RecipientRegisterInformationData/RecipientAddressData.php
  28. 2 2
      app/Data/Pagarme/Request/RecipientRequestData/RecipientRegisterInformationData/RecipientPhoneNumbersData/RecipientPhoneData.php
  29. 17 0
      app/Data/Pagarme/Request/RecipientRequestData/RecipientRegisterInformationData/RecipientPhoneNumbersData/RecipientPhoneNumbersData.php
  30. 10 11
      app/Data/Pagarme/Request/RecipientRequestData/RecipientRegisterInformationData/RecipientRegisterInformationData.php
  31. 29 0
      app/Data/Pagarme/Request/RecipientRequestData/RecipientRequestData.php
  32. 4 4
      app/Data/Pagarme/Request/RecipientRequestData/RecipientTransferSettingsData.php
  33. 2 4
      app/Data/Pagarme/Request/TransferRequestData.php
  34. 15 30
      app/Data/Pagarme/Response/CardResponseData.php
  35. 15 17
      app/Data/Pagarme/Response/CustomerResponseData/CustomerAddressResponseData.php
  36. 32 0
      app/Data/Pagarme/Response/CustomerResponseData/CustomerPhonesResponseData/CustomerPhonesResponseData.php
  37. 32 0
      app/Data/Pagarme/Response/CustomerResponseData/CustomerPhonesResponseData/PhoneResponseData.php
  38. 77 0
      app/Data/Pagarme/Response/CustomerResponseData/CustomerResponseData.php
  39. 54 0
      app/Data/Pagarme/Response/OrderResponseData/OrderChargeResponseData/OrderChargeResponseData.php
  40. 41 0
      app/Data/Pagarme/Response/OrderResponseData/OrderChargeResponseData/OrderTransactionResponseData.php
  41. 32 0
      app/Data/Pagarme/Response/OrderResponseData/OrderCheckoutResponseData.php
  42. 41 0
      app/Data/Pagarme/Response/OrderResponseData/OrderItemResponseData.php
  43. 252 0
      app/Data/Pagarme/Response/OrderResponseData/OrderResponseData.php
  44. 0 27
      app/Data/Pagarme/Response/PagarmeCustomerResponseData/PagarmeCustomerPhonesResponseData/PagarmeCustomerPhonesResponseData.php
  45. 0 34
      app/Data/Pagarme/Response/PagarmeCustomerResponseData/PagarmeCustomerPhonesResponseData/PagarmePhoneResponseData.php
  46. 0 73
      app/Data/Pagarme/Response/PagarmeCustomerResponseData/PagarmeCustomerResponseData.php
  47. 0 212
      app/Data/Pagarme/Response/PagarmeOrderResponseData/PagarmeOrderResponseData.php
  48. 0 66
      app/Data/Pagarme/Response/PagarmeTransferResponseData.php
  49. 14 12
      app/Data/Pagarme/Response/RecipientResponseData/RecipientBankAccountResponseData.php
  50. 22 24
      app/Data/Pagarme/Response/RecipientResponseData/RecipientResponseData.php
  51. 56 0
      app/Data/Pagarme/Response/TransferResponseData.php
  52. 208 208
      app/Http/Controllers/AuthController.php
  53. 1 0
      app/Http/Controllers/ClientCalendarController.php
  54. 3 0
      app/Http/Controllers/DashboardController.php
  55. 1 0
      app/Http/Controllers/ProviderCalendarController.php
  56. 21 14
      app/Http/Controllers/ProviderController.php
  57. 1 0
      app/Http/Controllers/SearchController.php
  58. 3 3
      app/Http/Resources/CardsListResource.php
  59. 8 8
      app/Http/Resources/ClientResource.php
  60. 1 1
      app/Http/Resources/DashboardClienteResource.php
  61. 1 1
      app/Http/Resources/DashboardPrestadorResource.php
  62. 7 7
      app/Http/Resources/ProviderPaymentMethodResource.php
  63. 3 4
      app/Http/Resources/ProviderResource.php
  64. 1 1
      app/Http/Resources/ReviewResource.php
  65. 0 1
      app/Http/Resources/UserResource.php
  66. 33 8
      app/Notifications/Push/Cliente/Contextual/ContextualSegundaPush.php
  67. 33 8
      app/Notifications/Push/Cliente/Contextual/ContextualSextaPush.php
  68. 23 5
      app/Notifications/Push/Cliente/Contextual/ContextualVisitaPush.php
  69. 23 5
      app/Notifications/Push/Cliente/Educativo/Educativo1Push.php
  70. 23 5
      app/Notifications/Push/Cliente/Educativo/Educativo2Push.php
  71. 23 5
      app/Notifications/Push/Cliente/Educativo/Educativo3Push.php
  72. 23 5
      app/Notifications/Push/Cliente/Educativo/Educativo4Push.php
  73. 32 7
      app/Notifications/Push/Cliente/EducativoConversao/EducativoConversao1Push.php
  74. 32 7
      app/Notifications/Push/Cliente/EducativoConversao/EducativoConversao2Push.php
  75. 23 5
      app/Notifications/Push/Cliente/Marketing/Marketing1Push.php
  76. 23 5
      app/Notifications/Push/Cliente/Marketing/Marketing2Push.php
  77. 23 5
      app/Notifications/Push/Cliente/Marketing/Marketing3Push.php
  78. 23 5
      app/Notifications/Push/Cliente/Marketing/Marketing4Push.php
  79. 23 5
      app/Notifications/Push/Cliente/Motivacional/Motivacional1Push.php
  80. 23 5
      app/Notifications/Push/Cliente/Motivacional/Motivacional2Push.php
  81. 23 5
      app/Notifications/Push/Cliente/Motivacional/Motivacional3Push.php
  82. 23 5
      app/Notifications/Push/Cliente/Recorrencia/Recorrencia1Push.php
  83. 23 5
      app/Notifications/Push/Cliente/Recorrencia/Recorrencia2Push.php
  84. 23 5
      app/Notifications/Push/Cliente/Recorrencia/Recorrencia3Push.php
  85. 32 7
      app/Notifications/Push/Cliente/SocialProof/SocialProof1Push.php
  86. 32 7
      app/Notifications/Push/Cliente/SocialProof/SocialProof2Push.php
  87. 10 10
      app/Notifications/Push/Prestador/ReforcoEducativo/ReforcoEducativo1Push.php
  88. 238 231
      app/Services/AuthService.php
  89. 7 9
      app/Services/CustomScheduleService.php
  90. 21 21
      app/Services/DashboardService.php
  91. 1 1
      app/Services/DistanceService.php
  92. 1 1
      app/Services/MediaService.php
  93. 2 2
      app/Services/NotificationService.php
  94. 2 3
      app/Services/Pagarme/Concerns/SendsPagarmeRequests.php
  95. 8 8
      app/Services/Pagarme/PagarmeCardService.php
  96. 74 12
      app/Services/Pagarme/PagarmeCustomerService.php
  97. 272 42
      app/Services/Pagarme/PagarmePaymentService.php
  98. 201 10
      app/Services/Pagarme/PagarmeRecipientService.php
  99. 40 52
      app/Services/Pagarme/PagarmeTransferService.php
  100. 17 208
      app/Services/PaymentService.php

+ 62 - 0
app/Data/Pagarme/PagarmeResponseData.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Data\Pagarme;
+
+abstract readonly class PagarmeResponseData
+{
+    abstract public static function fromArray(array $payload): static;
+
+    abstract public function toArray(): array;
+
+    //
+
+    protected static function arrGet(array $payload, int|string $key, mixed $default = null): mixed
+    {
+        return array_key_exists($key, $payload) ? $payload[$key] : $default;
+    }
+
+    protected static function arrInt(array $payload, string $key): ?int
+    {
+        if (! array_key_exists($key, $payload)) {
+            return null;
+        }
+
+        return (int) $payload[$key];
+    }
+
+    protected static function arrString(array $payload, string $key): ?string
+    {
+        if (! array_key_exists($key, $payload)) {
+            return null;
+        }
+
+        $value = $payload[$key];
+
+        return $value !== null && $value !== '' ? (string) $value : null;
+    }
+
+    protected static function arrBool(array $payload, string $key): ?bool
+    {
+        if (! array_key_exists($key, $payload)) {
+            return null;
+        }
+
+        $value = $payload[$key];
+
+        return $value !== null && $value !== '' ? (bool) $value : null;
+    }
+
+    protected static function arrArray(array $payload, string $key): array
+    {
+        if (! array_key_exists($key, $payload) || ! is_array($payload[$key])) {
+            return [];
+        }
+
+        return $payload[$key];
+    }
+
+    protected static function arrMap(array $payload, string $key, callable $fn): array
+    {
+        return array_map($fn, static::arrArray($payload, $key));
+    }
+}

+ 46 - 0
app/Data/Pagarme/Request/BankAccountUpdateRequestData.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace App\Data\Pagarme\Request;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class BankAccountUpdateRequestData extends PagarmeData
+{
+    public function __construct(
+        public string  $holderName,
+        public string  $holderType,
+        public string  $holderDocument,
+        public string  $bank,
+        public string  $branchNumber,
+        public ?string $branchCheckDigit,
+        public string  $accountNumber,
+        public string  $accountCheckDigit,
+        public string  $type,
+    ) {
+        self::requireFilled($this->holderName, 'bank_account.holder_name');
+        self::requireIn($this->holderType, ['individual', 'company'], 'bank_account.holder_type');
+        self::requireFilled($this->holderDocument, 'bank_account.holder_document');
+        self::requireFilled($this->bank, 'bank_account.bank');
+        self::requireFilled($this->branchNumber, 'bank_account.branch_number');
+        self::requireFilled($this->accountNumber, 'bank_account.account_number');
+        self::requireFilled($this->accountCheckDigit, 'bank_account.account_check_digit');
+        self::requireFilled($this->type, 'bank_account.type');
+    }
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'bank_account' => [
+                'holder_name'         => $this->holderName,
+                'holder_type'         => $this->holderType,
+                'holder_document'     => $this->holderDocument,
+                'bank'                => $this->bank,
+                'branch_number'       => $this->branchNumber,
+                'branch_check_digit'  => $this->branchCheckDigit,
+                'account_number'      => $this->accountNumber,
+                'account_check_digit' => $this->accountCheckDigit,
+                'type'                => $this->type,
+            ],
+        ]);
+    }
+}

+ 14 - 13
app/Data/Pagarme/Request/PagarmeCardRequestData/PagarmeCardBillingAddressData.php → app/Data/Pagarme/Request/CardRequestData/CardBillingAddressData.php

@@ -1,19 +1,19 @@
 <?php
 
-namespace App\Data\Pagarme\Request\PagarmeCardRequestData;
+namespace App\Data\Pagarme\Request\CardRequestData;
 
 use App\Data\Pagarme\PagarmeData;
 use App\Models\Address;
 
-final readonly class PagarmeCardBillingAddressData extends PagarmeData
+final readonly class CardBillingAddressData extends PagarmeData
 {
     public function __construct(
-        public string $line1,
+        public string  $line1,
         public ?string $line2,
-        public string $zipCode,
-        public string $city,
-        public string $state,
-        public string $country,
+        public string  $zipCode,
+        public string  $city,
+        public string  $state,
+        public string  $country,
     ) {
         self::requireFilled($this->line1, 'billing_address.line_1');
         self::requireFilled($this->zipCode, 'billing_address.zip_code');
@@ -25,8 +25,7 @@ final readonly class PagarmeCardBillingAddressData extends PagarmeData
     public static function fromAddress(?Address $address): self
     {
         $state = $address?->state?->code ?? $address?->city?->state?->code;
-
-        $city = $address?->city?->name;
+        $city  = $address?->city?->name;
 
         $line1 = implode(', ', array_filter([
             $address?->number ?: 'S/N',
@@ -35,15 +34,17 @@ final readonly class PagarmeCardBillingAddressData extends PagarmeData
         ]));
 
         return new self(
-            line1: $line1,
-            line2: $address?->complement ?: $address?->instructions,
+            line1:   $line1,
+            line2:   $address?->complement ?: $address?->instructions,
             zipCode: self::digits($address?->zip_code),
-            city: (string) $city,
-            state: (string) $state,
+            city:    (string) $city,
+            state:   (string) $state,
             country: 'BR',
         );
     }
 
+    //
+
     public function toArray(): array
     {
         return $this->filterFilledRecursive([

+ 4 - 4
app/Data/Pagarme/Request/PagarmeCardRequestData/PagarmeCardRequestData.php → app/Data/Pagarme/Request/CardRequestData/CardRequestData.php

@@ -1,15 +1,15 @@
 <?php
 
-namespace App\Data\Pagarme\Request\PagarmeCardRequestData;
+namespace App\Data\Pagarme\Request\CardRequestData;
 
 use App\Data\Pagarme\PagarmeData;
 
-final readonly class PagarmeCardRequestData extends PagarmeData
+final readonly class CardRequestData extends PagarmeData
 {
     public function __construct(
-        public string $token,
+        public string  $token,
         public ?string $label = null,
-        public ?PagarmeCardBillingAddressData $billingAddress = null,
+        public ?CardBillingAddressData $billingAddress = null,
     ) {
         self::requireFilled($this->token, 'token');
     }

+ 29 - 0
app/Data/Pagarme/Request/CustomerRequestData/CustomerAddressRequestData.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Data\Pagarme\Request\CustomerRequestData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class CustomerAddressRequestData extends PagarmeData
+{
+    public function __construct(
+        public ?string $line1,
+        public ?string $line2,
+        public ?string $zipCode,
+        public ?string $city,
+        public ?string $state,
+        public ?string $country,
+    ) {}
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'line_1'   => $this->line1,
+            'line_2'   => $this->line2,
+            'zip_code' => $this->zipCode,
+            'city'     => $this->city,
+            'state'    => $this->state,
+            'country'  => $this->country,
+        ]);
+    }
+}

+ 2 - 2
app/Data/Pagarme/Request/PagarmeCustomerRequestData/PagarmeCustomerPhonesRequestData/PagarmeCustomerPhoneData.php → app/Data/Pagarme/Request/CustomerRequestData/CustomerPhonesRequestData/CustomerPhoneData.php

@@ -1,10 +1,10 @@
 <?php
 
-namespace App\Data\Pagarme\Request\PagarmeCustomerRequestData\PagarmeCustomerPhonesRequestData;
+namespace App\Data\Pagarme\Request\CustomerRequestData\CustomerPhonesRequestData;
 
 use App\Data\Pagarme\PagarmeData;
 
-final readonly class PagarmeCustomerPhoneData extends PagarmeData
+final readonly class CustomerPhoneData extends PagarmeData
 {
     public function __construct(
         public string $countryCode,

+ 19 - 0
app/Data/Pagarme/Request/CustomerRequestData/CustomerPhonesRequestData/CustomerPhonesRequestData.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Data\Pagarme\Request\CustomerRequestData\CustomerPhonesRequestData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class CustomerPhonesRequestData extends PagarmeData
+{
+    public function __construct(
+        public ?CustomerPhoneData $mobilePhone = null,
+    ) {}
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'mobile_phone' => $this->mobilePhone,
+        ]);
+    }
+}

+ 5 - 27
app/Data/Pagarme/Request/PagarmeCustomerRequestData/PagarmeCustomerRequestData.php → app/Data/Pagarme/Request/CustomerRequestData/CustomerRequestData.php

@@ -1,11 +1,11 @@
 <?php
 
-namespace App\Data\Pagarme\Request\PagarmeCustomerRequestData;
+namespace App\Data\Pagarme\Request\CustomerRequestData;
 
 use App\Data\Pagarme\PagarmeData;
-use App\Data\Pagarme\Request\PagarmeCustomerRequestData\PagarmeCustomerPhonesRequestData\PagarmeCustomerPhonesRequestData;
+use App\Data\Pagarme\Request\CustomerRequestData\CustomerPhonesRequestData\CustomerPhonesRequestData;
 
-final readonly class PagarmeCustomerRequestData extends PagarmeData
+final readonly class CustomerRequestData extends PagarmeData
 {
     public function __construct(
         public string $name,
@@ -14,8 +14,8 @@ final readonly class PagarmeCustomerRequestData extends PagarmeData
         public string $type,
         public string $documentType,
         public string $code,
-        public ?PagarmeCustomerAddressRequestData $address = null,
-        public ?PagarmeCustomerPhonesRequestData $phones = null,
+        public ?CustomerAddressRequestData $address = null,
+        public ?CustomerPhonesRequestData  $phones  = null,
     ) {
         self::requireFilled($this->name, 'name');
         self::requireFilled($this->email, 'email');
@@ -25,28 +25,6 @@ final readonly class PagarmeCustomerRequestData extends PagarmeData
         self::requireFilled($this->code, 'code');
     }
 
-    public static function fromPayload(
-        ?string $name,
-        ?string $email,
-        ?string $document,
-        string $code,
-        array $addressData = [],
-        ?string $phone = null,
-    ): self {
-        $document = self::digits($document);
-
-        return new self(
-            name: $name ?: 'Cliente',
-            email: (string) $email,
-            document: $document,
-            type: strlen($document) === 14 ? 'company' : 'individual',
-            documentType: strlen($document) === 14 ? 'CNPJ' : 'CPF',
-            code: $code,
-            address: PagarmeCustomerAddressRequestData::fromPayload($addressData),
-            phones: PagarmeCustomerPhonesRequestData::fromPhone($phone),
-        );
-    }
-
     public function toArray(): array
     {
         return $this->filterFilledRecursive([

+ 29 - 0
app/Data/Pagarme/Request/OrderRequestData/OrderItemData.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Data\Pagarme\Request\OrderRequestData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class OrderItemData extends PagarmeData
+{
+    public function __construct(
+        public string  $code,
+        public int     $amount,
+        public int     $quantity,
+        public ?string $description = null,
+    ) {
+        self::requireFilled($this->code, 'items.code');
+        self::requirePositiveInt($this->amount, 'items.amount');
+        self::requirePositiveInt($this->quantity, 'items.quantity');
+    }
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'code'        => $this->code,
+            'amount'      => $this->amount,
+            'quantity'    => $this->quantity,
+            'description' => $this->description,
+        ]);
+    }
+}

+ 27 - 0
app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderCreditCardData.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class OrderCreditCardData extends PagarmeData
+{
+    public function __construct(
+        public string  $cardId,
+        public ?int    $installments        = null,
+        public ?string $statementDescriptor = null,
+        public ?string $operationType       = null,
+    ) {
+        self::requireFilled($this->cardId, 'credit_card.card_id');
+    }
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'card_id'              => $this->cardId,
+            'installments'         => $this->installments,
+            'statement_descriptor' => $this->statementDescriptor,
+            'operation_type'       => $this->operationType,
+        ]);
+    }
+}

+ 74 - 0
app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderPaymentData.php

@@ -0,0 +1,74 @@
+<?php
+
+namespace App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class OrderPaymentData extends PagarmeData
+{
+    /**
+     * @param  OrderSplitData[]|null  $split
+     */
+
+    public function __construct(
+        public string $paymentMethod,
+        public ?OrderCreditCardData $creditCard = null, public ?OrderPixData $pix = null,
+        public ?array $split = null,
+    ) {
+        self::requireIn($this->paymentMethod, ['credit_card', 'pix'], 'payments.payment_method');
+
+        if ($this->paymentMethod === 'credit_card' && ! $this->creditCard) {
+            throw new \InvalidArgumentException('payments.credit_card e obrigatorio para credit_card.');
+        }
+
+        if ($this->paymentMethod === 'pix' && ! $this->pix) {
+            throw new \InvalidArgumentException('payments.pix e obrigatorio para pix.');
+        }
+    }
+
+    /**
+     * @param  OrderSplitData[]|null  $split
+     */
+
+    public static function creditCard(OrderCreditCardData $creditCard, ?array $split = null): self
+    {
+        return new self(
+            paymentMethod: 'credit_card',
+            creditCard:    $creditCard,
+            split:         $split,
+        );
+    }
+
+    /**
+     * @param  OrderSplitData[]|null  $split
+     */
+
+    public static function pix(OrderPixData $pix, ?array $split = null): self
+    {
+        return new self(
+            paymentMethod: 'pix',
+            pix:           $pix,
+            split:         $split,
+        );
+    }
+
+    //
+
+    public function toArray(): array
+    {
+        $payload = $this->filterFilledRecursive([
+            'payment_method' => $this->paymentMethod,
+            'split'          => $this->split,
+        ]);
+
+        if ($this->creditCard) {
+            $payload['credit_card'] = $this->creditCard->toArray();
+        }
+
+        if ($this->pix) {
+            $payload['pix'] = $this->pix->toArray();
+        }
+
+        return $payload;
+    }
+}

+ 24 - 0
app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderPixAdditionalInformationData.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class OrderPixAdditionalInformationData extends PagarmeData
+{
+    public function __construct(
+        public string $name,
+        public string $value,
+    ) {
+        self::requireFilled($this->name, 'additional_information.name');
+        self::requireFilled($this->value, 'additional_information.value');
+    }
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'name'  => $this->name,
+            'value' => $this->value,
+        ]);
+    }
+}

+ 31 - 0
app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderPixData.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class OrderPixData extends PagarmeData
+{
+    /**
+     * @param  OrderPixAdditionalInformationData[]|null  $additionalInformation
+     */
+
+    public function __construct(
+        public ?int   $expiresIn             = null,
+        public ?array $additionalInformation = null,
+    ) {
+        if ($this->expiresIn === null) {
+            throw new \InvalidArgumentException(
+                'pix.expires_in e obrigatorio.'
+            );
+        }
+    }
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'expires_in'             => $this->expiresIn,
+            'additional_information' => $this->additionalInformation,
+        ]);
+    }
+}

+ 29 - 0
app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderSplitData.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class OrderSplitData extends PagarmeData
+{
+    public function __construct(
+        public int    $amount,
+        public string $recipientId,
+        public string $type = 'flat',
+        public ?OrderSplitOptionsData $options = null,
+    ) {
+        self::requirePositiveInt($this->amount, 'split.amount');
+        self::requireFilled($this->recipientId, 'split.recipient_id');
+        self::requireFilled($this->type, 'split.type');
+    }
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'amount'       => $this->amount,
+            'recipient_id' => $this->recipientId,
+            'type'         => $this->type,
+            'options'      => $this->options,
+        ]);
+    }
+}

+ 23 - 0
app/Data/Pagarme/Request/OrderRequestData/OrderPaymentData/OrderSplitOptionsData.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class OrderSplitOptionsData extends PagarmeData
+{
+    public function __construct(
+        public bool $chargeProcessingFee = false,
+        public bool $chargeRemainderFee  = false,
+        public bool $liable              = false,
+    ) {}
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'charge_processing_fee' => $this->chargeProcessingFee,
+            'charge_remainder_fee'  => $this->chargeRemainderFee,
+            'liable'                => $this->liable,
+        ]);
+    }
+}

+ 113 - 0
app/Data/Pagarme/Request/OrderRequestData/OrderRequestData.php

@@ -0,0 +1,113 @@
+<?php
+
+namespace App\Data\Pagarme\Request\OrderRequestData;
+
+use App\Data\Pagarme\PagarmeData;
+use App\Data\Pagarme\Request\CustomerRequestData\CustomerRequestData as CustomerData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderCreditCardData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderPaymentData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderPixData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderSplitData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderSplitOptionsData;
+use App\Models\PaymentSplit;
+use Illuminate\Support\Collection;
+
+final readonly class OrderRequestData extends PagarmeData
+{
+    /**
+     * @param  OrderItemData[]  $items
+     * @param  OrderPaymentData[]  $payments
+     */
+    public function __construct(
+        public string  $code,
+        public array   $items,
+        public array   $payments,
+        public array   $metadata,
+        public ?string $customerId = null,
+        public ?string $channel    = null,
+        public bool    $closed     = true,
+
+        public ?CustomerData $customer = null,
+    ) {
+        self::requireFilled($this->code, 'code');
+
+        if (empty($this->items)) {
+            throw new \InvalidArgumentException('items nao pode estar vazio.');
+        }
+
+        if (empty($this->payments)) {
+            throw new \InvalidArgumentException('payments nao pode estar vazio.');
+        }
+
+        if (! $this->customerId && ! $this->customer) {
+            throw new \InvalidArgumentException('customer ou customer_id e obrigatorio.');
+        }
+    }
+
+    //
+
+    public static function amountInCents(float $amount): int
+    {
+        return (int) round($amount * 100);
+    }
+
+    /**
+     * @param  OrderSplitData[]|null  $split
+     */
+
+    public static function creditCardPaymentMethod(OrderCreditCardData $creditCard, ?array $split = null): OrderPaymentData
+    {
+        return OrderPaymentData::creditCard($creditCard, $split);
+    }
+
+    /**
+     * @param  OrderSplitData[]|null  $split
+     */
+
+    public static function pixPaymentMethod(OrderPixData $pix, ?array $split = null): OrderPaymentData
+    {
+        return OrderPaymentData::pix($pix, $split);
+    }
+
+    /**
+     * @param  Collection<PaymentSplit>  $transfers
+     * @return OrderSplitData[]
+     */
+
+    public static function splitFromTransfers(Collection $transfers): array
+    {
+        return $transfers
+            ->filter(fn (PaymentSplit $split) => ! empty($split->gateway_transfer_target_reference))
+            ->map(function (PaymentSplit $split) {
+                return new OrderSplitData(
+                    amount:      self::amountInCents((float) $split->gross_amount),
+                    recipientId: $split->gateway_transfer_target_reference,
+                    type:        'flat',
+
+                    options: new OrderSplitOptionsData(
+                        chargeProcessingFee: false,
+                        chargeRemainderFee:  false,
+                        liable:              false,
+                    ),
+                );
+            })
+            ->values()
+            ->all();
+    }
+
+    //
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'code'        => $this->code,
+            'items'       => $this->items,
+            'payments'    => $this->payments,
+            'closed'      => $this->closed,
+            'metadata'    => $this->metadata,
+            'customer_id' => $this->customerId,
+            'channel'     => $this->channel,
+            'customer'    => $this->customer,
+        ]);
+    }
+}

+ 0 - 100
app/Data/Pagarme/Request/PagarmeBankAccountUpdateRequestData.php

@@ -1,100 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Request;
-
-use App\Data\Pagarme\PagarmeData;
-use Illuminate\Support\Str;
-
-final readonly class PagarmeBankAccountUpdateRequestData extends PagarmeData
-{
-    public function __construct(
-        public string $holderName,
-        public string $holderType,
-        public string $holderDocument,
-        public string $bank,
-        public string $branchNumber,
-        public ?string $branchCheckDigit,
-        public string $accountNumber,
-        public string $accountCheckDigit,
-        public string $type,
-    ) {
-        self::requireFilled($this->holderName, 'bank_account.holder_name');
-        self::requireIn($this->holderType, ['individual', 'company'], 'bank_account.holder_type');
-        self::requireFilled($this->holderDocument, 'bank_account.holder_document');
-        self::requireFilled($this->bank, 'bank_account.bank');
-        self::requireFilled($this->branchNumber, 'bank_account.branch_number');
-        self::requireFilled($this->accountNumber, 'bank_account.account_number');
-        self::requireFilled($this->accountCheckDigit, 'bank_account.account_check_digit');
-        self::requireFilled($this->type, 'bank_account.type');
-    }
-
-    public static function fromArray(array $payload): self
-    {
-        return new self(
-            holderName: self::normalizeHolderName($payload['holder_name']),
-            holderType: $payload['holder_type'],
-            holderDocument: self::digits($payload['holder_document']),
-            bank: $payload['bank'],
-            branchNumber: $payload['branch_number'],
-            branchCheckDigit: $payload['branch_check_digit'] ?? null,
-            accountNumber: $payload['account_number'],
-            accountCheckDigit: $payload['account_check_digit'],
-            type: $payload['type'],
-        );
-    }
-
-    public function toArray(): array
-    {
-        return $this->filterFilledRecursive([
-            'bank_account' => [
-                'holder_name'         => $this->holderName,
-                'holder_type'         => $this->holderType,
-                'holder_document'     => $this->holderDocument,
-                'bank'                => $this->bank,
-                'branch_number'       => $this->branchNumber,
-                'branch_check_digit'  => $this->branchCheckDigit,
-                'account_number'      => $this->accountNumber,
-                'account_check_digit' => $this->accountCheckDigit,
-                'type'                => $this->type,
-            ],
-        ]);
-    }
-
-    //
-
-    private static function normalizeHolderName(string $holderName): string
-    {
-        $holderName = trim(preg_replace('/\s+/', ' ', $holderName) ?? '');
-
-        if (Str::length($holderName) < 30) {
-            return $holderName;
-        }
-
-        $parts = explode(' ', $holderName);
-
-        if (count($parts) >= 3) {
-            $firstName = array_shift($parts);
-
-            $lastName = array_pop($parts);
-
-            $initials = array_map(
-                static fn (string $part): string => Str::upper(Str::substr($part, 0, 1)),
-                $parts
-            );
-
-            $abbreviated = trim($firstName.' '.implode(' ', $initials).' '.$lastName);
-
-            if (Str::length($abbreviated) < 30) {
-                return $abbreviated;
-            }
-
-            $firstAndLast = trim($firstName.' '.$lastName);
-
-            if (Str::length($firstAndLast) < 30) {
-                return $firstAndLast;
-            }
-        }
-
-        return Str::limit($holderName, 29, '');
-    }
-}

+ 0 - 47
app/Data/Pagarme/Request/PagarmeCustomerRequestData/PagarmeCustomerAddressRequestData.php

@@ -1,47 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Request\PagarmeCustomerRequestData;
-
-use App\Data\Pagarme\PagarmeData;
-
-final readonly class PagarmeCustomerAddressRequestData extends PagarmeData
-{
-    public function __construct(
-        public ?string $line1,
-        public ?string $line2,
-        public ?string $zipCode,
-        public ?string $city,
-        public ?string $state,
-        public ?string $country,
-    ) {}
-
-    public static function fromPayload(array $data): self
-    {
-        $line1Parts = array_filter([
-            (string) ($data['number'] ?? '0'),
-            (string) ($data['address'] ?? ''),
-            (string) ($data['district'] ?? ''),
-        ], static fn ($value) => $value !== '');
-
-        return new self(
-            line1: implode(', ', $line1Parts),
-            line2: (string) ($data['complement'] ?? $data['instructions'] ?? ''),
-            zipCode: self::digits($data['zip_code'] ?? null),
-            city: (string) ($data['city'] ?? ''),
-            state: (string) ($data['state'] ?? ''),
-            country: (string) ($data['country'] ?? 'BR'),
-        );
-    }
-
-    public function toArray(): array
-    {
-        return $this->filterFilledRecursive([
-            'line_1'   => $this->line1,
-            'line_2'   => $this->line2,
-            'zip_code' => $this->zipCode,
-            'city'     => $this->city,
-            'state'    => $this->state,
-            'country'  => $this->country,
-        ]);
-    }
-}

+ 0 - 47
app/Data/Pagarme/Request/PagarmeCustomerRequestData/PagarmeCustomerPhonesRequestData/PagarmeCustomerPhonesRequestData.php

@@ -1,47 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Request\PagarmeCustomerRequestData\PagarmeCustomerPhonesRequestData;
-
-use App\Data\Pagarme\PagarmeData;
-
-final readonly class PagarmeCustomerPhonesRequestData extends PagarmeData
-{
-    public function __construct(
-        public ?PagarmeCustomerPhoneData $homePhone = null,
-        public ?PagarmeCustomerPhoneData $mobilePhone = null,
-    ) {}
-
-    public static function fromPhone(?string $phone): self
-    {
-        $digits = self::digits($phone);
-
-        if ($digits === '') {
-            return new self;
-        }
-
-        $areaCode = substr($digits, 0, 2);
-
-        $number = substr($digits, 2);
-
-        if (strlen($digits) <= 2) {
-            $areaCode = '';
-            $number = $digits;
-        }
-
-        return new self(
-            mobilePhone: new PagarmeCustomerPhoneData(
-                countryCode: '55',
-                areaCode: $areaCode,
-                number: $number,
-            ),
-        );
-    }
-
-    public function toArray(): array
-    {
-        return $this->filterFilledRecursive([
-            'home_phone'   => $this->homePhone,
-            'mobile_phone' => $this->mobilePhone,
-        ]);
-    }
-}

+ 0 - 41
app/Data/Pagarme/Request/PagarmeCustomerRequestData/PagarmeCustomerUpdateRequestData.php

@@ -1,41 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Request\PagarmeCustomerRequestData;
-
-use App\Data\Pagarme\PagarmeData;
-
-final readonly class PagarmeCustomerUpdateRequestData extends PagarmeData
-{
-    public function __construct(
-        public ?string $name = null,
-        public ?string $email = null,
-        public ?string $document = null,
-        public ?string $type = null,
-        public ?string $documentType = null,
-        public ?string $code = null,
-        public ?PagarmeCustomerAddressRequestData $address = null,
-        public ?PagarmeCustomerPhonesRequestData $phones = null,
-    ) {
-        if ($this->type !== null) {
-            self::requireIn($this->type, ['individual', 'company'], 'type');
-        }
-
-        if ($this->documentType !== null) {
-            self::requireIn($this->documentType, ['CPF', 'CNPJ'], 'document_type');
-        }
-    }
-
-    public function toArray(): array
-    {
-        return $this->filterFilledRecursive([
-            'name'          => $this->name,
-            'email'         => $this->email,
-            'document'      => $this->document,
-            'type'          => $this->type,
-            'document_type' => $this->documentType,
-            'code'          => $this->code,
-            'address'       => $this->address,
-            'phones'        => $this->phones,
-        ]);
-    }
-}

+ 0 - 269
app/Data/Pagarme/Request/PagarmeOrderRequestData/PagarmeOrderRequestData.php

@@ -1,269 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Request\PagarmeOrderRequestData;
-
-use App\Data\Pagarme\PagarmeData;
-use App\Models\PaymentSplit;
-use Illuminate\Support\Collection;
-
-/**
- * @param  array<int, array{code?: string, amount?: int, quantity?: int, description?: string, ...}>  $items  Lista de itens do pedido
- * @param  array<int, array{payment_method: string, ...}>  $payments  Lista de formas de pagamento
- * @param  array<string, mixed>  $metadata  Metadados do pedido (ex: payment_id, schedule_id, client_id, provider_id)
- * @param  array<string, mixed>|null  $customer  Dados do cliente (name, email, document, type, etc.)
- */
-final readonly class PagarmeOrderRequestData extends PagarmeData
-{
-    public function __construct(
-        public string $code,
-        public array $items,
-        public array $payments,
-        public array $metadata,
-        public ?array $customer = null,
-        public ?string $customerId = null,
-        public bool $closed = true,
-        public ?string $channel = null,
-    ) {
-        self::requireFilled($this->code, 'code');
-
-        if (empty($this->items)) {
-            throw new \InvalidArgumentException('items nao pode estar vazio.');
-        }
-
-        if (empty($this->payments)) {
-            throw new \InvalidArgumentException('payments nao pode estar vazio.');
-        }
-
-        foreach ($this->payments as $index => $payment) {
-            if (! is_array($payment) || empty($payment['payment_method'])) {
-                throw new \InvalidArgumentException("payments.{$index}.payment_method e obrigatorio.");
-            }
-
-            self::requireIn($payment['payment_method'], ['credit_card', 'pix'], "payments.{$index}.payment_method");
-        }
-
-        if (! $this->customerId && empty($this->customer)) {
-            throw new \InvalidArgumentException('customer ou customer_id e obrigatorio.');
-        }
-    }
-
-    public static function fromOrderPayload(
-        string $code,
-        array $items,
-        array $customer,
-        array $paymentMethod,
-        array $metadata,
-        mixed $customerId = null,
-        bool $closed = true,
-        ?string $channel = null,
-    ): self {
-        if (empty($items)) {
-            throw new \InvalidArgumentException('items nao pode estar vazio.');
-        }
-
-        if (empty($paymentMethod['payment_method'])) {
-            throw new \InvalidArgumentException('payment_method e obrigatorio.');
-        }
-
-        if (! in_array($paymentMethod['payment_method'], ['credit_card', 'pix'], true)) {
-            throw new \InvalidArgumentException('payment_method deve ser credit_card ou pix.');
-        }
-
-        $customerIdPayload = self::filled($customerId) ? (string) $customerId : null;
-
-        $customerPayload = self::filterFilledRecursiveStatic($customer);
-
-        if (! $customerIdPayload && empty($customerPayload)) {
-            throw new \InvalidArgumentException('customer ou customer_id e obrigatorio.');
-        }
-
-        return new self(
-            code: $code,
-            items: self::validateItems($items),
-            payments: [self::filterFilledRecursiveStatic($paymentMethod)],
-            metadata: $metadata,
-            customer: ! empty($customerPayload) ? $customerPayload : null,
-            customerId: $customerIdPayload,
-            closed: $closed,
-            channel: $channel,
-        );
-    }
-
-    //
-
-    public static function amountInCents(float $amount): int
-    {
-        return (int) round($amount * 100);
-    }
-
-    public static function creditCardPaymentMethod(array $creditCard, ?array $split = null): array
-    {
-        return self::paymentMethodWithOptionalSplit([
-            'payment_method' => 'credit_card',
-            'credit_card'    => self::buildCreditCardPayload($creditCard),
-        ], $split);
-    }
-
-    public static function pixPaymentMethod(array $pix, ?array $split = null): array
-    {
-        return self::paymentMethodWithOptionalSplit([
-            'payment_method' => 'pix',
-            'pix'            => self::buildPixPayload($pix),
-        ], $split);
-    }
-
-    public static function splitFromTransfers(Collection $transfers): array
-    {
-        return $transfers
-            ->filter(fn (PaymentSplit $split) => ! empty($split->gateway_transfer_target_reference))
-            ->map(function (PaymentSplit $split) {
-                return [
-                    'amount'       => self::amountInCents((float) $split->gross_amount),
-                    'recipient_id' => $split->gateway_transfer_target_reference,
-                    'type'         => 'flat',
-
-                    'options' => [
-                        'charge_processing_fee' => false,
-                        'charge_remainder_fee'  => false,
-                        'liable'                => false,
-                    ],
-                ];
-            })
-            ->values()
-            ->all();
-    }
-
-    //
-
-    public function toArray(): array
-    {
-        return $this->filterFilledRecursive([
-            'code'        => $this->code,
-            'items'       => $this->items,
-            'payments'    => $this->payments,
-            'closed'      => $this->closed,
-            'metadata'    => $this->metadata,
-            'customer_id' => $this->customerId,
-            'customer'    => $this->customer,
-            'channel'     => $this->channel,
-        ]);
-    }
-
-    //
-
-    private static function buildCreditCardPayload(array $creditCard): array
-    {
-        $payload = [];
-
-        foreach ([
-            'installments',
-            'statement_descriptor',
-            'operation_type',
-            'recurrence_cycle',
-            'metadata',
-            'extended_limit_enabled',
-            'extended_limit_code',
-            'merchant_category_code',
-            'authentication',
-            'auto_recovery',
-            'payload',
-            'payment_type',
-            'funding_source',
-            'initiated_type',
-            'recurrence_model',
-            'channel',
-            'payment_origin',
-        ] as $field) {
-            if (array_key_exists($field, $creditCard) && self::filled($creditCard[$field])) {
-                $payload[$field] = $creditCard[$field];
-            }
-        }
-
-        $allowedCardOptions = ['card', 'card_id', 'card_token', 'network_token'];
-
-        $provided = array_values(array_filter(
-            $allowedCardOptions,
-            static fn (string $field) => ! empty($creditCard[$field])
-        ));
-
-        if (count($provided) !== 1) {
-            throw new \InvalidArgumentException('Informe exatamente uma opcao entre card, card_id, card_token ou network_token.');
-        }
-
-        $selected = $provided[0];
-
-        $payload[$selected] = $creditCard[$selected];
-
-        return $payload;
-    }
-
-    private static function buildPixPayload(array $pix): array
-    {
-        if (! self::filled($pix['expires_in'] ?? null) && ! self::filled($pix['expires_at'] ?? null)) {
-            throw new \InvalidArgumentException('pix.expires_in ou pix.expires_at e obrigatorio.');
-        }
-
-        $payload = [];
-
-        foreach (['expires_in', 'expires_at', 'additional_information'] as $field) {
-            if (array_key_exists($field, $pix) && self::filled($pix[$field])) {
-                $payload[$field] = $pix[$field];
-            }
-        }
-
-        return $payload;
-    }
-
-    //
-
-    private static function filled(mixed $value): bool
-    {
-        return $value !== null && $value !== '' && $value !== [];
-    }
-
-    private static function filterFilledRecursiveStatic(array $data): array
-    {
-        $filtered = [];
-
-        foreach ($data as $key => $value) {
-            if (is_array($value)) {
-                $value = self::filterFilledRecursiveStatic($value);
-            }
-
-            if (self::filled($value)) {
-                $filtered[$key] = $value;
-            }
-        }
-
-        return $filtered;
-    }
-
-    private static function paymentMethodWithOptionalSplit(array $paymentMethod, ?array $split): array
-    {
-        if (! empty($split)) {
-            $paymentMethod['split'] = $split;
-        }
-
-        return $paymentMethod;
-    }
-
-    private static function validateItems(array $items): array
-    {
-        return collect($items)
-            ->map(function (array $item, int $index) {
-                foreach (['code', 'amount', 'quantity'] as $field) {
-                    if (! array_key_exists($field, $item) || ! self::filled($item[$field])) {
-                        throw new \InvalidArgumentException("items.{$index}.{$field} e obrigatorio.");
-                    }
-                }
-
-                if ((int) $item['amount'] <= 0 || (int) $item['quantity'] <= 0) {
-                    throw new \InvalidArgumentException("items.{$index}.amount e quantity devem ser maiores que zero.");
-                }
-
-                return self::filterFilledRecursiveStatic($item);
-            })
-            ->values()
-            ->all();
-    }
-}

+ 0 - 98
app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientBankAccountData.php

@@ -1,98 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Request\PagarmeRecipientRequestData;
-
-use App\Data\Pagarme\PagarmeData;
-use Illuminate\Support\Str;
-
-final readonly class PagarmeRecipientBankAccountData extends PagarmeData
-{
-    public function __construct(
-        public string $holderName,
-        public string $holderType,
-        public string $holderDocument,
-        public string $bank,
-        public string $branchNumber,
-        public ?string $branchCheckDigit,
-        public string $accountNumber,
-        public string $accountCheckDigit,
-        public string $type,
-    ) {
-        self::requireFilled($this->holderName, 'holder_name');
-        self::requireIn($this->holderType, ['individual', 'company'], 'holder_type');
-        self::requireFilled($this->holderDocument, 'holder_document');
-        self::requireFilled($this->bank, 'bank');
-        self::requireFilled($this->branchNumber, 'branch_number');
-        self::requireFilled($this->accountNumber, 'account_number');
-        self::requireFilled($this->accountCheckDigit, 'account_check_digit');
-        self::requireFilled($this->type, 'type');
-    }
-
-    public static function fromArray(array $payload): self
-    {
-        return new self(
-            holderName: self::normalizeHolderName($payload['holder_name']),
-            holderType: $payload['holder_type'],
-            holderDocument: self::digits($payload['holder_document']),
-            bank: $payload['bank'],
-            branchNumber: $payload['branch_number'],
-            branchCheckDigit: $payload['branch_check_digit'] ?? null,
-            accountNumber: $payload['account_number'],
-            accountCheckDigit: $payload['account_check_digit'],
-            type: $payload['type'],
-        );
-    }
-
-    public function toArray(): array
-    {
-        return $this->filterFilledRecursive([
-            'holder_name'         => $this->holderName,
-            'holder_type'         => $this->holderType,
-            'holder_document'     => $this->holderDocument,
-            'bank'                => $this->bank,
-            'branch_number'       => $this->branchNumber,
-            'branch_check_digit'  => $this->branchCheckDigit,
-            'account_number'      => $this->accountNumber,
-            'account_check_digit' => $this->accountCheckDigit,
-            'type'                => $this->type,
-        ]);
-    }
-
-    //
-
-    private static function normalizeHolderName(string $holderName): string
-    {
-        $holderName = trim(preg_replace('/\s+/', ' ', $holderName) ?? '');
-
-        if (Str::length($holderName) < 30) {
-            return $holderName;
-        }
-
-        $parts = explode(' ', $holderName);
-
-        if (count($parts) >= 3) {
-            $firstName = array_shift($parts);
-
-            $lastName = array_pop($parts);
-
-            $initials = array_map(
-                static fn (string $part): string => Str::upper(Str::substr($part, 0, 1)),
-                $parts
-            );
-
-            $abbreviated = trim($firstName.' '.implode(' ', $initials).' '.$lastName);
-
-            if (Str::length($abbreviated) < 30) {
-                return $abbreviated;
-            }
-
-            $firstAndLast = trim($firstName.' '.$lastName);
-
-            if (Str::length($firstAndLast) < 30) {
-                return $firstAndLast;
-            }
-        }
-
-        return Str::limit($holderName, 29, '');
-    }
-}

+ 0 - 17
app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientRegisterInformationData/PagarmeRecipientPhoneNumbersData/PagarmeRecipientPhoneNumbersData.php

@@ -1,17 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientPhoneNumbersData;
-
-use App\Data\Pagarme\PagarmeData;
-
-final readonly class PagarmeRecipientPhoneNumbersData extends PagarmeData
-{
-    public function __construct(
-        public PagarmeRecipientPhoneData $phone,
-    ) {}
-
-    public function toArray(): array
-    {
-        return [$this->phone->toArray()];
-    }
-}

+ 0 - 140
app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientRequestData.php

@@ -1,140 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Request\PagarmeRecipientRequestData;
-
-use App\Data\Pagarme\PagarmeData;
-use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientAddressData;
-use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientPhoneNumbersData\PagarmeRecipientPhoneData;
-use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientPhoneNumbersData\PagarmeRecipientPhoneNumbersData;
-use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientRegisterInformationData;
-use Carbon\Carbon;
-
-final readonly class PagarmeRecipientRequestData extends PagarmeData
-{
-    public function __construct(
-        public string $code,
-        public PagarmeRecipientRegisterInformationData $registerInformation,
-        public PagarmeRecipientBankAccountData $defaultBankAccount,
-        public PagarmeRecipientTransferSettingsData $transferSettings,
-        public PagarmeRecipientAutomaticAnticipationSettingsData $automaticAnticipationSettings,
-    ) {
-        self::requireFilled($this->code, 'code');
-    }
-
-    public static function fromPayload(string $code, array $data): self
-    {
-        $addressParts = self::extractAddressParts($data);
-
-        return new self(
-            code: $code,
-            registerInformation: new PagarmeRecipientRegisterInformationData(
-                name: $data['recipient_name'],
-                email: $data['recipient_email'],
-                document: self::digits($data['recipient_document'] ?? null),
-                type: $data['recipient_type'] ?? 'individual',
-                birthdate: self::formatBirthdate($data['birth_date'] ?? null),
-                monthlyIncome: isset($data['monthly_income']) ? (int) $data['monthly_income'] : 1000,
-                professionalOccupation: $data['professional_occupation'] ?? 'autonomo',
-                phoneNumbers: new PagarmeRecipientPhoneNumbersData(self::phoneFromPayload($data['phone'] ?? null)),
-                address: new PagarmeRecipientAddressData(
-                    street: $data['address'],
-                    complementary: $addressParts['complementary'],
-                    streetNumber: $addressParts['street_number'],
-                    neighborhood: $addressParts['neighborhood'],
-                    city: $data['city'] ?? null,
-                    state: $data['state'] ?? null,
-                    zipCode: self::digits($data['zip_code'] ?? null),
-                    referencePoint: $addressParts['reference_point'],
-                ),
-            ),
-            defaultBankAccount: PagarmeRecipientBankAccountData::fromArray($data['recipient_default_bank_account']),
-            transferSettings: new PagarmeRecipientTransferSettingsData(
-                transferEnabled: false,
-                transferInterval: 'Daily',
-                transferDay: 0,
-            ),
-            automaticAnticipationSettings: new PagarmeRecipientAutomaticAnticipationSettingsData(
-                enabled: false,
-            ),
-        );
-    }
-
-    public function toArray(): array
-    {
-        return $this->filterFilledRecursive([
-            'code'                            => $this->code,
-            'register_information'            => $this->registerInformation,
-            'default_bank_account'            => $this->defaultBankAccount,
-            'transfer_settings'               => $this->transferSettings,
-            'automatic_anticipation_settings' => $this->automaticAnticipationSettings,
-        ]);
-    }
-
-    //
-
-    private static function extractAddressParts(array $data): array
-    {
-        $addressLine = trim((string) ($data['address'] ?? ''));
-
-        $segments = array_map('trim', explode(',', $addressLine));
-
-        $streetSegment = $segments[0] ?? '';
-
-        if (($data['number'] ?? null) === null) {
-            preg_match('/^(\d+)/', $streetSegment, $matches);
-        }
-
-        return [
-            'street_number'   => (string) ($data['number'] ?? $matches[1] ?? 'S/N'),
-            'neighborhood'    => (string) ($data['district'] ?? $segments[1] ?? 'N/A'),
-            'reference_point' => (string) ($data['reference_point'] ?? 'N/A'),
-            'complementary'   => (string) ($data['complement'] ?? 'N/A'),
-        ];
-    }
-
-    private static function formatBirthdate(mixed $birthdate): ?string
-    {
-        if ($birthdate === null || $birthdate === '') {
-            return null;
-        }
-
-        if ($birthdate instanceof \DateTimeInterface) {
-            return Carbon::instance($birthdate)->format('d/m/Y');
-        }
-
-        $birthdate = trim((string) $birthdate);
-
-        if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $birthdate) === 1) {
-            return $birthdate;
-        }
-
-        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $birthdate) === 1) {
-            return Carbon::createFromFormat('Y-m-d', $birthdate)->format('d/m/Y');
-        }
-
-        return Carbon::parse($birthdate)->format('d/m/Y');
-    }
-
-    private static function phoneFromPayload(?string $phone): PagarmeRecipientPhoneData
-    {
-        $digits = self::digits($phone);
-
-        if (strlen($digits) < 10) {
-            return new PagarmeRecipientPhoneData(
-                ddd: '11',
-                number: '999999999',
-                type: 'mobile',
-            );
-        }
-
-        if (str_starts_with($digits, '55')) {
-            $digits = substr($digits, 2);
-        }
-
-        return new PagarmeRecipientPhoneData(
-            ddd: substr($digits, 0, 2),
-            number: substr($digits, 2),
-            type: 'mobile',
-        );
-    }
-}

+ 2 - 2
app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientAutomaticAnticipationSettingsData.php → app/Data/Pagarme/Request/RecipientRequestData/RecipientAutomaticAnticipationSettingsData.php

@@ -1,10 +1,10 @@
 <?php
 
-namespace App\Data\Pagarme\Request\PagarmeRecipientRequestData;
+namespace App\Data\Pagarme\Request\RecipientRequestData;
 
 use App\Data\Pagarme\PagarmeData;
 
-final readonly class PagarmeRecipientAutomaticAnticipationSettingsData extends PagarmeData
+final readonly class RecipientAutomaticAnticipationSettingsData extends PagarmeData
 {
     public function __construct(
         public bool $enabled,

+ 44 - 0
app/Data/Pagarme/Request/RecipientRequestData/RecipientBankAccountData.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace App\Data\Pagarme\Request\RecipientRequestData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class RecipientBankAccountData extends PagarmeData
+{
+    public function __construct(
+        public string  $holderName,
+        public string  $holderType,
+        public string  $holderDocument,
+        public string  $bank,
+        public string  $branchNumber,
+        public ?string $branchCheckDigit,
+        public string  $accountNumber,
+        public string  $accountCheckDigit,
+        public string  $type,
+    ) {
+        self::requireFilled($this->holderName, 'holder_name');
+        self::requireIn($this->holderType, ['individual', 'company'], 'holder_type');
+        self::requireFilled($this->holderDocument, 'holder_document');
+        self::requireFilled($this->bank, 'bank');
+        self::requireFilled($this->branchNumber, 'branch_number');
+        self::requireFilled($this->accountNumber, 'account_number');
+        self::requireFilled($this->accountCheckDigit, 'account_check_digit');
+        self::requireFilled($this->type, 'type');
+    }
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'holder_name'         => $this->holderName,
+            'holder_type'         => $this->holderType,
+            'holder_document'     => $this->holderDocument,
+            'bank'                => $this->bank,
+            'branch_number'       => $this->branchNumber,
+            'branch_check_digit'  => $this->branchCheckDigit,
+            'account_number'      => $this->accountNumber,
+            'account_check_digit' => $this->accountCheckDigit,
+            'type'                => $this->type,
+        ]);
+    }
+}

+ 8 - 8
app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientRegisterInformationData/PagarmeRecipientAddressData.php → app/Data/Pagarme/Request/RecipientRequestData/RecipientRegisterInformationData/RecipientAddressData.php

@@ -1,20 +1,20 @@
 <?php
 
-namespace App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData;
+namespace App\Data\Pagarme\Request\RecipientRequestData\RecipientRegisterInformationData;
 
 use App\Data\Pagarme\PagarmeData;
 
-final readonly class PagarmeRecipientAddressData extends PagarmeData
+final readonly class RecipientAddressData extends PagarmeData
 {
     public function __construct(
-        public string $street,
-        public string $complementary,
-        public string $streetNumber,
-        public string $neighborhood,
+        public string  $street,
+        public string  $complementary,
+        public string  $streetNumber,
+        public string  $neighborhood,
         public ?string $city,
         public ?string $state,
-        public string $zipCode,
-        public string $referencePoint,
+        public string  $zipCode,
+        public string  $referencePoint,
     ) {
         self::requireFilled($this->street, 'register_information.address.street');
         self::requireFilled($this->streetNumber, 'register_information.address.street_number');

+ 2 - 2
app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientRegisterInformationData/PagarmeRecipientPhoneNumbersData/PagarmeRecipientPhoneData.php → app/Data/Pagarme/Request/RecipientRequestData/RecipientRegisterInformationData/RecipientPhoneNumbersData/RecipientPhoneData.php

@@ -1,10 +1,10 @@
 <?php
 
-namespace App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientPhoneNumbersData;
+namespace App\Data\Pagarme\Request\RecipientRequestData\RecipientRegisterInformationData\RecipientPhoneNumbersData;
 
 use App\Data\Pagarme\PagarmeData;
 
-final readonly class PagarmeRecipientPhoneData extends PagarmeData
+final readonly class RecipientPhoneData extends PagarmeData
 {
     public function __construct(
         public string $ddd,

+ 17 - 0
app/Data/Pagarme/Request/RecipientRequestData/RecipientRegisterInformationData/RecipientPhoneNumbersData/RecipientPhoneNumbersData.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App\Data\Pagarme\Request\RecipientRequestData\RecipientRegisterInformationData\RecipientPhoneNumbersData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class RecipientPhoneNumbersData extends PagarmeData
+{
+    public function __construct(
+        public RecipientPhoneData $phone,
+    ) {}
+
+    public function toArray(): array
+    {
+        return [$this->phone->toArray()];
+    }
+}

+ 10 - 11
app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientRegisterInformationData/PagarmeRecipientRegisterInformationData.php → app/Data/Pagarme/Request/RecipientRequestData/RecipientRegisterInformationData/RecipientRegisterInformationData.php

@@ -1,22 +1,21 @@
 <?php
 
-namespace App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData;
+namespace App\Data\Pagarme\Request\RecipientRequestData\RecipientRegisterInformationData;
 
 use App\Data\Pagarme\PagarmeData;
-use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRegisterInformationData\PagarmeRecipientPhoneNumbersData\PagarmeRecipientPhoneNumbersData;
+use App\Data\Pagarme\Request\RecipientRequestData\RecipientRegisterInformationData\RecipientPhoneNumbersData\RecipientPhoneNumbersData;
 
-final readonly class PagarmeRecipientRegisterInformationData extends PagarmeData
+final readonly class RecipientRegisterInformationData extends PagarmeData
 {
     public function __construct(
-        public string $name,
-        public string $email,
-        public string $document,
-        public string $type,
+        public string  $name,
+        public string  $email,
+        public string  $document,
+        public string  $type,
         public ?string $birthdate,
-        public int $monthlyIncome,
-        public string $professionalOccupation,
-        public PagarmeRecipientPhoneNumbersData $phoneNumbers,
-        public PagarmeRecipientAddressData $address,
+        public int     $monthlyIncome,
+        public string  $professionalOccupation,
+        public RecipientPhoneNumbersData $phoneNumbers, public RecipientAddressData $address,
     ) {
         self::requireFilled($this->name, 'register_information.name');
         self::requireFilled($this->email, 'register_information.email');

+ 29 - 0
app/Data/Pagarme/Request/RecipientRequestData/RecipientRequestData.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Data\Pagarme\Request\RecipientRequestData;
+
+use App\Data\Pagarme\PagarmeData;
+
+final readonly class RecipientRequestData extends PagarmeData
+{
+    public function __construct(
+        public string $code,
+        public RecipientRegisterInformationData $registerInformation,
+        public RecipientBankAccountData         $defaultBankAccount,
+        public RecipientTransferSettingsData    $transferSettings,
+        public RecipientAutomaticAnticipationSettingsData $automaticAnticipationSettings,
+    ) {
+        self::requireFilled($this->code, 'code');
+    }
+
+    public function toArray(): array
+    {
+        return $this->filterFilledRecursive([
+            'code'                            => $this->code,
+            'register_information'            => $this->registerInformation,
+            'default_bank_account'            => $this->defaultBankAccount,
+            'transfer_settings'               => $this->transferSettings,
+            'automatic_anticipation_settings' => $this->automaticAnticipationSettings,
+        ]);
+    }
+}

+ 4 - 4
app/Data/Pagarme/Request/PagarmeRecipientRequestData/PagarmeRecipientTransferSettingsData.php → app/Data/Pagarme/Request/RecipientRequestData/RecipientTransferSettingsData.php

@@ -1,15 +1,15 @@
 <?php
 
-namespace App\Data\Pagarme\Request\PagarmeRecipientRequestData;
+namespace App\Data\Pagarme\Request\RecipientRequestData;
 
 use App\Data\Pagarme\PagarmeData;
 
-final readonly class PagarmeRecipientTransferSettingsData extends PagarmeData
+final readonly class RecipientTransferSettingsData extends PagarmeData
 {
     public function __construct(
-        public bool $transferEnabled,
+        public bool   $transferEnabled,
         public string $transferInterval,
-        public int $transferDay,
+        public int    $transferDay,
     ) {
         self::requireIn($this->transferInterval, ['Daily', 'Weekly', 'Monthly'], 'transfer_interval');
 

+ 2 - 4
app/Data/Pagarme/Request/PagarmeTransferRequestData.php → app/Data/Pagarme/Request/TransferRequestData.php

@@ -4,12 +4,11 @@ namespace App\Data\Pagarme\Request;
 
 use App\Data\Pagarme\PagarmeData;
 
-final readonly class PagarmeTransferRequestData extends PagarmeData
+final readonly class TransferRequestData extends PagarmeData
 {
     public function __construct(
-        public int $amount,
+        public int    $amount,
         public string $recipientId,
-        public ?array $metadata = null,
     ) {
         self::requirePositiveInt($this->amount, 'amount');
         self::requireFilled($this->recipientId, 'recipient_id');
@@ -20,7 +19,6 @@ final readonly class PagarmeTransferRequestData extends PagarmeData
         return $this->filterFilledRecursive([
             'amount'       => $this->amount,
             'recipient_id' => $this->recipientId,
-            'metadata'     => $this->metadata,
         ]);
     }
 }

+ 15 - 30
app/Data/Pagarme/Response/PagarmeCardResponseData.php → app/Data/Pagarme/Response/CardResponseData.php

@@ -2,7 +2,7 @@
 
 namespace App\Data\Pagarme\Response;
 
-final readonly class PagarmeCardResponseData
+final readonly class CardResponseData extends PagarmeResponseData
 {
     public function __construct(
         public ?string $id,
@@ -10,29 +10,14 @@ final readonly class PagarmeCardResponseData
         public ?string $lastFourDigits,
         public ?string $brand,
         public ?string $holderName,
-        public ?int $expMonth,
-        public ?int $expYear,
+        public ?int    $expMonth,
+        public ?int    $expYear,
         public ?string $status,
         public ?string $type,
         public ?string $createdAt = null,
         public ?string $updatedAt = null,
     ) {}
 
-    public function brand(): ?string
-    {
-        return $this->brand;
-    }
-
-    public function id(): ?string
-    {
-        return $this->id;
-    }
-
-    public function lastFourDigits(): ?string
-    {
-        return $this->lastFourDigits;
-    }
-
     public function requireId(): string
     {
         if (! $this->id) {
@@ -44,20 +29,20 @@ final readonly class PagarmeCardResponseData
 
     //
 
-    public static function fromArray(array $payload): self
+    public static function fromArray(array $payload): static
     {
         return new self(
-            id: $payload['id'] ?? null,
-            firstSixDigits: $payload['first_six_digits'] ?? null,
-            lastFourDigits: $payload['last_four_digits'] ?? null,
-            brand: $payload['brand'] ?? null,
-            holderName: $payload['holder_name'] ?? null,
-            expMonth: isset($payload['exp_month']) ? (int) $payload['exp_month'] : null,
-            expYear: isset($payload['exp_year']) ? (int) $payload['exp_year'] : null,
-            status: $payload['status'] ?? null,
-            type: $payload['type'] ?? null,
-            createdAt: $payload['created_at'] ?? null,
-            updatedAt: $payload['updated_at'] ?? null,
+            id:             static::arrString($payload, 'id'),
+            firstSixDigits: static::arrString($payload, 'first_six_digits'),
+            lastFourDigits: static::arrString($payload, 'last_four_digits'),
+            brand:          static::arrString($payload, 'brand'),
+            holderName:     static::arrString($payload, 'holder_name'),
+            expMonth:       static::arrInt($payload, 'exp_month'),
+            expYear:        static::arrInt($payload, 'exp_year'),
+            status:         static::arrString($payload, 'status'),
+            type:           static::arrString($payload, 'type'),
+            createdAt:      static::arrString($payload, 'created_at'),
+            updatedAt:      static::arrString($payload, 'updated_at'),
         );
     }
 

+ 15 - 17
app/Data/Pagarme/Response/PagarmeCustomerResponseData/PagarmeCustomerAddressResponseData.php → app/Data/Pagarme/Response/CustomerResponseData/CustomerAddressResponseData.php

@@ -1,8 +1,10 @@
 <?php
 
-namespace App\Data\Pagarme\Response\PagarmeCustomerResponseData;
+namespace App\Data\Pagarme\Response\CustomerResponseData;
 
-final readonly class PagarmeCustomerAddressResponseData
+use App\Data\Pagarme\PagarmeResponseData;
+
+final readonly class CustomerAddressResponseData extends PagarmeResponseData
 {
     public function __construct(
         public ?string $id,
@@ -17,23 +19,19 @@ final readonly class PagarmeCustomerAddressResponseData
         public ?string $updatedAt = null,
     ) {}
 
-    public static function fromArray(?array $payload): ?self
+    public static function fromArray(array $payload): static
     {
-        if (empty($payload)) {
-            return null;
-        }
-
         return new self(
-            id: $payload['id'] ?? null,
-            line1: $payload['line_1'] ?? null,
-            line2: $payload['line_2'] ?? null,
-            zipCode: $payload['zip_code'] ?? null,
-            city: $payload['city'] ?? null,
-            state: $payload['state'] ?? null,
-            country: $payload['country'] ?? null,
-            status: $payload['status'] ?? null,
-            createdAt: $payload['created_at'] ?? null,
-            updatedAt: $payload['updated_at'] ?? null,
+            id:        static::arrString($payload, 'id'),
+            line1:     static::arrString($payload, 'line_1'),
+            line2:     static::arrString($payload, 'line_2'),
+            zipCode:   static::arrString($payload, 'zip_code'),
+            city:      static::arrString($payload, 'city'),
+            state:     static::arrString($payload, 'state'),
+            country:   static::arrString($payload, 'country'),
+            status:    static::arrString($payload, 'status'),
+            createdAt: static::arrString($payload, 'created_at'),
+            updatedAt: static::arrString($payload, 'updated_at'),
         );
     }
 

+ 32 - 0
app/Data/Pagarme/Response/CustomerResponseData/CustomerPhonesResponseData/CustomerPhonesResponseData.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Data\Pagarme\Response\CustomerResponseData\CustomerPhonesResponseData;
+
+use App\Data\Pagarme\PagarmeResponseData;
+
+final readonly class CustomerPhonesResponseData extends PagarmeResponseData
+{
+    public function __construct(
+        public ?PhoneResponseData $homePhone,
+        public ?PhoneResponseData $mobilePhone,
+    ) {}
+
+    public static function fromArray(array $payload): static
+    {
+        $home   = static::arrArray($payload, 'home_phone');
+        $mobile = static::arrArray($payload, 'mobile_phone');
+
+        return new self(
+            homePhone:   ! empty($home)   ? PhoneResponseData::fromArray($home)   : null,
+            mobilePhone: ! empty($mobile) ? PhoneResponseData::fromArray($mobile) : null,
+        );
+    }
+
+    public function toArray(): array
+    {
+        return array_filter([
+            'home_phone'   => $this->homePhone?->toArray(),
+            'mobile_phone' => $this->mobilePhone?->toArray(),
+        ]);
+    }
+}

+ 32 - 0
app/Data/Pagarme/Response/CustomerResponseData/CustomerPhonesResponseData/PhoneResponseData.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Data\Pagarme\Response\CustomerResponseData\CustomerPhonesResponseData;
+
+use App\Data\Pagarme\PagarmeResponseData;
+
+final readonly class PhoneResponseData extends PagarmeResponseData
+{
+    public function __construct(
+        public ?string $countryCode,
+        public ?string $areaCode,
+        public ?string $number,
+    ) {}
+
+    public static function fromArray(array $payload): static
+    {
+        return new self(
+            countryCode: static::arrString($payload, 'country_code'),
+            areaCode:    static::arrString($payload, 'area_code'),
+            number:      static::arrString($payload, 'number'),
+        );
+    }
+
+    public function toArray(): array
+    {
+        return [
+            'country_code' => $this->countryCode,
+            'area_code'    => $this->areaCode,
+            'number'       => $this->number,
+        ];
+    }
+}

+ 77 - 0
app/Data/Pagarme/Response/CustomerResponseData/CustomerResponseData.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace App\Data\Pagarme\Response\CustomerResponseData;
+
+use App\Data\Pagarme\Response\CustomerResponseData\CustomerPhonesResponseData\CustomerPhonesResponseData;
+use App\Data\Pagarme\PagarmeResponseData;
+
+final readonly class CustomerResponseData extends PagarmeResponseData
+{
+    public function __construct(
+        public ?string $id,
+        public ?string $name,
+        public ?string $email,
+        public ?string $code,
+        public ?string $document,
+        public ?string $documentType,
+        public ?string $type,
+        public ?bool   $delinquent,
+
+        public ?CustomerAddressResponseData $address, public CustomerPhonesResponseData $phones,
+
+        public ?string $createdAt = null,
+        public ?string $updatedAt = null,
+    ) {}
+
+    public function requireId(): string
+    {
+        if (! $this->id) {
+            throw new \RuntimeException('Customer creation returned an empty id.');
+        }
+
+        return $this->id;
+    }
+
+    //
+
+    public static function fromArray(array $payload): static
+    {
+        $address = static::arrArray($payload, 'address');
+        $phones  = static::arrArray($payload, 'phones');
+
+        return new self(
+            id:           static::arrString($payload, 'id'),
+            name:         static::arrString($payload, 'name'),
+            email:        static::arrString($payload, 'email'),
+            code:         static::arrString($payload, 'code'),
+            document:     static::arrString($payload, 'document'),
+            documentType: static::arrString($payload, 'document_type'),
+            type:         static::arrString($payload, 'type'),
+            delinquent:   static::arrBool($payload, 'delinquent'),
+
+            address: ! empty($address) ? CustomerAddressResponseData::fromArray($address) : null,
+
+            phones:    CustomerPhonesResponseData::fromArray($phones),
+            createdAt: static::arrString($payload, 'created_at'),
+            updatedAt: static::arrString($payload, 'updated_at'),
+        );
+    }
+
+    public function toArray(): array
+    {
+        return [
+            'id'            => $this->id,
+            'name'          => $this->name,
+            'email'         => $this->email,
+            'code'          => $this->code,
+            'document'      => $this->document,
+            'document_type' => $this->documentType,
+            'type'          => $this->type,
+            'delinquent'    => $this->delinquent,
+            'address'       => $this->address?->toArray(),
+            'phones'        => $this->phones->toArray(),
+            'created_at'    => $this->createdAt,
+            'updated_at'    => $this->updatedAt,
+        ];
+    }
+}

+ 54 - 0
app/Data/Pagarme/Response/OrderResponseData/OrderChargeResponseData/OrderChargeResponseData.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace App\Data\Pagarme\Response\OrderResponseData\OrderChargeResponseData;
+
+use App\Data\Pagarme\PagarmeResponseData;
+
+final readonly class OrderChargeResponseData extends PagarmeResponseData
+{
+    public function __construct(
+        public ?string $id,
+        public ?string $status,
+        public ?int    $amount,
+        public ?string $currency,
+        public ?string $paidAt,
+        public ?string $createdAt,
+        public ?OrderTransactionResponseData $lastTransaction,
+    ) {}
+
+    public function transaction(): ?OrderTransactionResponseData
+    {
+        return $this->lastTransaction;
+    }
+
+    public static function fromArray(array $payload): static
+    {
+        $transaction = static::arrArray($payload, 'last_transaction');
+
+        return new self(
+            id:        static::arrString($payload, 'id'),
+            status:    static::arrString($payload, 'status'),
+            amount:    static::arrInt($payload, 'amount'),
+            currency:  static::arrString($payload, 'currency'),
+            paidAt:    static::arrString($payload, 'paid_at'),
+            createdAt: static::arrString($payload, 'created_at'),
+
+            lastTransaction: ! empty($transaction)
+                ? OrderTransactionResponseData::fromArray($transaction)
+                : null,
+        );
+    }
+
+    public function toArray(): array
+    {
+        return array_filter([
+            'id'               => $this->id,
+            'status'           => $this->status,
+            'amount'           => $this->amount,
+            'currency'         => $this->currency,
+            'paid_at'          => $this->paidAt,
+            'created_at'       => $this->createdAt,
+            'last_transaction' => $this->lastTransaction?->toArray(),
+        ], static fn ($v) => $v !== null);
+    }
+}

+ 41 - 0
app/Data/Pagarme/Response/OrderResponseData/OrderChargeResponseData/OrderTransactionResponseData.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Data\Pagarme\Response\OrderResponseData\OrderChargeResponseData;
+
+use App\Data\Pagarme\PagarmeResponseData;
+
+final readonly class OrderTransactionResponseData extends PagarmeResponseData
+{
+    public function __construct(
+        public ?string $id,
+        public ?string $status,
+        public ?int    $amount,
+        public ?string $createdAt,
+        public ?string $acquirerMessage,
+        public array   $gatewayResponse,
+    ) {}
+
+    public static function fromArray(array $payload): static
+    {
+        return new self(
+            id:              static::arrString($payload, 'id'),
+            status:          static::arrString($payload, 'status'),
+            amount:          static::arrInt($payload, 'amount'),
+            createdAt:       static::arrString($payload, 'created_at'),
+            acquirerMessage: static::arrString($payload, 'acquirer_message'),
+            gatewayResponse: static::arrArray($payload, 'gateway_response'),
+        );
+    }
+
+    public function toArray(): array
+    {
+        return [
+            'id'               => $this->id,
+            'status'           => $this->status,
+            'amount'           => $this->amount,
+            'created_at'       => $this->createdAt,
+            'acquirer_message' => $this->acquirerMessage,
+            'gateway_response' => $this->gatewayResponse,
+        ];
+    }
+}

+ 32 - 0
app/Data/Pagarme/Response/OrderResponseData/OrderCheckoutResponseData.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace App\Data\Pagarme\Response\OrderResponseData;
+
+use App\Data\Pagarme\PagarmeResponseData;
+
+final readonly class OrderCheckoutResponseData extends PagarmeResponseData
+{
+    public function __construct(
+        public ?string $id,
+        public ?string $status,
+        public ?string $url,
+    ) {}
+
+    public static function fromArray(array $payload): static
+    {
+        return new self(
+            id:     static::arrString($payload, 'id'),
+            status: static::arrString($payload, 'status'),
+            url:    static::arrString($payload, 'url'),
+        );
+    }
+
+    public function toArray(): array
+    {
+        return [
+            'id'     => $this->id,
+            'status' => $this->status,
+            'url'    => $this->url,
+        ];
+    }
+}

+ 41 - 0
app/Data/Pagarme/Response/OrderResponseData/OrderItemResponseData.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Data\Pagarme\Response\OrderResponseData;
+
+use App\Data\Pagarme\PagarmeResponseData;
+
+final readonly class OrderItemResponseData extends PagarmeResponseData
+{
+    public function __construct(
+        public ?string $id,
+        public ?string $code,
+        public ?int    $amount,
+        public ?int    $quantity,
+        public ?string $description,
+        public ?string $status,
+    ) {}
+
+    public static function fromArray(array $payload): static
+    {
+        return new self(
+            id:          static::arrString($payload, 'id'),
+            code:        static::arrString($payload, 'code'),
+            amount:      static::arrInt($payload, 'amount'),
+            quantity:    static::arrInt($payload, 'quantity'),
+            description: static::arrString($payload, 'description'),
+            status:      static::arrString($payload, 'status'),
+        );
+    }
+
+    public function toArray(): array
+    {
+        return [
+            'id'          => $this->id,
+            'code'        => $this->code,
+            'amount'      => $this->amount,
+            'quantity'    => $this->quantity,
+            'description' => $this->description,
+            'status'      => $this->status,
+        ];
+    }
+}

+ 252 - 0
app/Data/Pagarme/Response/OrderResponseData/OrderResponseData.php

@@ -0,0 +1,252 @@
+<?php
+
+namespace App\Data\Pagarme\Response\OrderResponseData;
+
+use App\Data\Pagarme\Response\CustomerResponseData\CustomerResponseData;
+use App\Data\Pagarme\Response\OrderResponseData\OrderChargeResponseData\OrderChargeResponseData;
+use App\Data\Pagarme\Response\OrderResponseData\OrderChargeResponseData\OrderTransactionResponseData;
+use App\Data\Pagarme\PagarmeResponseData;
+use App\Enums\PaymentStatusEnum;
+
+/**
+ * @param  OrderItemResponseData[]  $items
+ * @param  OrderChargeResponseData[]  $charges
+ * @param  OrderCheckoutResponseData[]  $checkouts
+ */
+final readonly class OrderResponseData extends PagarmeResponseData
+{
+    public function __construct(
+        public ?string $id,
+        public ?string $code,
+        public ?int    $amount,
+        public ?string $currency,
+        public ?bool   $closed,
+        public ?string $status,
+        public array   $items,
+
+        public ?CustomerResponseData $customer,
+
+        public array   $charges,
+        public array   $checkouts,
+        public array   $metadata,
+        public ?string $createdAt = null,
+        public ?string $updatedAt = null,
+        public ?string $closedAt  = null,
+    ) {}
+
+    public function authorizedAt(): ?string
+    {
+        $transaction = $this->lastTransaction();
+
+        if (! $transaction) {
+            return null;
+        }
+
+        if (in_array($transaction->status, ['authorized_pending_capture', 'captured', 'partial_capture'], true)) {
+            return $transaction->createdAt;
+        }
+
+        return null;
+    }
+
+    public function failureCode(): ?string
+    {
+        $transaction = $this->lastTransaction();
+
+        if (! $transaction) {
+            return null;
+        }
+
+        return $this->filledValue($transaction->gatewayResponse['code'] ?? null);
+    }
+
+    public function failureMessage(): ?string
+    {
+        $transaction = $this->lastTransaction();
+
+        if (! $transaction) {
+            return null;
+        }
+
+        $acquirerMessage = $this->filledValue($transaction->acquirerMessage);
+
+        if ($acquirerMessage) {
+            return $acquirerMessage;
+        }
+
+        $gatewayErrors = $transaction->gatewayResponse['errors'] ?? [];
+
+        if (! is_array($gatewayErrors) || empty($gatewayErrors)) {
+            return null;
+        }
+
+        $message = collect($gatewayErrors)
+            ->pluck('message')
+            ->filter()
+            ->implode('; ') ?: null;
+
+        if ($message && str_contains($message, 'Sem ambiente configurado')) {
+            return 'Pix não esta habilitado ou configurado neste ambiente do Pagar.me.';
+        }
+
+        return $message;
+    }
+
+    public function firstCharge(): ?OrderChargeResponseData
+    {
+        return $this->charges[0] ?? null;
+    }
+
+    public function gatewayEntityLabel(): string
+    {
+        $charge = $this->firstCharge();
+
+        return $charge?->id ? 'charge' : 'order';
+    }
+
+    public function gatewayEntityReference(): ?string
+    {
+        $charge = $this->firstCharge();
+
+        return $charge?->id ?? $this->id;
+    }
+
+    public function gatewayOperationLabel(): string
+    {
+        $charge      = $this->firstCharge();
+        $transaction = $this->lastTransaction();
+
+        return $transaction?->id ? 'transaction' : ($charge?->id ? 'charge' : 'order');
+    }
+
+    public function gatewayOperationReference(): ?string
+    {
+        $charge      = $this->firstCharge();
+        $transaction = $this->lastTransaction();
+
+        return $transaction?->id ?? $charge?->id ?? $this->id;
+    }
+
+    public function lastTransaction(): ?OrderTransactionResponseData
+    {
+        return $this->firstCharge()?->transaction();
+    }
+
+    public function paymentStatus(): PaymentStatusEnum
+    {
+        $charge      = $this->firstCharge();
+        $transaction = $this->lastTransaction();
+        $status      = strtolower((string) ($transaction?->status ?: $charge?->status));
+
+        return match ($status) {
+            'captured', 'paid', 'overpaid'                  => PaymentStatusEnum::PAID,
+            'authorized_pending_capture', 'waiting_capture' => PaymentStatusEnum::AUTHORIZED,
+            'pending', 'waiting_payment'                    => PaymentStatusEnum::PENDING,
+            'processing'                                    => PaymentStatusEnum::PROCESSING,
+
+            'not_authorized', 'with_error', 'failed',
+            'underpaid', 'chargedback' => PaymentStatusEnum::FAILED,
+
+            'voided', 'partial_void', 'canceled',
+            'cancelled', 'refunded', 'partial_refunded',
+            'partial_canceled' => PaymentStatusEnum::CANCELLED,
+            default            => PaymentStatusEnum::PENDING,
+        };
+    }
+
+    public function paidAt(): ?string
+    {
+        return $this->firstCharge()?->paidAt;
+    }
+
+    public function requireId(): string
+    {
+        if (! $this->id) {
+            throw new \RuntimeException('Pagar.me order creation returned an empty id.');
+        }
+
+        return $this->id;
+    }
+
+    //
+
+    public static function fromArray(array $payload): static
+    {
+        $customer = static::arrArray($payload, 'customer');
+
+        return new self(
+            id:       static::arrString($payload, 'id'),
+            code:     static::arrString($payload, 'code'),
+            amount:   static::arrInt($payload, 'amount'),
+            currency: static::arrString($payload, 'currency'),
+            closed:   static::arrBool($payload, 'closed'),
+            status:   static::arrString($payload, 'status'),
+
+            items: static::arrMap($payload, 'items',
+                static fn (array $item) => OrderItemResponseData::fromArray($item),
+            ),
+
+            customer: ! empty($customer)
+                ? CustomerResponseData::fromArray($customer)
+                : null,
+
+            charges: static::arrMap($payload, 'charges',
+                static fn (array $charge) => OrderChargeResponseData::fromArray($charge),
+            ),
+
+            checkouts: static::arrMap($payload, 'checkouts',
+                static fn (array $checkout) => OrderCheckoutResponseData::fromArray($checkout),
+            ),
+
+            metadata:  static::arrArray($payload, 'metadata'),
+            createdAt: static::arrString($payload, 'created_at'),
+            updatedAt: static::arrString($payload, 'updated_at'),
+            closedAt:  static::arrString($payload, 'closed_at'),
+        );
+    }
+
+    public function toArray(): array
+    {
+        return [
+            'id'       => $this->id,
+            'code'     => $this->code,
+            'amount'   => $this->amount,
+            'currency' => $this->currency,
+            'closed'   => $this->closed,
+
+            'items' => array_map(
+                static fn (OrderItemResponseData $item) => $item->toArray(),
+                $this->items,
+            ),
+
+            'customer'   => $this->customer?->toArray(),
+            'status'     => $this->status,
+            'created_at' => $this->createdAt,
+            'updated_at' => $this->updatedAt,
+            'closed_at'  => $this->closedAt,
+
+            'charges' => array_map(
+                static fn (OrderChargeResponseData $charge) => $charge->toArray(),
+                $this->charges,
+            ),
+
+            'checkouts' => array_map(
+                static fn (OrderCheckoutResponseData $checkout) => $checkout->toArray(),
+                $this->checkouts,
+            ),
+
+            'metadata' => $this->metadata,
+        ];
+    }
+
+    //
+
+    private function filledValue(mixed $value): ?string
+    {
+        if ($value === null || $value === '' || $value === []) {
+            return null;
+        }
+
+        return (string) $value;
+    }
+}

+ 0 - 27
app/Data/Pagarme/Response/PagarmeCustomerResponseData/PagarmeCustomerPhonesResponseData/PagarmeCustomerPhonesResponseData.php

@@ -1,27 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Response\PagarmeCustomerResponseData\PagarmeCustomerPhonesResponseData;
-
-final readonly class PagarmeCustomerPhonesResponseData
-{
-    public function __construct(
-        public ?PagarmePhoneResponseData $homePhone,
-        public ?PagarmePhoneResponseData $mobilePhone,
-    ) {}
-
-    public static function fromArray(?array $payload): self
-    {
-        return new self(
-            homePhone: PagarmePhoneResponseData::fromArray($payload['home_phone'] ?? null),
-            mobilePhone: PagarmePhoneResponseData::fromArray($payload['mobile_phone'] ?? null),
-        );
-    }
-
-    public function toArray(): array
-    {
-        return array_filter([
-            'home_phone'   => $this->homePhone?->toArray(),
-            'mobile_phone' => $this->mobilePhone?->toArray(),
-        ]);
-    }
-}

+ 0 - 34
app/Data/Pagarme/Response/PagarmeCustomerResponseData/PagarmeCustomerPhonesResponseData/PagarmePhoneResponseData.php

@@ -1,34 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Response\PagarmeCustomerResponseData\PagarmeCustomerPhonesResponseData;
-
-final readonly class PagarmePhoneResponseData
-{
-    public function __construct(
-        public ?string $countryCode,
-        public ?string $areaCode,
-        public ?string $number,
-    ) {}
-
-    public static function fromArray(?array $payload): ?self
-    {
-        if (empty($payload)) {
-            return null;
-        }
-
-        return new self(
-            countryCode: $payload['country_code'] ?? null,
-            areaCode: $payload['area_code'] ?? null,
-            number: $payload['number'] ?? null,
-        );
-    }
-
-    public function toArray(): array
-    {
-        return [
-            'country_code' => $this->countryCode,
-            'area_code'    => $this->areaCode,
-            'number'       => $this->number,
-        ];
-    }
-}

+ 0 - 73
app/Data/Pagarme/Response/PagarmeCustomerResponseData/PagarmeCustomerResponseData.php

@@ -1,73 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Response\PagarmeCustomerResponseData;
-
-use App\Data\Pagarme\Response\PagarmeCustomerResponseData\PagarmeCustomerPhonesResponseData\PagarmeCustomerPhonesResponseData;
-
-final readonly class PagarmeCustomerResponseData
-{
-    public function __construct(
-        public ?string $id,
-        public ?string $name,
-        public ?string $email,
-        public ?string $code,
-        public ?string $document,
-        public ?string $documentType,
-        public ?string $type,
-        public ?bool $delinquent,
-        public ?PagarmeCustomerAddressResponseData $address,
-        public PagarmeCustomerPhonesResponseData $phones,
-        public ?string $createdAt = null,
-        public ?string $updatedAt = null,
-    ) {}
-
-    public function id(): ?string
-    {
-        return $this->id;
-    }
-
-    public function requireId(): string
-    {
-        if (! $this->id) {
-            throw new \RuntimeException('Customer creation returned an empty id.');
-        }
-
-        return $this->id;
-    }
-
-    public static function fromArray(array $payload): self
-    {
-        return new self(
-            id: $payload['id'] ?? null,
-            name: $payload['name'] ?? null,
-            email: $payload['email'] ?? null,
-            code: $payload['code'] ?? null,
-            document: $payload['document'] ?? null,
-            documentType: $payload['document_type'] ?? null,
-            type: $payload['type'] ?? null,
-            delinquent: $payload['delinquent'] ?? null,
-            address: PagarmeCustomerAddressResponseData::fromArray($payload['address'] ?? null),
-            phones: PagarmeCustomerPhonesResponseData::fromArray($payload['phones'] ?? null),
-            createdAt: $payload['created_at'] ?? null,
-            updatedAt: $payload['updated_at'] ?? null,
-        );
-    }
-
-    public function toArray(): array
-    {
-        return [
-            'id'            => $this->id,
-            'name'          => $this->name,
-            'email'         => $this->email,
-            'code'          => $this->code,
-            'document'      => $this->document,
-            'document_type' => $this->documentType,
-            'type'          => $this->type,
-            'delinquent'    => $this->delinquent,
-            'address'       => $this->address?->toArray(),
-            'phones'        => $this->phones->toArray(),
-            'created_at'    => $this->createdAt,
-            'updated_at'    => $this->updatedAt,
-        ];
-    }
-}

+ 0 - 212
app/Data/Pagarme/Response/PagarmeOrderResponseData/PagarmeOrderResponseData.php

@@ -1,212 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Response\PagarmeOrderResponseData;
-
-use App\Enums\PaymentStatusEnum;
-
-/**
- * @param  array<int, array>  $items  Itens do pedido (code, amount, quantity, description, etc.)
- * @param  array<string, mixed>|null  $customer  Dados do cliente retornados pela API
- * @param  array<int, array>  $charges  Cobrancas do pedido (status, amount, payment_method, last_transaction, etc.)
- * @param  array<int, array>  $checkouts  Checkouts do pedido
- * @param  array<string, mixed>  $metadata  Metadados retornados pela API
- */
-final readonly class PagarmeOrderResponseData
-{
-    public function __construct(
-        public ?string $id,
-        public ?string $code,
-        public ?int $amount,
-        public ?string $currency,
-        public ?bool $closed,
-        public ?string $status,
-        public array $items,
-        public ?array $customer,
-        public array $charges,
-        public array $checkouts,
-        public array $metadata,
-        public ?string $createdAt = null,
-        public ?string $updatedAt = null,
-        public ?string $closedAt = null,
-    ) {}
-
-    public function authorizedAt(): ?string
-    {
-        $transaction = $this->lastTransaction();
-
-        $transactionStatus = $transaction['status'] ?? null;
-
-        if (in_array($transactionStatus, ['authorized_pending_capture', 'captured', 'partial_capture'], true)) {
-            return $this->filledArrayValue($transaction, 'created_at');
-        }
-
-        return null;
-    }
-
-    public function failureCode(): ?string
-    {
-        return $this->filledArrayValue($this->lastTransaction()['gateway_response'] ?? [], 'code');
-    }
-
-    public function failureMessage(): ?string
-    {
-        $transaction = $this->lastTransaction();
-
-        $acquirerMessage = $this->filledArrayValue($transaction, 'acquirer_message');
-
-        if ($acquirerMessage) {
-            return $acquirerMessage;
-        }
-
-        $gatewayErrors = $transaction['gateway_response']['errors'] ?? [];
-
-        if (! is_array($gatewayErrors) || empty($gatewayErrors)) {
-            return null;
-        }
-
-        $message = collect($gatewayErrors)
-            ->pluck('message')
-            ->filter()
-            ->implode('; ') ?: null;
-
-        if ($message && str_contains($message, 'Sem ambiente configurado')) {
-            return 'Pix não esta habilitado ou configurado neste ambiente do Pagar.me.';
-        }
-
-        return $message;
-    }
-
-    public function firstCharge(): array
-    {
-        return $this->charges[0] ?? [];
-    }
-
-    public function gatewayEntityLabel(): string
-    {
-        return isset($this->firstCharge()['id']) ? 'charge' : 'order';
-    }
-
-    public function gatewayEntityReference(): ?string
-    {
-        $charge = $this->firstCharge();
-
-        return $charge['id'] ?? $this->id;
-    }
-
-    public function gatewayOperationLabel(): string
-    {
-        $charge = $this->firstCharge();
-
-        $transaction = $this->lastTransaction();
-
-        return isset($transaction['id']) ? 'transaction' : (isset($charge['id']) ? 'charge' : 'order');
-    }
-
-    public function gatewayOperationReference(): ?string
-    {
-        $charge = $this->firstCharge();
-
-        $transaction = $this->lastTransaction();
-
-        return $transaction['id'] ?? $charge['id'] ?? $this->id;
-    }
-
-    public function id(): ?string
-    {
-        return $this->id;
-    }
-
-    public function lastTransaction(): array
-    {
-        return $this->firstCharge()['last_transaction'] ?? [];
-    }
-
-    public function paymentStatus(): PaymentStatusEnum
-    {
-        $charge = $this->firstCharge();
-
-        $transaction = $this->lastTransaction();
-
-        $status = strtolower((string) (($transaction['status'] ?? null) ?: ($charge['status'] ?? null)));
-
-        return match ($status) {
-            'captured', 'paid', 'overpaid' => PaymentStatusEnum::PAID,
-            'authorized_pending_capture', 'waiting_capture' => PaymentStatusEnum::AUTHORIZED,
-            'pending', 'waiting_payment' => PaymentStatusEnum::PENDING,
-            'processing' => PaymentStatusEnum::PROCESSING,
-            'not_authorized', 'with_error', 'failed',
-            'underpaid', 'chargedback' => PaymentStatusEnum::FAILED,
-            'voided', 'partial_void', 'canceled',
-            'cancelled', 'refunded', 'partial_refunded',
-            'partial_canceled' => PaymentStatusEnum::CANCELLED,
-            default            => PaymentStatusEnum::PENDING,
-        };
-    }
-
-    public function paidAt(): ?string
-    {
-        return $this->filledArrayValue($this->firstCharge(), 'paid_at');
-    }
-
-    public function requireId(): string
-    {
-        if (! $this->id) {
-            throw new \RuntimeException('Pagar.me order creation returned an empty id.');
-        }
-
-        return $this->id;
-    }
-
-    //
-
-    public static function fromArray(array $payload): self
-    {
-        return new self(
-            id: $payload['id'] ?? null,
-            code: $payload['code'] ?? null,
-            amount: isset($payload['amount']) ? (int) $payload['amount'] : null,
-            currency: $payload['currency'] ?? null,
-            closed: $payload['closed'] ?? null,
-            status: $payload['status'] ?? null,
-            items: $payload['items'] ?? [],
-            customer: ! empty($payload['customer']) ? $payload['customer'] : null,
-            charges: $payload['charges'] ?? [],
-            checkouts: $payload['checkouts'] ?? [],
-            metadata: $payload['metadata'] ?? [],
-            createdAt: $payload['created_at'] ?? null,
-            updatedAt: $payload['updated_at'] ?? null,
-            closedAt: $payload['closed_at'] ?? null,
-        );
-    }
-
-    public function toArray(): array
-    {
-        return [
-            'id'         => $this->id,
-            'code'       => $this->code,
-            'amount'     => $this->amount,
-            'currency'   => $this->currency,
-            'closed'     => $this->closed,
-            'items'      => $this->items,
-            'customer'   => $this->customer,
-            'status'     => $this->status,
-            'created_at' => $this->createdAt,
-            'updated_at' => $this->updatedAt,
-            'closed_at'  => $this->closedAt,
-            'charges'    => $this->charges,
-            'checkouts'  => $this->checkouts,
-            'metadata'   => $this->metadata,
-        ];
-    }
-
-    //
-
-    private function filledArrayValue(array $data, string $field): ?string
-    {
-        if (! array_key_exists($field, $data) || $data[$field] === null || $data[$field] === '' || $data[$field] === []) {
-            return null;
-        }
-
-        return (string) $data[$field];
-    }
-}

+ 0 - 66
app/Data/Pagarme/Response/PagarmeTransferResponseData.php

@@ -1,66 +0,0 @@
-<?php
-
-namespace App\Data\Pagarme\Response;
-
-final readonly class PagarmeTransferResponseData
-{
-    public function __construct(
-        public ?string $id,
-        public ?int $amount,
-        public ?string $type,
-        public ?string $status,
-        public ?int $fee,
-        public ?string $fundingDate,
-        public ?string $fundingEstimatedDate,
-        public ?array $bankAccount,
-        public ?string $bankResponse,
-        public ?string $createdAt,
-        public ?array $metadata,
-    ) {}
-    
-    public function id(): ?string
-    {
-        return $this->id;
-    }
-
-    public function status(): ?string
-    {
-        return $this->status;
-    }
-
-    //
-
-    public static function fromArray(array $payload): self
-    {
-        return new self(
-            id: $payload['id'] ?? null,
-            amount: $payload['amount'] ?? null,
-            type: $payload['type'] ?? null,
-            status: $payload['status'] ?? null,
-            fee: $payload['fee'] ?? null,
-            fundingDate: $payload['funding_date'] ?? null,
-            fundingEstimatedDate: $payload['funding_estimated_date'] ?? null,
-            bankAccount: $payload['bank_account'] ?? null,
-            bankResponse: $payload['bank_response'] ?? null,
-            createdAt: $payload['created_at'] ?? $payload['date_created'] ?? null,
-            metadata: $payload['metadata'] ?? null,
-        );
-    }
-
-    public function toArray(): array
-    {
-        return [
-            'id'                     => $this->id,
-            'amount'                 => $this->amount,
-            'type'                   => $this->type,
-            'status'                 => $this->status,
-            'fee'                    => $this->fee,
-            'funding_date'           => $this->fundingDate,
-            'funding_estimated_date' => $this->fundingEstimatedDate,
-            'bank_account'           => $this->bankAccount,
-            'bank_response'          => $this->bankResponse,
-            'created_at'             => $this->createdAt,
-            'metadata'               => $this->metadata,
-        ];
-    }
-}

+ 14 - 12
app/Data/Pagarme/Response/PagarmeRecipientResponseData/PagarmeRecipientBankAccountResponseData.php → app/Data/Pagarme/Response/RecipientResponseData/RecipientBankAccountResponseData.php

@@ -1,8 +1,10 @@
 <?php
 
-namespace App\Data\Pagarme\Response\PagarmeRecipientResponseData;
+namespace App\Data\Pagarme\Response\RecipientResponseData;
 
-final readonly class PagarmeRecipientBankAccountResponseData
+use App\Data\Pagarme\PagarmeResponseData;
+
+final readonly class RecipientBankAccountResponseData extends PagarmeResponseData
 {
     public function __construct(
         public ?string $holderName,
@@ -16,18 +18,18 @@ final readonly class PagarmeRecipientBankAccountResponseData
         public ?string $type,
     ) {}
 
-    public static function fromArray(array $payload): self
+    public static function fromArray(array $payload): static
     {
         return new self(
-            holderName: $payload['holder_name'] ?? null,
-            holderType: $payload['holder_type'] ?? null,
-            holderDocument: $payload['holder_document'] ?? null,
-            bank: $payload['bank'] ?? null,
-            branchNumber: $payload['branch_number'] ?? null,
-            branchCheckDigit: $payload['branch_check_digit'] ?? null,
-            accountNumber: $payload['account_number'] ?? null,
-            accountCheckDigit: $payload['account_check_digit'] ?? null,
-            type: $payload['type'] ?? null,
+            holderName:        static::arrString($payload, 'holder_name'),
+            holderType:        static::arrString($payload, 'holder_type'),
+            holderDocument:    static::arrString($payload, 'holder_document'),
+            bank:              static::arrString($payload, 'bank'),
+            branchNumber:      static::arrString($payload, 'branch_number'),
+            branchCheckDigit:  static::arrString($payload, 'branch_check_digit'),
+            accountNumber:     static::arrString($payload, 'account_number'),
+            accountCheckDigit: static::arrString($payload, 'account_check_digit'),
+            type:              static::arrString($payload, 'type'),
         );
     }
 

+ 22 - 24
app/Data/Pagarme/Response/PagarmeRecipientResponseData/PagarmeRecipientResponseData.php → app/Data/Pagarme/Response/RecipientResponseData/RecipientResponseData.php

@@ -1,8 +1,10 @@
 <?php
 
-namespace App\Data\Pagarme\Response\PagarmeRecipientResponseData;
+namespace App\Data\Pagarme\Response\RecipientResponseData;
 
-final readonly class PagarmeRecipientResponseData
+use App\Data\Pagarme\PagarmeResponseData;
+
+final readonly class RecipientResponseData extends PagarmeResponseData
 {
     public function __construct(
         public ?string $id,
@@ -11,21 +13,13 @@ final readonly class PagarmeRecipientResponseData
         public ?string $document,
         public ?string $type,
         public ?string $status,
-        public ?PagarmeRecipientBankAccountResponseData $defaultBankAccount = null,
+
+        public ?RecipientBankAccountResponseData $defaultBankAccount = null,
+
         public ?string $createdAt = null,
         public ?string $updatedAt = null,
     ) {}
 
-    public function defaultBankAccount(): ?PagarmeRecipientBankAccountResponseData
-    {
-        return $this->defaultBankAccount;
-    }
-
-    public function id(): ?string
-    {
-        return $this->id;
-    }
-
     public function requireId(): string
     {
         if (! $this->id) {
@@ -37,20 +31,24 @@ final readonly class PagarmeRecipientResponseData
 
     //
 
-    public static function fromArray(array $payload): self
+    public static function fromArray(array $payload): static
     {
+        $bankAccount = static::arrArray($payload, 'default_bank_account');
+
         return new self(
-            id: $payload['id'] ?? null,
-            name: $payload['name'] ?? null,
-            email: $payload['email'] ?? null,
-            document: $payload['document'] ?? null,
-            type: $payload['type'] ?? null,
-            status: $payload['status'] ?? null,
-            defaultBankAccount: ! empty($payload['default_bank_account'])
-                ? PagarmeRecipientBankAccountResponseData::fromArray($payload['default_bank_account'])
+            id:       static::arrString($payload, 'id'),
+            name:     static::arrString($payload, 'name'),
+            email:    static::arrString($payload, 'email'),
+            document: static::arrString($payload, 'document'),
+            type:     static::arrString($payload, 'type'),
+            status:   static::arrString($payload, 'status'),
+
+            defaultBankAccount: ! empty($bankAccount)
+                ? RecipientBankAccountResponseData::fromArray($bankAccount)
                 : null,
-            createdAt: $payload['created_at'] ?? null,
-            updatedAt: $payload['updated_at'] ?? null,
+
+            createdAt: static::arrString($payload, 'created_at'),
+            updatedAt: static::arrString($payload, 'updated_at'),
         );
     }
 

+ 56 - 0
app/Data/Pagarme/Response/TransferResponseData.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace App\Data\Pagarme\Response;
+
+final readonly class TransferResponseData extends PagarmeResponseData
+{
+    public function __construct(
+        public ?string $id,
+        public ?int    $amount,
+        public ?string $type,
+        public ?string $status,
+        public ?int    $fee,
+        public ?string $fundingDate,
+        public ?string $fundingEstimatedDate,
+        public ?array  $bankAccount,
+        public ?string $bankResponse,
+        public ?string $createdAt,
+        public ?array  $metadata,
+    ) {}
+
+    //
+
+    public static function fromArray(array $payload): static
+    {
+        return new self(
+            id:                   static::arrString($payload, 'id'),
+            amount:               static::arrInt($payload, 'amount'),
+            type:                 static::arrString($payload, 'type'),
+            status:               static::arrString($payload, 'status'),
+            fee:                  static::arrInt($payload, 'fee'),
+            fundingDate:          static::arrString($payload, 'funding_date'),
+            fundingEstimatedDate: static::arrString($payload, 'funding_estimated_date'),
+            bankAccount:          static::arrGet($payload, 'bank_account'),
+            bankResponse:         static::arrString($payload, 'bank_response'),
+            createdAt:            static::arrString($payload, 'created_at') ?? static::arrString($payload, 'date_created'),
+            metadata:             static::arrGet($payload, 'metadata'),
+        );
+    }
+
+    public function toArray(): array
+    {
+        return [
+            'id'                     => $this->id,
+            'amount'                 => $this->amount,
+            'type'                   => $this->type,
+            'status'                 => $this->status,
+            'fee'                    => $this->fee,
+            'funding_date'           => $this->fundingDate,
+            'funding_estimated_date' => $this->fundingEstimatedDate,
+            'bank_account'           => $this->bankAccount,
+            'bank_response'          => $this->bankResponse,
+            'created_at'             => $this->createdAt,
+            'metadata'               => $this->metadata,
+        ];
+    }
+}

+ 208 - 208
app/Http/Controllers/AuthController.php

@@ -3,173 +3,173 @@
 namespace App\Http\Controllers;
 
 use App\Http\Requests\AuthRequest;
-use App\Http\Requests\RefreshTokenRequest;
 use App\Http\Requests\RefreshTokenAppRequest;
+use App\Http\Requests\RefreshTokenRequest;
 use App\Http\Requests\UserAppsRequest;
 use App\Http\Requests\UserAppsValidateCodeRequest;
-use Illuminate\Http\JsonResponse;
 use App\Http\Resources\AuthResource;
 use App\Services\AuthService;
-use Illuminate\Support\Facades\Log;
+use Illuminate\Http\JsonResponse;
 
 class AuthController extends Controller
 {
-  public function __construct(protected AuthService $authService) {}
+    public function __construct(protected AuthService $authService) {}
 
-  public function login(AuthRequest $request): JsonResponse
-  {
-    $validated = $request->validated();
+    public function login(AuthRequest $request): JsonResponse
+    {
+        $validated = $request->validated();
 
-    $result = $this->authService->login(
-      email: $validated["email"],
-      password: $validated["password"],
-    );
+        $result = $this->authService->login(
+            email: $validated['email'],
+            password: $validated['password'],
+        );
 
-    if (!$result) {
-      return $this->errorResponse(message: __("auth.failed"), code: 401);
-    }
+        if (! $result) {
+            return $this->errorResponse(message: __('auth.failed'), code: 401);
+        }
 
-    return $this->successResponse(
-      payload: new AuthResource($result["payload"]),
-      message: __("auth.logged_in"),
-    )->withCookie(
-      cookie(
-        "refresh_token",
-        $result["refreshToken"],
-        config("sanctum.rt_expiration") * 60,
-        "/",
-        config("session.domain"),
-        config("session.secure"),
-        true,
-        false,
-        "Lax",
-      ),
-    );
-  }
-
-  public function loginApp(AuthRequest $request): JsonResponse
-  {
-    $validated = $request->validated();
-
-    $result = $this->authService->login(
-      email: $validated["email"],
-      password: $validated["password"],
-    );
-
-    if (!$result) {
-      return $this->errorResponse(message: __("auth.failed"), code: 401);
+        return $this->successResponse(
+            payload: new AuthResource($result['payload']),
+            message: __('auth.logged_in'),
+        )->withCookie(
+            cookie(
+                'refresh_token',
+                $result['refreshToken'],
+                config('sanctum.rt_expiration') * 60,
+                '/',
+                config('session.domain'),
+                config('session.secure'),
+                true,
+                false,
+                'Lax',
+            ),
+        );
     }
 
-    return $this->successResponse(
-      payload: new AuthResource([
-        ...$result["payload"],
-        "refresh_token" => $result["refreshToken"],
-      ]),
-      message: __("auth.logged_in"),
-    );
-  }
-
-  public function logout(): JsonResponse
-  {
-    $this->authService->logout();
-
-    return $this->successResponse(
-      message: __("auth.logout"),
-    )->withoutCookie("refresh_token");
-  }
-
-  public function refresh(RefreshTokenRequest $request): JsonResponse
-  {
-    $refresh_token = $request->cookie("refresh_token");
-
-    if (is_null($refresh_token)) {
-      return $this->errorResponse(
-        code: 403,
-      )->withoutCookie("refresh_token");
-    }
+    public function loginApp(AuthRequest $request): JsonResponse
+    {
+        $validated = $request->validated();
+
+        $result = $this->authService->login(
+            email: $validated['email'],
+            password: $validated['password'],
+        );
 
-    $result = $this->authService->refresh(
-      $refresh_token
-    );
+        if (! $result) {
+            return $this->errorResponse(message: __('auth.failed'), code: 401);
+        }
 
-    if (is_null($result)) {
-      return $this->errorResponse(
-        message: __("auth.unauthorized"),
-        code: 403,
-      )->withoutCookie("refresh_token");
+        return $this->successResponse(
+            payload: new AuthResource([
+                ...$result['payload'],
+                'refresh_token' => $result['refreshToken'],
+            ]),
+            message: __('auth.logged_in'),
+        );
     }
 
-    return $this->successResponse(
-      payload: new AuthResource($result["payload"]),
-    )->withCookie(
-      cookie(
-        "refresh_token",
-        $result["refreshToken"],
-        config("sanctum.rt_expiration") * 60,
-        "/",
-        config("session.domain"),
-        config("session.secure"),
-        true,
-        true,
-        "Lax",
-      ),
-    );
-  }
-
-  public function refreshApp(RefreshTokenAppRequest $request): JsonResponse
-  {
-    $refresh_token = $request->validated("refresh_token");
-
-    if (is_null($refresh_token)) {
-      return $this->errorResponse(code: 403);
+    public function logout(): JsonResponse
+    {
+        $this->authService->logout();
+
+        return $this->successResponse(
+            message: __('auth.logout'),
+        )->withoutCookie('refresh_token');
     }
-    $result = $this->authService->refresh(
-      $refresh_token
-    );
-
-    if (is_null($result)) {
-      return $this->errorResponse(
-        message: __("auth.unauthorized"),
-        code: 403,
-      );
+
+    public function refresh(RefreshTokenRequest $request): JsonResponse
+    {
+        $refresh_token = $request->cookie('refresh_token');
+
+        if (is_null($refresh_token)) {
+            return $this->errorResponse(
+                code: 403,
+            )->withoutCookie('refresh_token');
+        }
+
+        $result = $this->authService->refresh(
+            $refresh_token
+        );
+
+        if (is_null($result)) {
+            return $this->errorResponse(
+                message: __('auth.unauthorized'),
+                code: 403,
+            )->withoutCookie('refresh_token');
+        }
+
+        return $this->successResponse(
+            payload: new AuthResource($result['payload']),
+        )->withCookie(
+            cookie(
+                'refresh_token',
+                $result['refreshToken'],
+                config('sanctum.rt_expiration') * 60,
+                '/',
+                config('session.domain'),
+                config('session.secure'),
+                true,
+                true,
+                'Lax',
+            ),
+        );
     }
-    return $this->successResponse(
-      payload: new AuthResource([
-        ...$result["payload"],
-        "refresh_token" => $result["refreshToken"],
-      ]),
-    );
-  }
-
-  public function clientSendCode(UserAppsRequest $request): JsonResponse
-  {
-    $result = $this->authService->clientSendCode($request->validated());
-
-    if (is_array($result) && isset($result['error'])) {
-      return $this->errorResponse(message: __("auth.{$result['error']}"), code: 403);
+
+    public function refreshApp(RefreshTokenAppRequest $request): JsonResponse
+    {
+        $refresh_token = $request->validated('refresh_token');
+
+        if (is_null($refresh_token)) {
+            return $this->errorResponse(code: 403);
+        }
+        $result = $this->authService->refresh(
+            $refresh_token
+        );
+
+        if (is_null($result)) {
+            return $this->errorResponse(
+                message: __('auth.unauthorized'),
+                code: 403,
+            );
+        }
+
+        return $this->successResponse(
+            payload: new AuthResource([
+                ...$result['payload'],
+                'refresh_token' => $result['refreshToken'],
+            ]),
+        );
     }
 
-    return $this->successResponse(
-      message: __("messages.code_sent"),
-      code: 201,
-      payload: ['isLogin' => $result],
-    );
-  }
+    public function clientSendCode(UserAppsRequest $request): JsonResponse
+    {
+        $result = $this->authService->clientSendCode($request->validated());
 
-  public function providerSendCode(UserAppsRequest $request): JsonResponse
-  {
-    $result = $this->authService->providerSendCode($request->validated());
+        if (is_array($result) && isset($result['error'])) {
+            return $this->errorResponse(message: __("auth.{$result['error']}"), code: 403);
+        }
 
-    if (is_array($result) && isset($result['error'])) {
-      return $this->errorResponse(message: __("auth.{$result['error']}"), code: 403);
+        return $this->successResponse(
+            message: __('messages.code_sent'),
+            code: 201,
+            payload: ['isLogin' => $result],
+        );
     }
 
-    return $this->successResponse(
-      message: __("messages.code_sent"),
-      code: 201,
-      payload: ['isLogin' => $result],
-    );
-  }
+    public function providerSendCode(UserAppsRequest $request): JsonResponse
+    {
+        $result = $this->authService->providerSendCode($request->validated());
+
+        if (is_array($result) && isset($result['error'])) {
+            return $this->errorResponse(message: __("auth.{$result['error']}"), code: 403);
+        }
+
+        return $this->successResponse(
+            message: __('messages.code_sent'),
+            code: 201,
+            payload: ['isLogin' => $result],
+        );
+    }
 
     public function validateCodeClient(UserAppsValidateCodeRequest $request): JsonResponse
     {
@@ -178,28 +178,28 @@ class AuthController extends Controller
         $code = $request->input('code');
         $isLogin = (bool) $request->input('isLogin', false);
 
-    $result = $this->authService->validateCodeClient($request->validated(), $isLogin);
+        $result = $this->authService->validateCodeClient($request->validated(), $isLogin);
 
-    if ($result === false) {
-      return $this->errorResponse(message: __('auth.invalid_code'), code: 400);
-    }
+        if ($result === false) {
+            return $this->errorResponse(message: __('auth.invalid_code'), code: 400);
+        }
 
-    if (is_array($result) && isset($result['error'])) {
-      return $this->errorResponse(message: __("auth.{$result['error']}"), code: 403);
-    }
+        if (is_array($result) && isset($result['error'])) {
+            return $this->errorResponse(message: __("auth.{$result['error']}"), code: 403);
+        }
 
-    if ($isLogin) {
-      return $this->successResponse(
-        payload: new AuthResource([...$result['payload'], 'refresh_token' => $result['refreshToken']]),
-        message: __('auth.logged_in'),
-      );
-    }
+        if ($isLogin) {
+            return $this->successResponse(
+                payload: new AuthResource([...$result['payload'], 'refresh_token' => $result['refreshToken']]),
+                message: __('auth.logged_in'),
+            );
+        }
 
-    return $this->successResponse(
-      payload: ['email' => $email, 'phone' => $phone, 'code' => $code],
-      message: __('auth.valid_code'),
-    );
-  }
+        return $this->successResponse(
+            payload: ['email' => $email, 'phone' => $phone, 'code' => $code],
+            message: __('auth.valid_code'),
+        );
+    }
 
     public function validateCodeProvider(UserAppsValidateCodeRequest $request): JsonResponse
     {
@@ -208,28 +208,28 @@ class AuthController extends Controller
         $code = $request->input('code');
         $isLogin = (bool) $request->input('isLogin', false);
 
-    $result = $this->authService->validateCodeProvider($request->validated(), $isLogin);
+        $result = $this->authService->validateCodeProvider($request->validated(), $isLogin);
 
-    if ($result === false) {
-      return $this->errorResponse(message: __('auth.invalid_code'), code: 400);
-    }
+        if ($result === false) {
+            return $this->errorResponse(message: __('auth.invalid_code'), code: 400);
+        }
 
-    if (is_array($result) && isset($result['error'])) {
-      return $this->errorResponse(message: __("auth.{$result['error']}"), code: 403);
-    }
+        if (is_array($result) && isset($result['error'])) {
+            return $this->errorResponse(message: __("auth.{$result['error']}"), code: 403);
+        }
 
-    if ($isLogin) {
-      return $this->successResponse(
-        payload: new AuthResource([...$result['payload'], 'refresh_token' => $result['refreshToken']]),
-        message: __('auth.logged_in'),
-      );
-    }
+        if ($isLogin) {
+            return $this->successResponse(
+                payload: new AuthResource([...$result['payload'], 'refresh_token' => $result['refreshToken']]),
+                message: __('auth.logged_in'),
+            );
+        }
 
-    return $this->successResponse(
-      payload: ['email' => $email, 'phone' => $phone, 'code' => $code],
-      message: __('auth.valid_code'),
-    );
-  }
+        return $this->successResponse(
+            payload: ['email' => $email, 'phone' => $phone, 'code' => $code],
+            message: __('auth.valid_code'),
+        );
+    }
 
     public function validateCode(UserAppsValidateCodeRequest $request): JsonResponse
     {
@@ -239,36 +239,36 @@ class AuthController extends Controller
             $code = $request->input('code');
             $isLogin = $request->input('isLogin');
 
-      $result = $this->authService->validateCode($request->validated(), $isLogin);
-  
-      if (!$result) {
-        return $this->errorResponse(
-          message: __("auth.invalid_code"),
-          code: 400,
-        );
-      }
-      
-      if($isLogin) {
-        return $this->successResponse(
-          payload: new AuthResource([
-            ...$result["payload"],
-            "refresh_token" => $result["refreshToken"],
-          ]),
-          message: __("auth.logged_in"),
-        );
-      } else {
-        return $this->successResponse(
-          payload: ['email' => $email, 'phone' => $phone, 'code' => $code],
-          message: __("auth.valid_code"),
-          code: 200,
-        );
-      }
-
-    } catch (\Exception $e) {
-      return $this->errorResponse(
-        message: __("auth.validation_error"),
-        code: 500,
-      );
+            $result = $this->authService->validateCode($request->validated(), $isLogin);
+
+            if (! $result) {
+                return $this->errorResponse(
+                    message: __('auth.invalid_code'),
+                    code: 400,
+                );
+            }
+
+            if ($isLogin) {
+                return $this->successResponse(
+                    payload: new AuthResource([
+                        ...$result['payload'],
+                        'refresh_token' => $result['refreshToken'],
+                    ]),
+                    message: __('auth.logged_in'),
+                );
+            } else {
+                return $this->successResponse(
+                    payload: ['email' => $email, 'phone' => $phone, 'code' => $code],
+                    message: __('auth.valid_code'),
+                    code: 200,
+                );
+            }
+
+        } catch (\Exception $e) {
+            return $this->errorResponse(
+                message: __('auth.validation_error'),
+                code: 500,
+            );
+        }
     }
-  }
 }

+ 1 - 0
app/Http/Controllers/ClientCalendarController.php

@@ -18,6 +18,7 @@ class ClientCalendarController extends Controller
             return $this->successResponse(payload: $dados);
         } catch (\Exception $e) {
             Log::error('Error fetching client calendar: '.$e->getMessage());
+
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }

+ 3 - 0
app/Http/Controllers/DashboardController.php

@@ -28,6 +28,7 @@ class DashboardController extends Controller
             return $this->errorResponse(message: 'Cliente não encontrado.', code: 404);
         } catch (\Exception $e) {
             Log::error('Erro ao obter dados do dashboard do cliente: '.$e->getMessage());
+
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }
@@ -40,6 +41,7 @@ class DashboardController extends Controller
             return $this->successResponse(payload: $dados);
         } catch (\Exception $e) {
             Log::error('Erro ao obter detalhes do schedule do cliente: '.$e->getMessage());
+
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }
@@ -58,6 +60,7 @@ class DashboardController extends Controller
             return $this->errorResponse(message: 'Prestador não encontrado.', code: 404);
         } catch (\Exception $e) {
             Log::error('Erro ao obter dados do dashboard do prestador: '.$e->getMessage());
+
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }

+ 1 - 0
app/Http/Controllers/ProviderCalendarController.php

@@ -18,6 +18,7 @@ class ProviderCalendarController extends Controller
             return $this->successResponse(payload: $dados);
         } catch (\Exception $e) {
             Log::error('Error fetching provider calendar: '.$e->getMessage());
+
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }

+ 21 - 14
app/Http/Controllers/ProviderController.php

@@ -18,6 +18,7 @@ class ProviderController extends Controller
     public function index(): JsonResponse
     {
         $items = $this->service->getAll();
+
         return $this->successResponse(
             payload: ProviderResource::collection($items),
         );
@@ -26,9 +27,10 @@ class ProviderController extends Controller
     public function store(ProviderRequest $request): JsonResponse
     {
         $item = $this->service->create($request->validated());
+
         return $this->successResponse(
             payload: new ProviderResource($item),
-            message: __("messages.created"),
+            message: __('messages.created'),
             code: 201,
         );
     }
@@ -36,12 +38,14 @@ class ProviderController extends Controller
     public function show(int $id): JsonResponse
     {
         $item = $this->service->findById($id);
+
         return $this->successResponse(payload: new ProviderResource($item));
     }
 
     public function update(ProviderRequest $request, int $id): JsonResponse
     {
         $item = $this->service->update($id, $request->validated());
+
         return $this->successResponse(
             payload: new ProviderResource($item),
             message: __('messages.updated'),
@@ -61,8 +65,9 @@ class ProviderController extends Controller
     public function destroy(int $id): JsonResponse
     {
         $this->service->delete($id);
+
         return $this->successResponse(
-            message: __("messages.deleted"),
+            message: __('messages.deleted'),
             code: 204,
         );
     }
@@ -84,6 +89,7 @@ class ProviderController extends Controller
     public function approve(int $id): JsonResponse
     {
         $item = $this->service->approve($id);
+
         return $this->successResponse(
             payload: new ProviderResource($item),
             message: __('messages.provider_approved'),
@@ -93,6 +99,7 @@ class ProviderController extends Controller
     public function reject(int $id): JsonResponse
     {
         $item = $this->service->reject($id);
+
         return $this->successResponse(
             payload: new ProviderResource($item),
             message: __('messages.provider_rejected'),
@@ -101,17 +108,17 @@ class ProviderController extends Controller
 
     public function register(RegisterProviderRequest $request): JsonResponse
     {
-      $result = $this->service->register($request->validated());
-      if (!$result) {
-        return $this->errorResponse(message: __("auth.failed"), code: 401);
-      }
-
-      return $this->successResponse(
-        payload: new AuthResource([
-          ...$result["payload"],
-          "refresh_token" => $result["refreshToken"],
-        ]),
-        message: __("auth.logged_in"),
-      );
+        $result = $this->service->register($request->validated());
+        if (! $result) {
+            return $this->errorResponse(message: __('auth.failed'), code: 401);
+        }
+
+        return $this->successResponse(
+            payload: new AuthResource([
+                ...$result['payload'],
+                'refresh_token' => $result['refreshToken'],
+            ]),
+            message: __('auth.logged_in'),
+        );
     }
 }

+ 1 - 0
app/Http/Controllers/SearchController.php

@@ -19,6 +19,7 @@ class SearchController extends Controller
             return $this->successResponse(payload: $dados);
         } catch (\Exception $e) {
             Log::error('Erro ao buscar prestadores: '.$e->getMessage());
+
             return $this->errorResponse(message: __('messages.error_fetching_data'), code: 500);
         }
     }

+ 3 - 3
app/Http/Resources/CardsListResource.php

@@ -10,10 +10,10 @@ class CardsListResource extends JsonResource
     public function toArray(Request $request): array
     {
         return [
-            'id' => $this->id,
-            'brand' => $this->brand,
+            'id'               => $this->id,
+            'brand'            => $this->brand,
             'last_four_digits' => $this->last_four_digits,
-            'card_name' => $this->card_name,
+            'card_name'        => $this->card_name,
 
         ];
     }

+ 8 - 8
app/Http/Resources/ClientResource.php

@@ -15,15 +15,15 @@ class ClientResource extends JsonResource
     public function toArray(Request $request): array
     {
         return [
-            'id'              => $this->id,
-            'document'        => $this->document,
-            'user_id'         => $this->user_id,
+            'id'               => $this->id,
+            'document'         => $this->document,
+            'user_id'          => $this->user_id,
             'profile_media_id' => $this->profile_media_id,
-            'profile_media'   => new MediaResource($this->whenLoaded('profileMedia')),
-            'user'            => new UserResource($this->whenLoaded('user')),
-            'created_at'      => $this->created_at,
-            'updated_at'      => $this->updated_at,
-            'deleted_at'      => $this->deleted_at,
+            'profile_media'    => new MediaResource($this->whenLoaded('profileMedia')),
+            'user'             => new UserResource($this->whenLoaded('user')),
+            'created_at'       => $this->created_at,
+            'updated_at'       => $this->updated_at,
+            'deleted_at'       => $this->deleted_at,
         ];
     }
 }

+ 1 - 1
app/Http/Resources/DashboardClienteResource.php

@@ -24,7 +24,7 @@ class DashboardClienteResource extends JsonResource
             'providersClose'      => $this['providersClose'],
             'schedulesProposals'  => $this['schedulesProposals'],
             'todaySchedules'      => $this['todaySchedules'],
-            'notifications' => $this['notifications'],
+            'notifications'       => $this['notifications'],
             'has_payment_methods' => $this['has_payment_methods'],
         ];
     }

+ 1 - 1
app/Http/Resources/DashboardPrestadorResource.php

@@ -22,7 +22,7 @@ class DashboardPrestadorResource extends JsonResource
             'solicitations'  => $this['solicitations'],
             'nextSchedules'  => $this['nextSchedules'],
             'opportunities'  => $this['opportunities'],
-            'notifications' => $this['notifications'],
+            'notifications'  => $this['notifications'],
         ];
     }
 }

+ 7 - 7
app/Http/Resources/ProviderPaymentMethodResource.php

@@ -10,14 +10,14 @@ class ProviderPaymentMethodResource extends JsonResource
     public function toArray(Request $request): array
     {
         return [
-            'id' => $this->id,
-            'provider_id' => $this->provider_id,
-            'account_type' => $this->account_type?->value,
-            'pix_key' => $this->pix_key,
+            'id'                => $this->id,
+            'provider_id'       => $this->provider_id,
+            'account_type'      => $this->account_type?->value,
+            'pix_key'           => $this->pix_key,
             'bank_account_type' => $this->bank_account_type?->value,
-            'agency' => $this->agency,
-            'account' => $this->account,
-            'digit' => $this->digit,
+            'agency'            => $this->agency,
+            'account'           => $this->account,
+            'digit'             => $this->digit,
         ];
     }
 }

+ 3 - 4
app/Http/Resources/ProviderResource.php

@@ -2,12 +2,11 @@
 
 namespace App\Http\Resources;
 
+use App\Models\Provider;
 use Carbon\Carbon;
 use Illuminate\Http\Request;
-use Illuminate\Http\Resources\Json\JsonResource;
 use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
-use App\Http\Resources\MediaResource;
-use App\Models\Provider;
+use Illuminate\Http\Resources\Json\JsonResource;
 
 class ProviderResource extends JsonResource
 {
@@ -39,7 +38,7 @@ class ProviderResource extends JsonResource
     }
 
     /**
-     * @param \Illuminate\Database\Eloquent\Collection<Provider> $resource
+     * @param  \Illuminate\Database\Eloquent\Collection<Provider>  $resource
      * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<ProviderResource>
      */
     public static function collection($resource): AnonymousResourceCollection

+ 1 - 1
app/Http/Resources/ReviewResource.php

@@ -35,7 +35,7 @@ class ReviewResource extends JsonResource
                 });
             }),
 
-            'photos'     => $this->whenLoaded('reviewMedia', function () {
+            'photos' => $this->whenLoaded('reviewMedia', function () {
                 return $this->reviewMedia->map(fn ($rm) => [
                     'id'     => $rm->media_id,
                     'origin' => $rm->origin,

+ 0 - 1
app/Http/Resources/UserResource.php

@@ -6,7 +6,6 @@ use Carbon\Carbon;
 use Illuminate\Http\Request;
 use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
 use Illuminate\Http\Resources\Json\JsonResource;
-use App\Http\Resources\ProviderResource;
 
 class UserResource extends JsonResource
 {

+ 33 - 8
app/Notifications/Push/Cliente/Contextual/ContextualSegundaPush.php

@@ -10,21 +10,46 @@ use Illuminate\Database\Eloquent\Collection;
 
 class ContextualSegundaPush extends BasePushNotification
 {
-    public function label(): string { return 'cliente_contextual_segunda'; }
-    public function title(): string { return 'Segunda organizada'; }
-    public function body(): string  { return 'Comece a semana com a casa limpa.'; }
+    public function label(): string
+    {
+        return 'cliente_contextual_segunda';
+    }
+
+    public function title(): string
+    {
+        return 'Segunda organizada';
+    }
+
+    public function body(): string
+    {
+        return 'Comece a semana com a casa limpa.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::CONTEXTUAL; }
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::CONTEXTUAL;
+    }
 
-    public function notificationCooldownDays(): int { return 7; }
-    public function categoryCooldownDays(): int     { return 7; }
+    public function notificationCooldownDays(): int
+    {
+        return 7;
+    }
+
+    public function categoryCooldownDays(): int
+    {
+        return 7;
+    }
 
     /** Só retorna usuários se hoje for segunda-feira */
     public function eligibleUsers(): Collection
     {
         if (! now()->isMonday()) {
-            return new Collection();
+            return new Collection;
         }
 
         return User::whereHas('client')

+ 33 - 8
app/Notifications/Push/Cliente/Contextual/ContextualSextaPush.php

@@ -10,21 +10,46 @@ use Illuminate\Database\Eloquent\Collection;
 
 class ContextualSextaPush extends BasePushNotification
 {
-    public function label(): string { return 'cliente_contextual_sexta'; }
-    public function title(): string { return 'Sexta chegando'; }
-    public function body(): string  { return 'Que tal deixar a casa pronta pro fim de semana?'; }
+    public function label(): string
+    {
+        return 'cliente_contextual_sexta';
+    }
+
+    public function title(): string
+    {
+        return 'Sexta chegando';
+    }
+
+    public function body(): string
+    {
+        return 'Que tal deixar a casa pronta pro fim de semana?';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::CONTEXTUAL; }
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::CONTEXTUAL;
+    }
 
-    public function notificationCooldownDays(): int { return 7; }
-    public function categoryCooldownDays(): int     { return 7; }
+    public function notificationCooldownDays(): int
+    {
+        return 7;
+    }
+
+    public function categoryCooldownDays(): int
+    {
+        return 7;
+    }
 
     /** Só retorna usuários se hoje for sexta-feira */
     public function eligibleUsers(): Collection
     {
         if (! now()->isFriday()) {
-            return new Collection();
+            return new Collection;
         }
 
         return User::whereHas('client')

+ 23 - 5
app/Notifications/Push/Cliente/Contextual/ContextualVisitaPush.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class ContextualVisitaPush extends BasePushNotification
 {
-    public function label(): string { return 'cliente_contextual_visita'; }
-    public function title(): string { return 'Visita marcada?'; }
-    public function body(): string  { return 'Uma diarista pode ajudar hoje.'; }
+    public function label(): string
+    {
+        return 'cliente_contextual_visita';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::CONTEXTUAL; }
+    public function title(): string
+    {
+        return 'Visita marcada?';
+    }
+
+    public function body(): string
+    {
+        return 'Uma diarista pode ajudar hoje.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::CONTEXTUAL;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Educativo/Educativo1Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Educativo1Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_educativo_1'; }
-    public function title(): string { return 'Você sabia?'; }
-    public function body(): string  { return 'No Diária, o pagamento só é liberado após o serviço concluído.'; }
+    public function label(): string
+    {
+        return 'cliente_educativo_1';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::EDUCATIVO; }
+    public function title(): string
+    {
+        return 'Você sabia?';
+    }
+
+    public function body(): string
+    {
+        return 'No Diária, o pagamento só é liberado após o serviço concluído.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::EDUCATIVO;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Educativo/Educativo2Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Educativo2Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_educativo_2'; }
-    public function title(): string { return 'Mais segurança'; }
-    public function body(): string  { return 'Você acompanha todo o serviço direto pelo app.'; }
+    public function label(): string
+    {
+        return 'cliente_educativo_2';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::EDUCATIVO; }
+    public function title(): string
+    {
+        return 'Mais segurança';
+    }
+
+    public function body(): string
+    {
+        return 'Você acompanha todo o serviço direto pelo app.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::EDUCATIVO;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Educativo/Educativo3Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Educativo3Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_educativo_3'; }
-    public function title(): string { return 'Dica importante'; }
-    public function body(): string  { return 'Avaliações ajudam a manter a qualidade das diaristas.'; }
+    public function label(): string
+    {
+        return 'cliente_educativo_3';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::EDUCATIVO; }
+    public function title(): string
+    {
+        return 'Dica importante';
+    }
+
+    public function body(): string
+    {
+        return 'Avaliações ajudam a manter a qualidade das diaristas.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::EDUCATIVO;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Educativo/Educativo4Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Educativo4Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_educativo_4'; }
-    public function title(): string { return 'Transparência'; }
-    public function body(): string  { return 'Você vê perfil, avaliações e valores antes de contratar.'; }
+    public function label(): string
+    {
+        return 'cliente_educativo_4';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::EDUCATIVO; }
+    public function title(): string
+    {
+        return 'Transparência';
+    }
+
+    public function body(): string
+    {
+        return 'Você vê perfil, avaliações e valores antes de contratar.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::EDUCATIVO;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 32 - 7
app/Notifications/Push/Cliente/EducativoConversao/EducativoConversao1Push.php

@@ -10,15 +10,40 @@ use Illuminate\Database\Eloquent\Collection;
 
 class EducativoConversao1Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_educ_conversao_1'; }
-    public function title(): string { return 'Sob Medida funciona assim'; }
-    public function body(): string  { return 'Seu pedido é enviado para várias diaristas disponíveis.'; }
+    public function label(): string
+    {
+        return 'cliente_educ_conversao_1';
+    }
+
+    public function title(): string
+    {
+        return 'Sob Medida funciona assim';
+    }
+
+    public function body(): string
+    {
+        return 'Seu pedido é enviado para várias diaristas disponíveis.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::EDUCATIVO_CONVERSAO; }
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::EDUCATIVO_CONVERSAO;
+    }
 
-    public function notificationCooldownDays(): int { return 28; }
-    public function categoryCooldownDays(): int     { return 14; }
+    public function notificationCooldownDays(): int
+    {
+        return 28;
+    }
+
+    public function categoryCooldownDays(): int
+    {
+        return 14;
+    }
 
     /**
      * Elegível se:

+ 32 - 7
app/Notifications/Push/Cliente/EducativoConversao/EducativoConversao2Push.php

@@ -10,15 +10,40 @@ use Illuminate\Database\Eloquent\Collection;
 
 class EducativoConversao2Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_educ_conversao_2'; }
-    public function title(): string { return 'Quer mais chances de aceite?'; }
-    public function body(): string  { return 'Pedidos Sob Medida aumentam a rapidez na confirmação.'; }
+    public function label(): string
+    {
+        return 'cliente_educ_conversao_2';
+    }
+
+    public function title(): string
+    {
+        return 'Quer mais chances de aceite?';
+    }
+
+    public function body(): string
+    {
+        return 'Pedidos Sob Medida aumentam a rapidez na confirmação.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::EDUCATIVO_CONVERSAO; }
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::EDUCATIVO_CONVERSAO;
+    }
 
-    public function notificationCooldownDays(): int { return 28; }
-    public function categoryCooldownDays(): int     { return 14; }
+    public function notificationCooldownDays(): int
+    {
+        return 28;
+    }
+
+    public function categoryCooldownDays(): int
+    {
+        return 14;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Marketing/Marketing1Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Marketing1Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_marketing_1'; }
-    public function title(): string { return 'Casa limpa sem esforço'; }
-    public function body(): string  { return 'Encontre uma diarista disponível em poucos minutos.'; }
+    public function label(): string
+    {
+        return 'cliente_marketing_1';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::MARKETING; }
+    public function title(): string
+    {
+        return 'Casa limpa sem esforço';
+    }
+
+    public function body(): string
+    {
+        return 'Encontre uma diarista disponível em poucos minutos.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::MARKETING;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Marketing/Marketing2Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Marketing2Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_marketing_2'; }
-    public function title(): string { return 'Precisando de ajuda hoje?'; }
-    public function body(): string  { return 'Veja diaristas disponíveis perto de você.'; }
+    public function label(): string
+    {
+        return 'cliente_marketing_2';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::MARKETING; }
+    public function title(): string
+    {
+        return 'Precisando de ajuda hoje?';
+    }
+
+    public function body(): string
+    {
+        return 'Veja diaristas disponíveis perto de você.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::MARKETING;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Marketing/Marketing3Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Marketing3Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_marketing_3'; }
-    public function title(): string { return 'Menos preocupação, mais tempo'; }
-    public function body(): string  { return 'Agende sua próxima diária agora mesmo.'; }
+    public function label(): string
+    {
+        return 'cliente_marketing_3';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::MARKETING; }
+    public function title(): string
+    {
+        return 'Menos preocupação, mais tempo';
+    }
+
+    public function body(): string
+    {
+        return 'Agende sua próxima diária agora mesmo.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::MARKETING;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Marketing/Marketing4Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Marketing4Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_marketing_4'; }
-    public function title(): string { return 'Agenda cheia?'; }
-    public function body(): string  { return 'Uma diarista pode resolver isso hoje.'; }
+    public function label(): string
+    {
+        return 'cliente_marketing_4';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::MARKETING; }
+    public function title(): string
+    {
+        return 'Agenda cheia?';
+    }
+
+    public function body(): string
+    {
+        return 'Uma diarista pode resolver isso hoje.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::MARKETING;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Motivacional/Motivacional1Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Motivacional1Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_motivacional_1'; }
-    public function title(): string { return 'Sua casa merece cuidado'; }
-    public function body(): string  { return 'E você merece tempo livre.'; }
+    public function label(): string
+    {
+        return 'cliente_motivacional_1';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::MOTIVACIONAL; }
+    public function title(): string
+    {
+        return 'Sua casa merece cuidado';
+    }
+
+    public function body(): string
+    {
+        return 'E você merece tempo livre.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::MOTIVACIONAL;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Motivacional/Motivacional2Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Motivacional2Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_motivacional_2'; }
-    public function title(): string { return 'Chegue em casa e relaxe'; }
-    public function body(): string  { return 'A limpeza fica por nossa conta.'; }
+    public function label(): string
+    {
+        return 'cliente_motivacional_2';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::MOTIVACIONAL; }
+    public function title(): string
+    {
+        return 'Chegue em casa e relaxe';
+    }
+
+    public function body(): string
+    {
+        return 'A limpeza fica por nossa conta.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::MOTIVACIONAL;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Motivacional/Motivacional3Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Motivacional3Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_motivacional_3'; }
-    public function title(): string { return 'Menos bagunça, mais bem-estar'; }
-    public function body(): string  { return 'Agende sua diária quando quiser.'; }
+    public function label(): string
+    {
+        return 'cliente_motivacional_3';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::MOTIVACIONAL; }
+    public function title(): string
+    {
+        return 'Menos bagunça, mais bem-estar';
+    }
+
+    public function body(): string
+    {
+        return 'Agende sua diária quando quiser.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::MOTIVACIONAL;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Recorrencia/Recorrencia1Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Recorrencia1Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_recorrencia_1'; }
-    public function title(): string { return 'Hora da próxima diária?'; }
-    public function body(): string  { return 'Faz um tempo desde sua última limpeza 😊'; }
+    public function label(): string
+    {
+        return 'cliente_recorrencia_1';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::RECORRENCIA; }
+    public function title(): string
+    {
+        return 'Hora da próxima diária?';
+    }
+
+    public function body(): string
+    {
+        return 'Faz um tempo desde sua última limpeza 😊';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::RECORRENCIA;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Recorrencia/Recorrencia2Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Recorrencia2Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_recorrencia_2'; }
-    public function title(): string { return 'Rotina em dia'; }
-    public function body(): string  { return 'Que tal agendar sua próxima diária?'; }
+    public function label(): string
+    {
+        return 'cliente_recorrencia_2';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::RECORRENCIA; }
+    public function title(): string
+    {
+        return 'Rotina em dia';
+    }
+
+    public function body(): string
+    {
+        return 'Que tal agendar sua próxima diária?';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::RECORRENCIA;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 23 - 5
app/Notifications/Push/Cliente/Recorrencia/Recorrencia3Push.php

@@ -10,12 +10,30 @@ use Illuminate\Database\Eloquent\Collection;
 
 class Recorrencia3Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_recorrencia_3'; }
-    public function title(): string { return 'Casa limpa dura pouco'; }
-    public function body(): string  { return 'Garanta sua próxima diária no app.'; }
+    public function label(): string
+    {
+        return 'cliente_recorrencia_3';
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::RECORRENCIA; }
+    public function title(): string
+    {
+        return 'Casa limpa dura pouco';
+    }
+
+    public function body(): string
+    {
+        return 'Garanta sua próxima diária no app.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
+
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::RECORRENCIA;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 32 - 7
app/Notifications/Push/Cliente/SocialProof/SocialProof1Push.php

@@ -10,15 +10,40 @@ use Illuminate\Database\Eloquent\Collection;
 
 class SocialProof1Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_social_proof_1'; }
-    public function title(): string { return 'Clientes como você'; }
-    public function body(): string  { return 'Já estão usando o Diária para facilitar a rotina.'; }
+    public function label(): string
+    {
+        return 'cliente_social_proof_1';
+    }
+
+    public function title(): string
+    {
+        return 'Clientes como você';
+    }
+
+    public function body(): string
+    {
+        return 'Já estão usando o Diária para facilitar a rotina.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::SOCIAL_PROOF; }
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::SOCIAL_PROOF;
+    }
 
-    public function notificationCooldownDays(): int { return 28; }
-    public function categoryCooldownDays(): int     { return 14; }
+    public function notificationCooldownDays(): int
+    {
+        return 28;
+    }
+
+    public function categoryCooldownDays(): int
+    {
+        return 14;
+    }
 
     /**
      * Elegível se:

+ 32 - 7
app/Notifications/Push/Cliente/SocialProof/SocialProof2Push.php

@@ -10,15 +10,40 @@ use Illuminate\Database\Eloquent\Collection;
 
 class SocialProof2Push extends BasePushNotification
 {
-    public function label(): string { return 'cliente_social_proof_2'; }
-    public function title(): string { return 'Diaristas bem avaliadas'; }
-    public function body(): string  { return 'Veja profissionais recomendadas perto de você.'; }
+    public function label(): string
+    {
+        return 'cliente_social_proof_2';
+    }
+
+    public function title(): string
+    {
+        return 'Diaristas bem avaliadas';
+    }
+
+    public function body(): string
+    {
+        return 'Veja profissionais recomendadas perto de você.';
+    }
+
+    public function target(): PushNotificationTargetEnum
+    {
+        return PushNotificationTargetEnum::CLIENTE;
+    }
 
-    public function target(): PushNotificationTargetEnum   { return PushNotificationTargetEnum::CLIENTE; }
-    public function category(): PushNotificationCategoryEnum { return PushNotificationCategoryEnum::SOCIAL_PROOF; }
+    public function category(): PushNotificationCategoryEnum
+    {
+        return PushNotificationCategoryEnum::SOCIAL_PROOF;
+    }
 
-    public function notificationCooldownDays(): int { return 28; }
-    public function categoryCooldownDays(): int     { return 14; }
+    public function notificationCooldownDays(): int
+    {
+        return 28;
+    }
+
+    public function categoryCooldownDays(): int
+    {
+        return 14;
+    }
 
     public function eligibleUsers(): Collection
     {

+ 10 - 10
app/Notifications/Push/Prestador/ReforcoEducativo/ReforcoEducativo1Push.php

@@ -62,16 +62,16 @@ class ReforcoEducativo1Push extends BasePushNotification
                     'provider_reforco_educativo_1',
                     'provider_reforco_educativo_2',
                 ]))
-                ->orWhereHas('pushNotificationLogs', function ($q) use ($threeWeeksAgo) {
-                    $q->where('label', 'provider_reforco_educativo_2')
-                        ->where('sent_at', '<=', $threeWeeksAgo)
-                        ->whereNotExists(function ($sub) use ($threeWeeksAgo) {
-                            $sub->from('push_notification_logs as pnl2')
-                                ->whereColumn('pnl2.user_id', 'push_notification_logs.user_id')
-                                ->where('pnl2.label', 'provider_reforco_educativo_1')
-                                ->where('pnl2.sent_at', '>', $threeWeeksAgo);
-                        });
-                });
+                    ->orWhereHas('pushNotificationLogs', function ($q) use ($threeWeeksAgo) {
+                        $q->where('label', 'provider_reforco_educativo_2')
+                            ->where('sent_at', '<=', $threeWeeksAgo)
+                            ->whereNotExists(function ($sub) use ($threeWeeksAgo) {
+                                $sub->from('push_notification_logs as pnl2')
+                                    ->whereColumn('pnl2.user_id', 'push_notification_logs.user_id')
+                                    ->where('pnl2.label', 'provider_reforco_educativo_1')
+                                    ->where('pnl2.sent_at', '>', $threeWeeksAgo);
+                            });
+                    });
             })
             ->get();
     }

+ 238 - 231
app/Services/AuthService.php

@@ -17,114 +17,114 @@ use Illuminate\Support\Str;
 
 class AuthService
 {
-  public function __construct(
-    private readonly EmailService $emailService,
-  ) {}
+    public function __construct(
+        private readonly EmailService $emailService,
+    ) {}
 
-  public function login(string $email, string $password): ?array
-  {
-    $user = User::where('email', $email)->first();
+    public function login(string $email, string $password): ?array
+    {
+        $user = User::where('email', $email)->first();
 
-    if (!$user || !in_array($user->type, [UserTypeEnum::ADMIN, UserTypeEnum::USER])) {
-      return null;
-    }
+        if (! $user || ! in_array($user->type, [UserTypeEnum::ADMIN, UserTypeEnum::USER])) {
+            return null;
+        }
 
-    if (!Auth::attempt(['email' => $email, 'password' => $password])) {
-      return null;
-    }
+        if (! Auth::attempt(['email' => $email, 'password' => $password])) {
+            return null;
+        }
 
-    // $user = User::where('email', $email)->first();
-    $deviceId = Str::uuid()->toString();
+        // $user = User::where('email', $email)->first();
+        $deviceId = Str::uuid()->toString();
 
         $accessToken = $user->createAccessToken($deviceId);
         $refreshToken = $user->createRefreshToken($deviceId);
 
-    return [
-      'payload' => [
-        'access_token' => $accessToken,
-        'user'         => $user,
-      ],
-      'refreshToken' => $refreshToken,
-    ];
-  }
-
-  public function refresh(string $refreshToken): ?array
-  {
-    if (!$refreshToken) {
-      return null;
+        return [
+            'payload' => [
+                'access_token' => $accessToken,
+                'user'         => $user,
+            ],
+            'refreshToken' => $refreshToken,
+        ];
     }
 
-    $tokenModel = PersonalAccessToken::findToken($refreshToken);
+    public function refresh(string $refreshToken): ?array
+    {
+        if (! $refreshToken) {
+            return null;
+        }
 
-    if (
-      !$tokenModel ||
-      !in_array("refresh", $tokenModel->abilities) ||
-      $tokenModel->expires_at < now()
-    ) {
-      return null;
-    }
+        $tokenModel = PersonalAccessToken::findToken($refreshToken);
 
-    $user = $tokenModel->tokenable;
-    if (!$user) {
-      return null;
-    }
+        if (
+            ! $tokenModel ||
+            ! in_array('refresh', $tokenModel->abilities) ||
+            $tokenModel->expires_at < now()
+        ) {
+            return null;
+        }
 
-    $deviceId = Str::afterLast($tokenModel->name, "_");
+        $user = $tokenModel->tokenable;
+        if (! $user) {
+            return null;
+        }
 
-    $tokens = $this->refreshTokenTransaction($tokenModel, $user, $deviceId);
+        $deviceId = Str::afterLast($tokenModel->name, '_');
 
-    return [
-      "payload" => [
-        "access_token" => $tokens["access_token"],
-        "user" => $user,
-      ],
-      "refreshToken" => $tokens["refresh_token"],
-    ];
-  }
+        $tokens = $this->refreshTokenTransaction($tokenModel, $user, $deviceId);
 
-  public function logout(): void
-  {
-    $user = Auth::user();
-    if (!$user) {
-      return;
+        return [
+            'payload' => [
+                'access_token' => $tokens['access_token'],
+                'user'         => $user,
+            ],
+            'refreshToken' => $tokens['refresh_token'],
+        ];
     }
 
+    public function logout(): void
+    {
+        $user = Auth::user();
+        if (! $user) {
+            return;
+        }
+
         $tokenName = $user->currentAccessToken()->name;
         $deviceId = Str::afterLast($tokenName, '_');
 
-    $user
-      ->tokens()
-      ->where("name", "like", "%_{$deviceId}")
-      ->delete();
-  }
-
-  protected function refreshTokenTransaction(
-    PersonalAccessToken $tokenModel,
-    User $user,
-    string $deviceId,
-  ): array {
-    return DB::transaction(function () use (
-      $tokenModel,
-      $user,
-      $deviceId,
+        $user
+            ->tokens()
+            ->where('name', 'like', "%_{$deviceId}")
+            ->delete();
+    }
+
+    protected function refreshTokenTransaction(
+        PersonalAccessToken $tokenModel,
+        User $user,
+        string $deviceId,
     ): array {
-      $tokenModel->update(["expires_at" => Carbon::now()]);
+        return DB::transaction(function () use (
+            $tokenModel,
+            $user,
+            $deviceId,
+        ): array {
+            $tokenModel->update(['expires_at' => Carbon::now()]);
 
             $accessToken = $user->createAccessToken($deviceId);
             $refreshToken = $user->createRefreshToken($deviceId);
 
-      return [
-        "access_token" => $accessToken,
-        "refresh_token" => $refreshToken,
-      ];
-    });
-  }
+            return [
+                'access_token'  => $accessToken,
+                'refresh_token' => $refreshToken,
+            ];
+        });
+    }
 
-  public function clientSendCode(array $data): bool|array|null
-  {
-    try {
-      DB::beginTransaction();
-      $code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
+    public function clientSendCode(array $data): bool|array|null
+    {
+        try {
+            DB::beginTransaction();
+            $code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
 
             $user = User::where(function ($query) use ($data) {
                 $query->when(! empty($data['email']), function ($q) use ($data) {
@@ -172,93 +172,99 @@ class AuthService
                 Client::create(['user_id' => $user->id]);
             }
 
-      if (!empty($data['email'])) {
-        $this->emailService->sendVerificationCode(
-          email: $data['email'],
-          code: $code,
-          recipientName: $data['name'] ?? '',
-        );
-      } elseif (!empty($data['phone'])) {
-        Log::info('SMS: envio de código por telefone ainda não implementado.', [
-          'phone' => $data['phone'],
-        ]);
-      }
-
-      DB::commit();
-      return $isLogin;
-    } catch (\Exception $e) {
-      DB::rollBack();
-      Log::error('Erro ao enviar código de verificação.', [
-        'error' => $e->getMessage(),
-        'data' => $data,
-      ]);
-      return false;
-    }
-  }
+            if (! empty($data['email'])) {
+                $this->emailService->sendVerificationCode(
+                    email: $data['email'],
+                    code: $code,
+                    recipientName: $data['name'] ?? '',
+                );
+            } elseif (! empty($data['phone'])) {
+                Log::info('SMS: envio de código por telefone ainda não implementado.', [
+                    'phone' => $data['phone'],
+                ]);
+            }
 
-  public function providerSendCode(array $data): bool|array|null
-  {
-    try {
-      DB::beginTransaction();
-      $code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
+            DB::commit();
 
-      $user = User::where(function ($query) use ($data) {
-        $query->when(!empty($data['email']), function ($q) use ($data) {
-          $q->where('email', $data['email']);
-        })
-          ->when(!empty($data['phone']), function ($q) use ($data) {
-            $q->where('phone', $data['phone']);
-          });
-      })
-        ->first();
-      $isLogin = false;
-      if ($user) {
-        if ($user->type->value !== UserTypeEnum::PROVIDER->value) {
-          DB::rollBack();
-          return ['error' => 'wrong_user_type'];
+            return $isLogin;
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('Erro ao enviar código de verificação.', [
+                'error' => $e->getMessage(),
+                'data'  => $data,
+            ]);
+
+            return false;
         }
-        $provider = Provider::where('user_id', $user->id)->first();
-        if($provider && $provider->approval_status->value !== ApprovalStatusEnum::ACCEPTED->value) {
-          DB::rollBack();
-          return ['error' => 'provider_not_accepted'];
+    }
+
+    public function providerSendCode(array $data): bool|array|null
+    {
+        try {
+            DB::beginTransaction();
+            $code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
+
+            $user = User::where(function ($query) use ($data) {
+                $query->when(! empty($data['email']), function ($q) use ($data) {
+                    $q->where('email', $data['email']);
+                })
+                    ->when(! empty($data['phone']), function ($q) use ($data) {
+                        $q->where('phone', $data['phone']);
+                    });
+            })
+                ->first();
+            $isLogin = false;
+            if ($user) {
+                if ($user->type->value !== UserTypeEnum::PROVIDER->value) {
+                    DB::rollBack();
+
+                    return ['error' => 'wrong_user_type'];
+                }
+                $provider = Provider::where('user_id', $user->id)->first();
+                if ($provider && $provider->approval_status->value !== ApprovalStatusEnum::ACCEPTED->value) {
+                    DB::rollBack();
+
+                    return ['error' => 'provider_not_accepted'];
+                }
+
+                $user->code = $code;
+                $user->validated_code = false;
+                $user->save();
+                $isLogin = true;
+            } else {
+                $user = new User;
+                $user->fill($data);
+                $user->code = $code;
+                $user->name = $data['name'] ?? 'Usuário';
+                $user->type = $data['type'] ?? UserTypeEnum::PROVIDER->value;
+                $user->save();
+            }
+
+            if (! empty($data['email'])) {
+                $this->emailService->sendVerificationCode(
+                    email: $data['email'],
+                    code: $code,
+                    recipientName: $data['name'] ?? '',
+                );
+            } elseif (! empty($data['phone'])) {
+                Log::info('SMS: envio de código por telefone ainda não implementado.', [
+                    'phone' => $data['phone'],
+                ]);
+            }
+
+            DB::commit();
+
+            return $isLogin;
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('Erro ao enviar código de verificação.', [
+                'error' => $e->getMessage(),
+                'data'  => $data,
+            ]);
+
+            return false;
         }
-         
-        $user->code = $code;
-        $user->validated_code = false;
-        $user->save();
-        $isLogin = true;
-      } else {
-        $user = new User();
-        $user->fill($data);
-        $user->code = $code;
-        $user->name = $data['name'] ?? 'Usuário';
-        $user->type = $data['type'] ?? UserTypeEnum::PROVIDER->value;
-        $user->save();
-      }
-
-      if (!empty($data['email'])) {
-        $this->emailService->sendVerificationCode(
-          email: $data['email'],
-          code: $code,
-          recipientName: $data['name'] ?? '',
-        );
-      } elseif (!empty($data['phone'])) {
-        Log::info('SMS: envio de código por telefone ainda não implementado.', [
-          'phone' => $data['phone'],
-        ]);
-      }
-
-      DB::commit();
-      return $isLogin;
-    } catch (\Exception $e) {
-      DB::rollBack();
-      Log::error('Erro ao enviar código de verificação.', [
-        'error' => $e->getMessage(),
-        'data' => $data,
-      ]);
-      return false;
     }
-  }
 
     public function validateCodeClient(array $data, bool $isLogin): bool|array
     {
@@ -266,23 +272,23 @@ class AuthService
         $phone = $data['phone'] ?? null;
         $code = $data['code'] ?? '';
 
-    $user = User::where(function ($query) use ($email, $phone) {
-        $query->when($email, fn($q) => $q->where('email', $email))
-              ->when($phone,  fn($q) => $q->where('phone', $phone));
-      })
-      ->where('code', $code)
-      ->first();
+        $user = User::where(function ($query) use ($email, $phone) {
+            $query->when($email, fn ($q) => $q->where('email', $email))
+                ->when($phone, fn ($q) => $q->where('phone', $phone));
+        })
+            ->where('code', $code)
+            ->first();
 
-    if (!$user) {
-      return false;
-    }
+        if (! $user) {
+            return false;
+        }
 
-    if ($isLogin) {
-      return $this->loginWithEmail($user->email, $code);
-    }
+        if ($isLogin) {
+            return $this->loginWithEmail($user->email, $code);
+        }
 
-    return true;
-  }
+        return true;
+    }
 
     public function validateCodeProvider(array $data, bool $isLogin): bool|array
     {
@@ -290,69 +296,70 @@ class AuthService
         $phone = $data['phone'] ?? null;
         $code = $data['code'] ?? '';
 
-    $user = User::where(function ($query) use ($email, $phone) {
-        $query->when($email, fn($q) => $q->where('email', $email))
-              ->when($phone,  fn($q) => $q->where('phone', $phone));
-      })
-      ->where('code', $code)
-      ->first();
+        $user = User::where(function ($query) use ($email, $phone) {
+            $query->when($email, fn ($q) => $q->where('email', $email))
+                ->when($phone, fn ($q) => $q->where('phone', $phone));
+        })
+            ->where('code', $code)
+            ->first();
 
-    if (!$user) {
-      return false;
-    }
+        if (! $user) {
+            return false;
+        }
+
+        if ($isLogin) {
+            $user->load('provider');
+            $provider = $user->provider ?? null;
 
-    if ($isLogin) {
-      $user->load('provider');
-      $provider = $user->provider ?? null;
+            if ($provider && $provider->approval_status === ApprovalStatusEnum::PENDING->value) {
+                return ['error' => 'provider_pending'];
+            }
 
-      if ($provider && $provider->approval_status === ApprovalStatusEnum::PENDING->value) {
-        return ['error' => 'provider_pending'];
-      }
+            if ($provider && $provider->approval_status === ApprovalStatusEnum::REJECTED->value) {
+                return ['error' => 'provider_rejected'];
+            }
 
-      if ($provider && $provider->approval_status === ApprovalStatusEnum::REJECTED->value) {
-        return ['error' => 'provider_rejected'];
-      }
+            return $this->loginWithEmail($user->email, $code);
+        }
 
-      return $this->loginWithEmail($user->email, $code);
+        return true;
     }
 
-    return true;
-  }
-
     public function validateCode(array $data, bool $isLogin): bool|array
     {
         $email = $data['email'] ?? null;
         $phone = $data['phone'] ?? null;
         $code = $data['code'] ?? '';
 
-    $user = User::where(function ($query) use ($email, $phone) {
-      $query->when($email, function ($q) use ($email) {
-        $q->where('email', $email);
-      })
-        ->when($phone, function ($q) use ($phone) {
-          $q->where('phone', $phone);
-        });
-    })
-      ->where('code', $code)
-      ->first();
+        $user = User::where(function ($query) use ($email, $phone) {
+            $query->when($email, function ($q) use ($email) {
+                $q->where('email', $email);
+            })
+                ->when($phone, function ($q) use ($phone) {
+                    $q->where('phone', $phone);
+                });
+        })
+            ->where('code', $code)
+            ->first();
 
-    if (!$user) {
-      return false;
-    }
+        if (! $user) {
+            return false;
+        }
 
-    if($isLogin) {
-      $resultLogin = $this->loginWithEmail($user->email, $code);
-      return $resultLogin;
-    }
+        if ($isLogin) {
+            $resultLogin = $this->loginWithEmail($user->email, $code);
+
+            return $resultLogin;
+        }
 
-    return true;
-  }
+        return true;
+    }
 
-  public function loginWithEmail(string $email, string $code): ?array
-  {
-    $user = User::where('email', $email)
-      ->where('code', $code)
-      ->first();
+    public function loginWithEmail(string $email, string $code): ?array
+    {
+        $user = User::where('email', $email)
+            ->where('code', $code)
+            ->first();
 
         if (! $user) {
             return null;
@@ -369,12 +376,12 @@ class AuthService
 
         $user->save();
 
-    return [
-      "payload" => [
-        "access_token" => $accessToken,
-        "user" => $user,
-      ],
-      "refreshToken" => $refreshToken,
-    ];
-  }
+        return [
+            'payload' => [
+                'access_token' => $accessToken,
+                'user'         => $user,
+            ],
+            'refreshToken' => $refreshToken,
+        ];
+    }
 }

+ 7 - 9
app/Services/CustomScheduleService.php

@@ -2,6 +2,7 @@
 
 namespace App\Services;
 
+use App\Enums\NotificationTypeEnum;
 use App\Models\Address;
 use App\Models\CustomSchedule;
 use App\Models\CustomScheduleSpeciality;
@@ -10,13 +11,10 @@ use App\Models\Schedule;
 use App\Models\ScheduleProposal;
 use App\Models\ScheduleRefuse;
 use App\Rules\ScheduleBusinessRules;
-use App\Services\DistanceService;
 use Carbon\Carbon;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Log;
 use Illuminate\Support\Facades\Storage;
-use App\Enums\NotificationTypeEnum;
-use App\Services\NotificationService;
 
 class CustomScheduleService
 {
@@ -110,7 +108,7 @@ class CustomScheduleService
             return $createdCustomSchedules;
         } catch (\Exception $e) {
             DB::rollBack();
-            Log::error('Error creating custom schedule: ' . $e->getMessage());
+            Log::error('Error creating custom schedule: '.$e->getMessage());
             throw $e;
         }
     }
@@ -202,7 +200,7 @@ class CustomScheduleService
             ]);
         } catch (\Exception $e) {
             DB::rollBack();
-            Log::error('Error updating custom schedule: ' . $e->getMessage());
+            Log::error('Error updating custom schedule: '.$e->getMessage());
             throw $e;
         }
     }
@@ -226,7 +224,7 @@ class CustomScheduleService
             return $customSchedule;
         } catch (\Exception $e) {
             DB::rollBack();
-            Log::error('Error deleting custom schedule: ' . $e->getMessage());
+            Log::error('Error deleting custom schedule: '.$e->getMessage());
             throw $e;
         }
     }
@@ -409,8 +407,7 @@ class CustomScheduleService
             $notificationService->create([
                 'title' => 'Proposta aceita!',
 
-                'description' =>
-                'O cliente aceitou sua proposta de diária.',
+                'description' => 'O cliente aceitou sua proposta de diária.',
 
                 'origin' => 'schedule',
 
@@ -543,13 +540,14 @@ class CustomScheduleService
             $firstSchedule = $clientSchedules->first();
 
             $clientPhotoPath = $firstSchedule->client->profileMedia?->path;
+
             return [
                 'client_id'      => $firstSchedule->client_id,
                 'client_name'    => $firstSchedule->client->user->name ?? 'N/A',
                 'customer_photo' => $clientPhotoPath
                     ? Storage::temporaryUrl($clientPhotoPath, now()->addMinutes(60))
                     : null,
-                'schedules'   => $clientSchedules->map(function ($schedule) {
+                'schedules' => $clientSchedules->map(function ($schedule) {
                     $customSchedule = $schedule->customSchedule;
 
                     return [

+ 21 - 21
app/Services/DashboardService.php

@@ -7,15 +7,14 @@ use App\Models\Address;
 use App\Models\Client;
 use App\Models\ClientFavoriteProvider;
 use App\Models\ClientPaymentMethod;
+use App\Models\Notification;
 use App\Models\Provider;
 use App\Models\ProviderSpeciality;
 use App\Models\Review;
 use App\Models\Schedule;
 use App\Models\ScheduleProposal;
 use App\Models\Speciality;
-use App\Models\Notification;
 use App\Rules\ScheduleBusinessRules;
-use App\Services\DistanceService;
 use Illuminate\Auth\Access\AuthorizationException;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
@@ -53,8 +52,8 @@ class DashboardService
             ->first();
 
         $summaryInfos = [
-            'name'             => $user->name,
-            'profile_photo'    => $cliente->profileMedia?->path
+            'name'          => $user->name,
+            'profile_photo' => $cliente->profileMedia?->path
                 ? Storage::temporaryUrl($cliente->profileMedia->path, now()->addMinutes(60))
                 : null,
             'address'          => $address,
@@ -152,7 +151,7 @@ class DashboardService
             unset($item->provider_photo_path);
         });
 
-        $blockedProviderIds       = ScheduleBusinessRules::getBlockedProviderIdsForClient($cliente->id);
+        $blockedProviderIds = ScheduleBusinessRules::getBlockedProviderIdsForClient($cliente->id);
         $providersWithWorkingDays = ScheduleBusinessRules::getProviderIdsWithWorkingDays();
 
         $clientPrimaryAddress = Address::where('source', 'client')
@@ -336,6 +335,7 @@ class DashboardService
                 $item->provider_photo = $item->provider_photo
                     ? Storage::temporaryUrl($item->provider_photo, now()->addMinutes(60))
                     : null;
+
                 return $item;
             });
 
@@ -346,12 +346,12 @@ class DashboardService
             ->get()
             ->map(function ($notification) {
                 return [
-                    'id' => $notification->id,
-                    'title' => $notification->title,
+                    'id'          => $notification->id,
+                    'title'       => $notification->title,
                     'description' => $notification->description,
-                    'time' => $notification->created_at->diffForHumans(),
-                    'read' => $notification->read,
-                    'avatar' => '/icons/avatar.svg',
+                    'time'        => $notification->created_at->diffForHumans(),
+                    'read'        => $notification->read,
+                    'avatar'      => '/icons/avatar.svg',
                 ];
             });
 
@@ -402,7 +402,7 @@ class DashboardService
             ->pluck('speciality_id')
             ->all();
 
-        $specialities = $allSpecialities->map(fn($sp) => [
+        $specialities = $allSpecialities->map(fn ($sp) => [
             'id'             => $sp->id,
             'description'    => $sp->description,
             'has_speciality' => in_array($sp->id, $providerSpecialityIds),
@@ -414,8 +414,8 @@ class DashboardService
             'provider_photo'      => $schedule->provider_photo
                 ? Storage::temporaryUrl($schedule->provider_photo, now()->addMinutes(60))
                 : null,
-            'offers_meal'         => $schedule->offers_meal,
-            'specialities'        => $specialities,
+            'offers_meal'  => $schedule->offers_meal,
+            'specialities' => $specialities,
         ];
     }
 
@@ -438,8 +438,8 @@ class DashboardService
         $address = Address::where('source', 'provider')->where('source_id', $provider->id)->with(['city', 'state'])->first();
 
         $summaryInfos = [
-            'name'             => $user->name,
-            'profile_photo'    => $provider->profileMedia?->path
+            'name'          => $user->name,
+            'profile_photo' => $provider->profileMedia?->path
                 ? Storage::temporaryUrl($provider->profileMedia->path, now()->addMinutes(60))
                 : null,
             'address'          => $address,
@@ -621,12 +621,12 @@ class DashboardService
             ->get()
             ->map(function ($notification) {
                 return [
-                    'id' => $notification->id,
-                    'title' => $notification->title,
+                    'id'          => $notification->id,
+                    'title'       => $notification->title,
                     'description' => $notification->description,
-                    'time' => $notification->created_at->diffForHumans(),
-                    'read' => $notification->read,
-                    'avatar' => '/icons/avatar.svg',
+                    'time'        => $notification->created_at->diffForHumans(),
+                    'read'        => $notification->read,
+                    'avatar'      => '/icons/avatar.svg',
                 ];
             });
 
@@ -646,7 +646,7 @@ class DashboardService
             'todayServices'  => $todayServices,
             'nextSchedules'  => $nextSchedules,
             'opportunities'  => $opportunities,
-            'notifications' => $notifications,
+            'notifications'  => $notifications,
         ];
     }
 

+ 1 - 1
app/Services/DistanceService.php

@@ -44,7 +44,7 @@ class DistanceService
                 WHEN {$targetLatCol} IS NOT NULL
                 AND {$targetLngCol} IS NOT NULL
                 THEN ROUND((
-                    " . self::EARTH_RADIUS_KM . " * acos(
+                    ".self::EARTH_RADIUS_KM." * acos(
                         least(1, greatest(-1,
                             cos(radians({$clientLatitude}))
                             * cos(radians({$targetLatCol}))

+ 1 - 1
app/Services/MediaService.php

@@ -10,7 +10,7 @@ use Illuminate\Http\UploadedFile;
 
 class MediaService
 {
-    use UploadsFile, RemoveArchiveS3;
+    use RemoveArchiveS3, UploadsFile;
 
     public function getAll(): Collection
     {

+ 2 - 2
app/Services/NotificationService.php

@@ -28,7 +28,7 @@ class NotificationService
     public function markAsRead(Notification $notification): Notification
     {
         $notification->update([
-            'read' => true,
+            'read'    => true,
             'read_at' => now(),
         ]);
 
@@ -40,7 +40,7 @@ class NotificationService
         Notification::where('user_id', $userId)
             ->where('read', false)
             ->update([
-                'read' => true,
+                'read'    => true,
                 'read_at' => now(),
             ]);
     }

+ 2 - 3
app/Services/Pagarme/Concerns/SendsPagarmeRequests.php

@@ -2,7 +2,6 @@
 
 namespace App\Services\Pagarme\Concerns;
 
-use App\Data\Pagarme\PagarmeData;
 use Illuminate\Support\Facades\Http;
 use Illuminate\Support\Facades\Log;
 use Throwable;
@@ -14,9 +13,9 @@ trait SendsPagarmeRequests
         string $path,
         string $idempotencyKey,
         string $errorMessage,
-        array|PagarmeData $payload,
+        array|Data $payload,
     ): array {
-        $payload = $payload instanceof PagarmeData ? $payload->toArray() : $payload;
+        $payload = $payload instanceof Data ? $payload->toArray() : $payload;
 
         $endpoint = $this->pagarmeUrl($path);
 

+ 8 - 8
app/Services/Pagarme/PagarmeCardService.php

@@ -2,9 +2,9 @@
 
 namespace App\Services\Pagarme;
 
-use App\Data\Pagarme\Request\PagarmeCardRequestData\PagarmeCardBillingAddressData;
-use App\Data\Pagarme\Request\PagarmeCardRequestData\PagarmeCardRequestData;
-use App\Data\Pagarme\Response\PagarmeCardResponseData;
+use App\Data\Pagarme\Request\CardRequestData\CardBillingAddressData;
+use App\Data\Pagarme\Request\CardRequestData\CardRequestData;
+use App\Data\Pagarme\Response\CardResponseData;
 use App\Models\Address;
 use App\Models\ClientPaymentMethod;
 use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
@@ -30,14 +30,14 @@ class PagarmeCardService
             []
         );
 
-        $cardData = PagarmeCardResponseData::fromArray($this->pagarmeRequest(
+        $cardData = CardResponseData::fromArray($this->pagarmeRequest(
             method: 'POST',
             path: "/customers/{$customerId}/cards",
 
-            payload: new PagarmeCardRequestData(
+            payload: new CardRequestData(
                 token: $paymentMethod->token,
                 label: $paymentMethod->card_name,
-                billingAddress: PagarmeCardBillingAddressData::fromAddress(
+                billingAddress: CardBillingAddressData::fromAddress(
                     Address::query()
                         ->with(['city.state', 'state'])
                         ->where('source', 'client')
@@ -56,8 +56,8 @@ class PagarmeCardService
 
         $paymentMethod->forceFill([
             'gateway_card_id'  => $cardId,
-            'brand'            => $paymentMethod->brand ?: $cardData->brand(),
-            'last_four_digits' => $paymentMethod->last_four_digits ?: $cardData->lastFourDigits(),
+            'brand'            => $paymentMethod->brand ?: $cardData->brand,
+            'last_four_digits' => $paymentMethod->last_four_digits ?: $cardData->lastFourDigits,
         ])->save();
 
         return $cardId;

+ 74 - 12
app/Services/Pagarme/PagarmeCustomerService.php

@@ -2,8 +2,11 @@
 
 namespace App\Services\Pagarme;
 
-use App\Data\Pagarme\Request\PagarmeCustomerRequestData\PagarmeCustomerRequestData;
-use App\Data\Pagarme\Response\PagarmeCustomerResponseData\PagarmeCustomerResponseData;
+use App\Data\Pagarme\Request\CustomerRequestData\CustomerAddressRequestData;
+use App\Data\Pagarme\Request\CustomerRequestData\CustomerPhonesRequestData\CustomerPhoneData;
+use App\Data\Pagarme\Request\CustomerRequestData\CustomerPhonesRequestData\CustomerPhonesRequestData;
+use App\Data\Pagarme\Request\CustomerRequestData\CustomerRequestData;
+use App\Data\Pagarme\Response\CustomerResponseData\CustomerResponseData;
 use App\Models\Client;
 use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
 use Illuminate\Support\Str;
@@ -22,20 +25,29 @@ class PagarmeCustomerService
 
         $name = $client->user?->name ?? $data['name'] ?? 'Cliente';
         $email = $client->user?->email ?? $data['email'] ?? null;
-
         $code = $this->ensureCustomerCode($client);
 
-        $customerData = PagarmeCustomerResponseData::fromArray($this->pagarmeRequest(
+        $document = $this->onlyDigits($client->document ?? $data['document'] ?? null);
+        $documentLen = strlen($document);
+
+        $address = $this->buildAddressData($data);
+        $phones = $this->buildPhones($client->user?->phone ?? $data['phone'] ?? null);
+
+        $customerRequest = new CustomerRequestData(
+            name: $name,
+            email: (string) $email,
+            document: $document,
+            type: $documentLen === 14 ? 'company' : 'individual',
+            documentType: $documentLen === 14 ? 'CNPJ' : 'CPF',
+            code: $code,
+            address: $address,
+            phones: $phones,
+        );
+
+        $customerData = CustomerResponseData::fromArray($this->pagarmeRequest(
             method: 'POST',
             path: '/customers',
-            payload: PagarmeCustomerRequestData::fromPayload(
-                name: $name,
-                email: $email,
-                document: $client->document ?? $data['document'] ?? null,
-                code: $code,
-                addressData: $data,
-                phone: $client->user?->phone ?? $data['phone'] ?? null,
-            ),
+            payload: $customerRequest,
             idempotencyKey: $this->idempotencyKey($client->id),
             errorMessage: 'Erro ao criar cliente no Pagar.me.',
         ));
@@ -50,6 +62,56 @@ class PagarmeCustomerService
         return $customerId;
     }
 
+    //
+
+    private function buildAddressData(array $data): CustomerAddressRequestData
+    {
+        $line1Parts = array_filter([
+            (string) ($data['number'] ?? '0'),
+            (string) ($data['address'] ?? ''),
+            (string) ($data['district'] ?? ''),
+        ], static fn ($value) => $value !== '');
+
+        return new CustomerAddressRequestData(
+            line1: implode(', ', $line1Parts),
+            line2: (string) ($data['complement'] ?? $data['instructions'] ?? ''),
+            zipCode: $this->onlyDigits($data['zip_code'] ?? null),
+            city: (string) ($data['city'] ?? ''),
+            state: (string) ($data['state'] ?? ''),
+            country: (string) ($data['country'] ?? 'BR'),
+        );
+    }
+
+    private function buildPhones(?string $phone): CustomerPhonesRequestData
+    {
+        $digits = $this->onlyDigits($phone);
+
+        if ($digits === '') {
+            return new CustomerPhonesRequestData;
+        }
+
+        $areaCode = substr($digits, 0, 2);
+        $number = substr($digits, 2);
+
+        if (strlen($digits) <= 2) {
+            $areaCode = '';
+            $number = $digits;
+        }
+
+        return new CustomerPhonesRequestData(
+            mobilePhone: new CustomerPhoneData(
+                countryCode: '55',
+                areaCode: $areaCode,
+                number: $number,
+            ),
+        );
+    }
+
+    private function onlyDigits(?string $value): string
+    {
+        return preg_replace('/\D+/', '', (string) $value) ?? '';
+    }
+
     // evita criacao duplicada de customer
 
     private function idempotencyKey(int $clientId, string $suffix = 'customer'): string

+ 272 - 42
app/Services/Pagarme/PagarmePaymentService.php

@@ -2,12 +2,25 @@
 
 namespace App\Services\Pagarme;
 
-use App\Data\Pagarme\Request\PagarmeOrderRequestData\PagarmeOrderRequestData;
-use App\Data\Pagarme\Response\PagarmeOrderResponseData\PagarmeOrderResponseData;
+use App\Data\Pagarme\Request\CustomerRequestData\CustomerAddressRequestData;
+use App\Data\Pagarme\Request\CustomerRequestData\CustomerPhonesRequestData\CustomerPhoneData;
+use App\Data\Pagarme\Request\CustomerRequestData\CustomerPhonesRequestData\CustomerPhonesRequestData;
+use App\Data\Pagarme\Request\CustomerRequestData\CustomerRequestData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderItemData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderCreditCardData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderPaymentData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderPixAdditionalInformationData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderPixData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderSplitData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderPaymentData\OrderSplitOptionsData;
+use App\Data\Pagarme\Request\OrderRequestData\OrderRequestData;
+use App\Data\Pagarme\Response\OrderResponseData\OrderResponseData;
 use App\Enums\PaymentSplitStatusEnum;
 use App\Enums\PaymentStatusEnum;
+use App\Models\Address;
 use App\Models\Payment;
 use App\Models\PaymentSplit;
+use App\Models\Schedule;
 use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
 use Illuminate\Support\Str;
 
@@ -15,18 +28,73 @@ class PagarmePaymentService
 {
     use SendsPagarmeRequests;
 
+    public function processPayment(
+        Payment $payment,
+        Schedule $schedule,
+        string $paymentMethod,
+        ?string $cardId = null,
+        array $options = [],
+    ): array {
+        $grossAmount = (float) $payment->gross_amount;
+
+        $items = $this->buildOrderItems($schedule, $grossAmount);
+        $customer = $this->buildCustomer($schedule, $options);
+        $split = $this->buildSplit($payment, $options);
+
+        $pixOptions = config('services.pagarme.pix_disable_split')
+            ? []
+            : ['split' => $split];
+
+        $orderOptions = array_merge(['split' => $split], $pixOptions);
+
+        if ($paymentMethod === 'credit_card') {
+            $creditCard = new OrderCreditCardData(
+                cardId: $cardId,
+                installments: 1,
+                statementDescriptor: Str::limit((string) config('app.name', 'SOFTPAR'), 13, ''),
+                operationType: 'auth_and_capture',
+            );
+
+            return $this->createOrderWithCreditCard(
+                payment: $payment,
+                items: $items,
+                customer: $customer,
+                creditCard: $creditCard,
+                options: $orderOptions,
+            );
+        }
+
+        $pixData = new OrderPixData(
+            expiresIn: 1800,
+            additionalInformation: [
+                new OrderPixAdditionalInformationData(
+                    name: 'Agendamento',
+                    value: (string) $schedule->id,
+                ),
+            ],
+        );
+
+        return $this->createOrderWithPix(
+            payment: $payment,
+            items: $items,
+            customer: $customer,
+            pix: $pixData,
+            options: $pixOptions,
+        );
+    }
+
     public function createOrderWithCreditCard(
         Payment $payment,
         array $items,
-        array $customer,
-        array $creditCard,
+        CustomerRequestData $customer,
+        OrderCreditCardData $creditCard,
         array $options = []
     ): array {
         return $this->createOrder(
             payment: $payment,
             items: $items,
             customer: $customer,
-            paymentMethod: PagarmeOrderRequestData::creditCardPaymentMethod(
+            paymentMethod: OrderRequestData::creditCardPaymentMethod(
                 creditCard: $creditCard,
                 split: is_array($options['split'] ?? null) ? $options['split'] : null,
             ),
@@ -37,15 +105,15 @@ class PagarmePaymentService
     public function createOrderWithPix(
         Payment $payment,
         array $items,
-        array $customer,
-        array $pix,
+        CustomerRequestData $customer,
+        OrderPixData $pix,
         array $options = []
     ): array {
         return $this->createOrder(
             payment: $payment,
             items: $items,
             customer: $customer,
-            paymentMethod: PagarmeOrderRequestData::pixPaymentMethod(
+            paymentMethod: OrderRequestData::pixPaymentMethod(
                 pix: $pix,
                 split: is_array($options['split'] ?? null) ? $options['split'] : null,
             ),
@@ -53,32 +121,32 @@ class PagarmePaymentService
         );
     }
 
-    // criacao de pedidos por metodo de pagamento
-
     public function createOrder(
         Payment $payment,
         array $items,
-        array $customer,
-        array $paymentMethod,
+        CustomerRequestData $customer,
+        OrderPaymentData $paymentMethod,
         array $options = []
     ): array {
-        $requestData = PagarmeOrderRequestData::fromOrderPayload(
+        $metadata = array_merge([
+            'payment_id'  => (string) $payment->id,
+            'schedule_id' => (string) $payment->schedule_id,
+            'client_id'   => (string) $payment->client_id,
+            'provider_id' => (string) $payment->provider_id,
+        ], $options['metadata'] ?? []);
+
+        $requestData = new OrderRequestData(
             code: $this->ensurePaymentCode($payment),
             items: $items,
+            payments: [$paymentMethod],
+            metadata: $metadata,
             customer: $customer,
-            paymentMethod: $paymentMethod,
-            metadata: array_merge([
-                'payment_id'  => (string) $payment->id,
-                'schedule_id' => (string) $payment->schedule_id,
-                'client_id'   => (string) $payment->client_id,
-                'provider_id' => (string) $payment->provider_id,
-            ], $options['metadata'] ?? []),
             customerId: $options['customer_id'] ?? null,
             closed: $options['closed'] ?? true,
             channel: $options['channel'] ?? null,
         );
 
-        $order = PagarmeOrderResponseData::fromArray($this->pagarmeRequest(
+        $order = OrderResponseData::fromArray($this->pagarmeRequest(
             method: 'POST',
             path: '/orders',
             payload: $requestData,
@@ -91,31 +159,11 @@ class PagarmePaymentService
         return $order->toArray();
     }
 
-    // evita criacao duplicada de pedidos
-
-    private function idempotencyKey(Payment $payment): string
-    {
-        return "payment-{$payment->id}-schedule-{$payment->schedule_id}";
-    }
-
-    private function ensurePaymentCode(Payment $payment): string
-    {
-        if (! empty($payment->gateway_code)) {
-            return $payment->gateway_code;
-        }
-
-        $code = 'payment-'.(string) Str::uuid();
-
-        $payment->forceFill(['gateway_code' => $code])->save();
-
-        return $code;
-    }
-
     //
 
     public function applyGatewayResponseToPayment(Payment $payment, array $orderResponse): Payment
     {
-        $order = PagarmeOrderResponseData::fromArray($orderResponse);
+        $order = OrderResponseData::fromArray($orderResponse);
         $newStatus = $order->paymentStatus();
         $failureCode = null;
         $failureMessage = null;
@@ -153,4 +201,186 @@ class PagarmePaymentService
 
         return $payment->fresh();
     }
+
+    //
+
+    public function ensureCustomerPhone(Schedule $schedule, array $options): void
+    {
+        $phone = $this->buildPhonePayload($schedule->client?->user?->phone)
+            ?: $this->buildPhonePayload($options['phone'] ?? null);
+
+        if (! $phone) {
+            throw new \InvalidArgumentException(
+                'Voce precisa cadastrar um numero de celular valido no seu perfil para concluir o pagamento.'
+            );
+        }
+    }
+
+    //
+
+    private function buildOrderItems(Schedule $schedule, float $grossAmount): array
+    {
+        $description = $schedule->customSchedule?->serviceType?->description
+            ?? "Servico {$schedule->id}";
+
+        return [new OrderItemData(
+            code: "schedule-{$schedule->id}",
+            amount: OrderRequestData::amountInCents($grossAmount),
+            quantity: 1,
+            description: $description,
+        )];
+    }
+
+    private function buildCustomer(Schedule $schedule, array $options = []): CustomerRequestData
+    {
+        $client = $schedule->client;
+        $user = $client->user()->first(['id', 'name', 'email', 'phone']);
+        $address = Address::with(['city.state', 'state'])->find($schedule->address_id);
+
+        foreach ([
+            'nome'      => $user?->name,
+            'email'     => $user?->email,
+            'documento' => $client->document,
+        ] as $field => $value) {
+            if ($value === null || $value === '') {
+                throw new \InvalidArgumentException("Cliente precisa ter {$field} para criar pedido no Pagar.me.");
+            }
+        }
+
+        if (! $address) {
+            throw new \InvalidArgumentException('Endereco do agendamento nao encontrado para criar pedido no Pagar.me.');
+        }
+
+        $document = $this->digits($client->document);
+
+        $phone = $this->buildPhonePayload($user->phone)
+            ?: $this->buildPhonePayload($options['phone'] ?? null);
+
+        $state = $address->state?->code ?? $address->city?->state?->code;
+        $city = $address->city?->name;
+        $zipCode = $this->digits($address->zip_code);
+
+        $line1 = implode(', ', array_filter([
+            $address->number ?: 'S/N',
+            $address->address,
+            $address->district,
+        ]));
+
+        foreach ([
+            'documento' => $document,
+            'estado'    => $state,
+            'cidade'    => $city,
+            'cep'       => $zipCode,
+            'endereco'  => $line1,
+            'telefone'  => $phone,
+        ] as $field => $value) {
+            if ($value === null || $value === '' || $value === []) {
+                throw new \InvalidArgumentException("Cliente precisa ter {$field} valido para criar pedido no Pagar.me.");
+            }
+        }
+
+        $customerAddress = new CustomerAddressRequestData(
+            line1: $line1,
+            line2: $address->complement ?: $address->instructions,
+            zipCode: $zipCode,
+            city: $city,
+            state: $state,
+            country: 'BR',
+        );
+
+        $customerPhones = null;
+
+        if ($phone) {
+            $customerPhones = new CustomerPhonesRequestData(
+                mobilePhone: new CustomerPhoneData(
+                    countryCode: $phone['country_code'],
+                    areaCode: $phone['area_code'],
+                    number: $phone['number'],
+                ),
+            );
+        }
+
+        return new CustomerRequestData(
+            name: $user->name,
+            email: $user->email,
+            document: $document,
+            type: strlen($document) === 14 ? 'company' : 'individual',
+            documentType: strlen($document) === 14 ? 'CNPJ' : 'CPF',
+            code: "client-{$client->id}",
+            address: $customerAddress,
+            phones: $customerPhones,
+        );
+    }
+
+    private function buildPhonePayload(?string $phone): ?array
+    {
+        $digits = $this->digits($phone);
+
+        if (strlen($digits) < 10) {
+            return null;
+        }
+
+        if (str_starts_with($digits, '55')) {
+            $digits = substr($digits, 2);
+        }
+
+        return [
+            'country_code' => '55',
+            'area_code'    => substr($digits, 0, 2),
+            'number'       => substr($digits, 2),
+        ];
+    }
+
+    private function buildSplit(Payment $payment, array $options): array
+    {
+        $transfers = PaymentSplit::query()
+            ->where('payment_id', $payment->id)
+            ->get();
+
+        $split = OrderRequestData::splitFromTransfers($transfers);
+
+        $platformFee = (float) ($payment->platform_fee_amount ?? 0);
+
+        if ($platformFee > 0) {
+            $platformRecipientId = config('services.pagarme.platform_recipient_id');
+
+            $split[] = new OrderSplitData(
+                amount: OrderRequestData::amountInCents($platformFee),
+                recipientId: $platformRecipientId,
+                type: 'flat',
+                options: new OrderSplitOptionsData(
+                    chargeProcessingFee: true,
+                    chargeRemainderFee: true,
+                    liable: true,
+                ),
+            );
+        }
+
+        return $split;
+    }
+
+    private function digits(?string $value): string
+    {
+        return preg_replace('/\D+/', '', (string) $value) ?? '';
+    }
+
+    //
+
+    private function idempotencyKey(Payment $payment): string
+    {
+        return "payment-{$payment->id}-schedule-{$payment->schedule_id}";
+    }
+
+    private function ensurePaymentCode(Payment $payment): string
+    {
+        if (! empty($payment->gateway_code)) {
+            return $payment->gateway_code;
+        }
+
+        $code = 'payment-'.(string) Str::uuid();
+
+        $payment->forceFill(['gateway_code' => $code])->save();
+
+        return $code;
+    }
 }

+ 201 - 10
app/Services/Pagarme/PagarmeRecipientService.php

@@ -2,11 +2,19 @@
 
 namespace App\Services\Pagarme;
 
-use App\Data\Pagarme\Request\PagarmeBankAccountUpdateRequestData;
-use App\Data\Pagarme\Request\PagarmeRecipientRequestData\PagarmeRecipientRequestData;
-use App\Data\Pagarme\Response\PagarmeRecipientResponseData\PagarmeRecipientResponseData;
+use App\Data\Pagarme\Request\BankAccountUpdateRequestData;
+use App\Data\Pagarme\Request\RecipientRequestData\RecipientAddressData;
+use App\Data\Pagarme\Request\RecipientRequestData\RecipientAutomaticAnticipationSettingsData;
+use App\Data\Pagarme\Request\RecipientRequestData\RecipientBankAccountData;
+use App\Data\Pagarme\Request\RecipientRequestData\RecipientPhoneData;
+use App\Data\Pagarme\Request\RecipientRequestData\RecipientPhoneNumbersData;
+use App\Data\Pagarme\Request\RecipientRequestData\RecipientRegisterInformationData;
+use App\Data\Pagarme\Request\RecipientRequestData\RecipientRequestData;
+use App\Data\Pagarme\Request\RecipientRequestData\RecipientTransferSettingsData;
+use App\Data\Pagarme\Response\RecipientResponseData\RecipientResponseData;
 use App\Models\Provider;
 use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
+use Carbon\Carbon;
 use Illuminate\Support\Str;
 
 class PagarmeRecipientService
@@ -22,16 +30,66 @@ class PagarmeRecipientService
         $metadata = $data['recipient_metadata'] ?? [];
         $paymentMode = $data['recipient_payment_mode'];
         $recipientCode = $this->ensureRecipientCode($provider);
-        $payload = PagarmeRecipientRequestData::fromPayload($recipientCode, $data);
+
+        $addressParts = $this->extractAddressParts($data);
+
+        $registerInformation = new RecipientRegisterInformationData(
+            name: $data['recipient_name'],
+            email: $data['recipient_email'],
+            document: $this->onlyDigits($data['recipient_document'] ?? null),
+            type: $data['recipient_type'] ?? 'individual',
+            birthdate: $this->formatBirthdate($data['birth_date'] ?? null),
+            monthlyIncome: isset($data['monthly_income']) ? (int) $data['monthly_income'] : 1000,
+            professionalOccupation: $data['professional_occupation'] ?? 'autonomo',
+
+            phoneNumbers: new RecipientPhoneNumbersData(
+                $this->buildRecipientPhone($data['phone'] ?? null),
+            ),
+
+            address: new RecipientAddressData(
+                street: $data['address'],
+                complementary: $addressParts['complementary'],
+                streetNumber: $addressParts['street_number'],
+                neighborhood: $addressParts['neighborhood'],
+                city: $data['city'] ?? null,
+                state: $data['state'] ?? null,
+                zipCode: $this->onlyDigits($data['zip_code'] ?? null),
+                referencePoint: $addressParts['reference_point'],
+            ),
+        );
+
+        $defaultBankAccount = $this->buildRecipientBankAccount(
+            $data['recipient_default_bank_account'],
+        );
+
+        $payload = new RecipientRequestData(
+            code: $recipientCode,
+
+            registerInformation: $registerInformation,
+            defaultBankAccount: $defaultBankAccount,
+
+            transferSettings: new RecipientTransferSettingsData(
+                transferEnabled: false,
+                transferInterval: 'Daily',
+                transferDay: 0,
+            ),
+
+            automaticAnticipationSettings: new RecipientAutomaticAnticipationSettingsData(
+                enabled: false,
+            ),
+        );
+
         $bankAccountData = $payload->defaultBankAccount->toArray();
 
-        $recipientData = PagarmeRecipientResponseData::fromArray($this->pagarmeRequest(
+        $raw = $this->pagarmeRequest(
             method: 'POST',
             path: '/recipients',
             payload: $payload,
             idempotencyKey: $this->idempotencyKey($provider->id),
             errorMessage: 'Erro ao criar recebedor no Pagar.me.',
-        ));
+        );
+
+        $recipientData = RecipientResponseData::fromArray($raw);
 
         $recipientId = $recipientData->requireId();
 
@@ -64,23 +122,156 @@ class PagarmeRecipientService
 
     public function updateDefaultBankAccount(Provider $provider, array $bankAccountData): Provider
     {
-        $payload = PagarmeBankAccountUpdateRequestData::fromArray($bankAccountData);
+        $payload = new BankAccountUpdateRequestData(
+            holderName: $this->normalizeHolderName($bankAccountData['holder_name']),
+            holderType: $bankAccountData['holder_type'],
+            holderDocument: $this->onlyDigits($bankAccountData['holder_document']),
+            bank: $bankAccountData['bank'],
+            branchNumber: $bankAccountData['branch_number'],
+            branchCheckDigit: $bankAccountData['branch_check_digit'] ?? null,
+            accountNumber: $bankAccountData['account_number'],
+            accountCheckDigit: $bankAccountData['account_check_digit'],
+            type: $bankAccountData['type'],
+        );
 
-        $recipientData = PagarmeRecipientResponseData::fromArray($this->pagarmeRequest(
+        $raw = $this->pagarmeRequest(
             method: 'PATCH',
             path: "/recipients/{$provider->recipient_id}/default-bank-account",
             payload: $payload,
             idempotencyKey: $this->idempotencyKey($provider->id, 'default-bank-account-'.sha1(json_encode($payload->toArray()))),
             errorMessage: 'Erro ao atualizar conta bancaria do recebedor no Pagar.me.',
-        ));
+        );
+
+        $recipientData = RecipientResponseData::fromArray($raw);
 
         $provider->forceFill([
-            'recipient_default_bank_account' => $recipientData->defaultBankAccount()?->toArray() ?: $payload->toArray()['bank_account'],
+            'recipient_default_bank_account' => $recipientData->defaultBankAccount?->toArray() ?: $payload->toArray()['bank_account'],
         ])->save();
 
         return $provider->fresh();
     }
 
+    //
+
+    private function buildRecipientBankAccount(array $data): RecipientBankAccountData
+    {
+        return new RecipientBankAccountData(
+            holderName: $this->normalizeHolderName($data['holder_name']),
+            holderType: $data['holder_type'],
+            holderDocument: $this->onlyDigits($data['holder_document']),
+            bank: $data['bank'],
+            branchNumber: $data['branch_number'],
+            branchCheckDigit: $data['branch_check_digit'] ?? null,
+            accountNumber: $data['account_number'],
+            accountCheckDigit: $data['account_check_digit'],
+            type: $data['type'],
+        );
+    }
+
+    private function buildRecipientPhone(?string $phone): RecipientPhoneData
+    {
+        $digits = $this->onlyDigits($phone);
+
+        if (strlen($digits) < 10) {
+            return new RecipientPhoneData(
+                ddd: '11',
+                number: '999999999',
+                type: 'mobile',
+            );
+        }
+
+        if (str_starts_with($digits, '55')) {
+            $digits = substr($digits, 2);
+        }
+
+        return new RecipientPhoneData(
+            ddd: substr($digits, 0, 2),
+            number: substr($digits, 2),
+            type: 'mobile',
+        );
+    }
+
+    private function extractAddressParts(array $data): array
+    {
+        $addressLine = trim((string) ($data['address'] ?? ''));
+        $segments = array_map('trim', explode(',', $addressLine));
+        $streetSegment = $segments[0] ?? '';
+
+        if (($data['number'] ?? null) === null) {
+            preg_match('/^(\d+)/', $streetSegment, $matches);
+        }
+
+        return [
+            'street_number'   => (string) ($data['number'] ?? $matches[1] ?? 'S/N'),
+            'neighborhood'    => (string) ($data['district'] ?? $segments[1] ?? 'N/A'),
+            'reference_point' => (string) ($data['reference_point'] ?? 'N/A'),
+            'complementary'   => (string) ($data['complement'] ?? 'N/A'),
+        ];
+    }
+
+    private function formatBirthdate(mixed $birthdate): ?string
+    {
+        if ($birthdate === null || $birthdate === '') {
+            return null;
+        }
+
+        if ($birthdate instanceof \DateTimeInterface) {
+            return Carbon::instance($birthdate)->format('d/m/Y');
+        }
+
+        $birthdate = trim((string) $birthdate);
+
+        if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $birthdate) === 1) {
+            return $birthdate;
+        }
+
+        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $birthdate) === 1) {
+            return Carbon::createFromFormat('Y-m-d', $birthdate)->format('d/m/Y');
+        }
+
+        return Carbon::parse($birthdate)->format('d/m/Y');
+    }
+
+    private function normalizeHolderName(string $holderName): string
+    {
+        $holderName = trim(preg_replace('/\s+/', ' ', $holderName) ?? '');
+
+        if (Str::length($holderName) < 30) {
+            return $holderName;
+        }
+
+        $parts = explode(' ', $holderName);
+
+        if (count($parts) >= 3) {
+            $firstName = array_shift($parts);
+            $lastName = array_pop($parts);
+
+            $initials = array_map(
+                static fn (string $part): string => Str::upper(Str::substr($part, 0, 1)),
+                $parts
+            );
+
+            $abbreviated = trim($firstName.' '.implode(' ', $initials).' '.$lastName);
+
+            if (Str::length($abbreviated) < 30) {
+                return $abbreviated;
+            }
+
+            $firstAndLast = trim($firstName.' '.$lastName);
+
+            if (Str::length($firstAndLast) < 30) {
+                return $firstAndLast;
+            }
+        }
+
+        return Str::limit($holderName, 29, '');
+    }
+
+    private function onlyDigits(?string $value): string
+    {
+        return preg_replace('/\D+/', '', (string) $value) ?? '';
+    }
+
     // evita criacao duplica de recipient
 
     private function idempotencyKey(int $providerId, string $suffix = 'recipient'): string

+ 40 - 52
app/Services/Pagarme/PagarmeTransferService.php

@@ -2,7 +2,8 @@
 
 namespace App\Services\Pagarme;
 
-use App\Data\Pagarme\Request\PagarmeTransferRequestData;
+use App\Data\Pagarme\Request\TransferRequestData;
+use App\Data\Pagarme\Response\TransferResponseData;
 use App\Models\Provider;
 use App\Models\ProviderWithdrawal;
 use App\Services\Pagarme\Concerns\SendsPagarmeRequests;
@@ -12,7 +13,7 @@ class PagarmeTransferService
 {
     use SendsPagarmeRequests;
 
-    public function createTransfer(int $amountInCents, string $recipientId, string $idempotencyKey): array
+    public function createTransfer(int $amountInCents, string $recipientId, string $idempotencyKey): TransferResponseData
     {
         if ($this->shouldMockTransferRequest()) {
             return $this->mockTransferResponse(
@@ -22,31 +23,31 @@ class PagarmeTransferService
             );
         }
 
-        return $this->pagarmeRequest(
+        return TransferResponseData::fromArray($this->pagarmeRequest(
             method: 'POST',
             path: '/transfers',
-            payload: new PagarmeTransferRequestData(
+            payload: new TransferRequestData(
                 amount: $amountInCents,
                 recipientId: $recipientId,
             ),
             idempotencyKey: $idempotencyKey,
             errorMessage: 'Erro ao criar transferencia (saque) no Pagar.me.',
-        );
+        ));
     }
 
-    public function getTransfer(string $transferId): array
+    public function getTransfer(string $transferId): TransferResponseData
     {
         if ($this->shouldMockTransferRequest()) {
             return $this->mockTransferLookupResponse($transferId);
         }
 
-        return $this->pagarmeRequest(
+        return TransferResponseData::fromArray($this->pagarmeRequest(
             method: 'GET',
             path: "/transfers/{$transferId}",
             payload: [],
             idempotencyKey: "get-transfer-{$transferId}",
             errorMessage: 'Erro ao consultar transferencia no Pagar.me.',
-        );
+        ));
     }
 
     //
@@ -56,71 +57,58 @@ class PagarmeTransferService
         return app()->environment('local', 'development');
     }
 
-    private function mockTransferResponse(int $amountInCents, string $recipientId, string $idempotencyKey): array
+    private function mockTransferResponse(int $amountInCents, string $recipientId, string $idempotencyKey): TransferResponseData
     {
-        $provider = Provider::query()
-            ->where('recipient_id', $recipientId)
-            ->first();
-
+        $provider = Provider::query()->where('recipient_id', $recipientId)->first();
         $createdAt = Carbon::now();
 
-        return [
-            'id'                     => $this->mockTransferId($idempotencyKey),
-            'amount'                 => $amountInCents,
-            'type'                   => 'credito_em_conta',
-            'status'                 => 'pending_transfer',
-            'fee'                    => 0,
-            'funding_date'           => null,
-            'funding_estimated_date' => $createdAt->copy()->addWeekday()->toISOString(),
-            'transaction_id'         => null,
-            'bank_account'           => $provider?->recipient_default_bank_account,
-            'date_created'           => $createdAt->toISOString(),
-            'created_at'             => $createdAt->toISOString(),
-
-            'metadata' => [
+        return new TransferResponseData(
+            id: $this->mockTransferId($idempotencyKey),
+            amount: $amountInCents,
+            type: 'credito_em_conta',
+            status: 'pending_transfer',
+            fee: 0,
+            fundingDate: null,
+            fundingEstimatedDate: $createdAt->copy()->addWeekday()->toISOString(),
+            bankAccount: $provider?->recipient_default_bank_account,
+            bankResponse: null,
+            createdAt: $createdAt->toISOString(),
+            metadata: [
                 'mocked'          => true,
                 'environment'     => app()->environment(),
                 'recipient_id'    => $recipientId,
                 'idempotency_key' => $idempotencyKey,
                 'provider_id'     => $provider?->id,
             ],
-
-            'bank_response' => null,
-        ];
+        );
     }
 
-    private function mockTransferLookupResponse(string $transferId): array
+    private function mockTransferLookupResponse(string $transferId): TransferResponseData
     {
-        $withdrawal = ProviderWithdrawal::query()
-            ->where('transfer_id', $transferId)
-            ->first();
+        $withdrawal = ProviderWithdrawal::query()->where('transfer_id', $transferId)->first();
 
         if ($withdrawal?->gateway_payload) {
-            return $withdrawal->gateway_payload;
+            return TransferResponseData::fromArray($withdrawal->gateway_payload);
         }
 
         $createdAt = Carbon::now();
 
-        return [
-            'id'                     => $transferId,
-            'amount'                 => $withdrawal ? (int) round((float) $withdrawal->gross_amount * 100) : 0,
-            'type'                   => $withdrawal?->type ?? 'credito_em_conta',
-            'status'                 => $withdrawal?->status?->value ?? 'pending_transfer',
-            'fee'                    => $withdrawal ? (int) round((float) $withdrawal->gateway_fee_amount * 100) : 0,
-            'funding_date'           => $withdrawal?->completed_at?->toISOString(),
-            'funding_estimated_date' => $createdAt->copy()->addWeekday()->toISOString(),
-            'transaction_id'         => null,
-            'bank_account'           => $withdrawal?->bank_account,
-            'date_created'           => $withdrawal?->created_at?->toISOString() ?? $createdAt->toISOString(),
-            'created_at'             => $withdrawal?->created_at?->toISOString() ?? $createdAt->toISOString(),
-
-            'metadata' => $withdrawal?->metadata ?? [
+        return new TransferResponseData(
+            id: $transferId,
+            amount: $withdrawal ? (int) round((float) $withdrawal->gross_amount * 100) : 0,
+            type: $withdrawal?->type ?? 'credito_em_conta',
+            status: $withdrawal?->status?->value ?? 'pending_transfer',
+            fee: $withdrawal ? (int) round((float) $withdrawal->gateway_fee_amount * 100) : 0,
+            fundingDate: $withdrawal?->completed_at?->toISOString(),
+            fundingEstimatedDate: $createdAt->copy()->addWeekday()->toISOString(),
+            bankAccount: $withdrawal?->bank_account,
+            bankResponse: $withdrawal?->bank_response,
+            createdAt: $withdrawal?->created_at?->toISOString() ?? $createdAt->toISOString(),
+            metadata: $withdrawal?->metadata ?? [
                 'mocked'      => true,
                 'environment' => app()->environment(),
             ],
-
-            'bank_response' => $withdrawal?->bank_response,
-        ];
+        );
     }
 
     private function mockTransferId(string $idempotencyKey): string

+ 17 - 208
app/Services/PaymentService.php

@@ -2,10 +2,8 @@
 
 namespace App\Services;
 
-use App\Data\Pagarme\Request\PagarmeOrderRequestData\PagarmeOrderRequestData;
 use App\Enums\PaymentSplitStatusEnum;
 use App\Enums\PaymentStatusEnum;
-use App\Models\Address;
 use App\Models\ClientPaymentMethod;
 use App\Models\Payment;
 use App\Models\PaymentSplit;
@@ -125,6 +123,7 @@ class PaymentService
         }
 
         $clientPaymentMethod = null;
+        $cardId = null;
 
         if ($paymentMethod === 'credit_card') {
             if (! $clientPaymentMethodId && empty($options['card_id'])) {
@@ -143,10 +142,9 @@ class PaymentService
                 }
             }
 
-            if (
-                empty($clientPaymentMethod?->gateway_card_id)
-                && empty($options['card_id'])
-            ) {
+            $cardId = $options['card_id'] ?? $clientPaymentMethod?->gateway_card_id ?? null;
+
+            if (empty($cardId)) {
                 throw new \InvalidArgumentException('Cartao de pagamento invalido ou sem gateway_card_id do Pagar.me.');
             }
         }
@@ -154,11 +152,6 @@ class PaymentService
         $serviceAmount = (float) $schedule->total_amount;
         $platformFee = round($serviceAmount * 0.11, 2);
         $grossAmount = round($serviceAmount + $platformFee, 2);
-        $items = $this->buildOrderItems($schedule, $grossAmount);
-
-        $this->ensureCustomerPhoneForPayment($schedule, $options);
-
-        $customer = $this->buildCustomerPayload(schedule: $schedule, options: $options, requirePhone: true);
 
         $platformRecipientId = config('services.pagarme.platform_recipient_id');
 
@@ -170,7 +163,7 @@ class PaymentService
             'schedule_id'              => $schedule->id,
             'client_id'                => $schedule->client_id,
             'provider_id'              => $schedule->provider_id,
-            'client_payment_method_id' => $paymentMethod === 'credit_card' ? $clientPaymentMethod->id : null,
+            'client_payment_method_id' => $paymentMethod === 'credit_card' ? ($clientPaymentMethod?->id ?? null) : null,
             'gateway_provider'         => 'pagarme',
             'gateway_code'             => 'payment-'.(string) Str::uuid(),
             'payment_method'           => $paymentMethod,
@@ -189,7 +182,7 @@ class PaymentService
             ],
         ]);
 
-        $transfer = PaymentSplit::create([
+        PaymentSplit::create([
             'payment_id'                        => $payment->id,
             'provider_id'                       => $schedule->provider_id,
             'gateway_provider'                  => 'pagarme',
@@ -205,60 +198,16 @@ class PaymentService
             ],
         ]);
 
-        $split = PagarmeOrderRequestData::splitFromTransfers(collect([$transfer]));
-
-        if ($platformFee > 0) {
-            $split[] = [
-                'amount'       => PagarmeOrderRequestData::amountInCents($platformFee),
-                'recipient_id' => $platformRecipientId,
-                'type'         => 'flat',
-
-                'options' => [
-                    'charge_processing_fee' => true,
-                    'charge_remainder_fee'  => true,
-                    'liable'                => true,
-                ],
-            ];
-        }
-
-        $pixOptions = config('services.pagarme.pix_disable_split')
-            ? []
-            : ['split' => $split];
+        $this->pagarmePaymentService->ensureCustomerPhone($schedule, $options);
 
         try {
-            $creditCardReference = $paymentMethod === 'credit_card'
-                ? $this->resolveCreditCardReference($clientPaymentMethod, $options)
-                : [];
-
-            $orderResponse = $paymentMethod === 'credit_card'
-                ? $this->pagarmePaymentService->createOrderWithCreditCard(
-                    payment: $payment,
-                    items: $items,
-                    customer: $customer,
-                    creditCard: [
-                        'installments'         => 1,
-                        'statement_descriptor' => Str::limit((string) config('app.name', 'SOFTPAR'), 13, ''),
-                        'operation_type'       => 'auth_and_capture',
-                    ] + $creditCardReference,
-                    options: [
-                        'split' => $split,
-                    ],
-                )
-                : $this->pagarmePaymentService->createOrderWithPix(
-                    payment: $payment,
-                    items: $items,
-                    customer: $customer,
-                    pix: [
-                        'expires_in'             => '1800',
-                        'additional_information' => [
-                            [
-                                'name'  => 'Agendamento',
-                                'value' => (string) $schedule->id,
-                            ],
-                        ],
-                    ],
-                    options: $pixOptions,
-                );
+            $orderResponse = $this->pagarmePaymentService->processPayment(
+                payment: $payment,
+                schedule: $schedule,
+                paymentMethod: $paymentMethod,
+                cardId: $cardId,
+                options: $options,
+            );
         } catch (\Throwable $e) {
             $payment->forceFill([
                 'status'          => PaymentStatusEnum::FAILED,
@@ -266,7 +215,9 @@ class PaymentService
                 'failure_message' => $e->getMessage(),
             ])->save();
 
-            $transfer->update(['status' => PaymentSplitStatusEnum::FAILED]);
+            PaymentSplit::query()
+                ->where('payment_id', $payment->id)
+                ->update(['status' => PaymentSplitStatusEnum::FAILED]);
 
             throw $e;
         }
@@ -280,135 +231,6 @@ class PaymentService
 
     //
 
-    private function buildOrderItems(Schedule $schedule, float $grossAmount): array
-    {
-        $description = $schedule->customSchedule?->serviceType?->description
-            ?? "Servico {$schedule->id}";
-
-        return [[
-            'amount'      => PagarmeOrderRequestData::amountInCents($grossAmount),
-            'description' => $description,
-            'quantity'    => 1,
-            'code'        => "schedule-{$schedule->id}",
-        ]];
-    }
-
-    private function buildCustomerPayload(
-        Schedule $schedule,
-        array $options = [],
-        bool $requirePhone = true
-    ): array {
-        $client = $schedule->client;
-        $user = $client->user()->first(['id', 'name', 'email', 'phone']);
-        $address = Address::with(['city.state', 'state'])->find($schedule->address_id);
-
-        foreach ([
-            'nome'      => $user?->name,
-            'email'     => $user?->email,
-            'documento' => $client->document,
-        ] as $field => $value) {
-            if ($value === null || $value === '') {
-                throw new \InvalidArgumentException("Cliente precisa ter {$field} para criar pedido no Pagar.me.");
-            }
-        }
-
-        if (! $address) {
-            throw new \InvalidArgumentException('Endereco do agendamento nao encontrado para criar pedido no Pagar.me.');
-        }
-
-        $document = $this->digits($client->document);
-
-        $phone = $this->buildPhonePayload($user->phone)
-            ?: $this->buildPhonePayload($options['phone'] ?? null);
-
-        $state = $address->state?->code ?? $address->city?->state?->code;
-        $city = $address->city?->name;
-        $zipCode = $this->digits($address->zip_code);
-
-        $line1 = implode(', ', array_filter([
-            $address->number ?: 'S/N',
-            $address->address,
-            $address->district,
-        ]));
-
-        $requiredFields = [
-            'documento' => $document,
-            'estado'    => $state,
-            'cidade'    => $city,
-            'cep'       => $zipCode,
-            'endereco'  => $line1,
-        ];
-
-        if ($requirePhone) {
-            $requiredFields['telefone'] = $phone;
-        }
-
-        foreach ($requiredFields as $field => $value) {
-            if ($value === null || $value === '' || $value === []) {
-                throw new \InvalidArgumentException("Cliente precisa ter {$field} valido para criar pedido no Pagar.me.");
-            }
-        }
-
-        return [
-            'name'          => $user->name,
-            'email'         => $user->email,
-            'code'          => "client-{$client->id}",
-            'document'      => $document,
-            'document_type' => strlen($document) === 14 ? 'CNPJ' : 'CPF',
-            'type'          => strlen($document) === 14 ? 'company' : 'individual',
-
-            'address' => [
-                'country'  => 'BR',
-                'state'    => $state,
-                'city'     => $city,
-                'zip_code' => $zipCode,
-                'line_1'   => $line1,
-                'line_2'   => $address->complement ?: $address->instructions,
-            ],
-
-            'phones' => $phone ? ['mobile_phone' => $phone] : null,
-        ];
-    }
-
-    private function buildPhonePayload(?string $phone): ?array
-    {
-        $digits = $this->digits($phone);
-
-        if (strlen($digits) < 10) {
-            return null;
-        }
-
-        if (str_starts_with($digits, '55')) {
-            $digits = substr($digits, 2);
-        }
-
-        return [
-            'country_code' => '55',
-            'area_code'    => substr($digits, 0, 2),
-            'number'       => substr($digits, 2),
-        ];
-    }
-
-    private function ensureCustomerPhoneForPayment(Schedule $schedule, array $options = []): void
-    {
-        $userPhone = $schedule->client?->user?->phone;
-        $phone = $this->buildPhonePayload($userPhone)
-            ?: $this->buildPhonePayload($options['phone'] ?? null);
-
-        if ($phone) {
-            return;
-        }
-
-        throw new \InvalidArgumentException(
-            'Voce precisa cadastrar um numero de celular valido no seu perfil para concluir o pagamento.'
-        );
-    }
-
-    private function digits(?string $value): string
-    {
-        return preg_replace('/\D+/', '', (string) $value) ?? '';
-    }
-
     private function isIncompleteGatewayPayment(Payment $payment): bool
     {
         return $payment->status === PaymentStatusEnum::PENDING
@@ -417,19 +239,6 @@ class PaymentService
             && empty($payment->gateway_payload);
     }
 
-    private function resolveCreditCardReference(?ClientPaymentMethod $clientPaymentMethod, array $options): array
-    {
-        if (! empty($options['card_id'])) {
-            return ['card_id' => $options['card_id']];
-        }
-
-        if (! empty($clientPaymentMethod?->gateway_card_id)) {
-            return ['card_id' => $clientPaymentMethod->gateway_card_id];
-        }
-
-        throw new \InvalidArgumentException('Cartao de pagamento precisa ter gateway_card_id do Pagar.me.');
-    }
-
     public function syncScheduleStatusAfterPayment(Schedule $schedule, Payment $payment): void
     {
         if ($payment->status !== PaymentStatusEnum::PAID || $schedule->status === 'paid') {

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä