Skip to content
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ MultiPayment permite gerenciar pagamentos de diversos gateways de pagamento. Atu
- [Utilizando](#utilizando)
- [MultiPayment](#multipayment)
- [InvoiceBuilder](#invoicebuilder)
- [Pix Automático](#pix-automático)
- [CustomerBuilder](#customerbuilder)
- [getInvoice](#getinvoice)
- [charge](#charge)
Expand Down Expand Up @@ -90,6 +91,61 @@ $invoice = $invoiceBuilder->setPaymentMethod('payment_method')
->create();
```
Confira `src/MultiPayment/Builders/InvoiceBuilder.php` para saber quais métodos estão disponíveis.

#### Pix Automático

O Pix Automático está disponível no gateway Iugu e é configurado como parte da fatura:

```php
use Potelo\MultiPayment\Models\AutomaticPix;

$invoice = (new \Potelo\MultiPayment\MultiPayment('iugu'))
->newInvoice()
->addAvailablePaymentMethod('pix')
->addCustomer('Nome', 'email@example.com', '01234567891')
->addItem('Mensalidade', 10000, 1)
->addAutomaticPix(
AutomaticPix::AUTHORIZATION_TYPE_QR_CODE_WITH_PAYMENT,
AutomaticPix::FREQUENCY_MONTHLY,
'2026-08-01',
'contrato-123',
'2027-08-01',
AutomaticPix::RETRY_POLICY_ALLOWED,
)
->addAutomaticPixCharge('Mensalidade do plano')
->create();
```

As demais operações também utilizam os modelos do MultiPayment, enquanto os nomes específicos da Iugu são tratados internamente pelo gateway:

```php
$multiPayment = new \Potelo\MultiPayment\MultiPayment('iugu');

$multiPayment->rescheduleAutomaticPixPayment($invoiceId);
$multiPayment->cancelAutomaticPixRecurrence($recurrenceId);
$multiPayment->cancelAutomaticPixScheduledPayment($invoice->automaticPixCharge);
$multiPayment->getAutomaticPixCancellation($recurrenceId, $cancellationId);
$multiPayment->listAutomaticPixCancellations($recurrenceId, page: 1, limit: 100);
```

##### Testes com a sandbox da Iugu

A suíte `Integration` reúne todos os testes que acessam a sandbox da Iugu. Cada
teste cria durante a execução os clientes, faturas e cartões de que precisa; não
há dependência de IDs ou outros dados previamente existentes no gateway.

```bash
IUGU_ID=seu_account_id \
IUGU_APIKEY=seu_api_token \
./vendor/bin/phpunit -c phpunit.xml.dist --testsuite Integration
```

Atualmente, a sandbox responde que Pix Automático não está disponível no modo de
teste. Os cenários que dependem desse recurso estão identificados com o grupo
`iugu-sandbox-limitation` e usam um `skip` explícito com a razão da limitação. Os
testes permanecem junto das classes responsáveis pelo builder e pela facade para
que possam ser reativados quando o ambiente passar a suportar o fluxo.

#### CustomerBuilder
```php
$multiPayment = new \Potelo\MultiPayment\MultiPayment('iugu');
Expand Down
5 changes: 4 additions & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Integration">
<directory suffix="Test.php">./tests/Integration</directory>
</testsuite>
</testsuites>
<php>
<env name="APP_ENV" value="testing"/>
Expand All @@ -30,4 +33,4 @@
<env name="IUGU_ID" value="" />
<env name="IUGU_APIKEY" value="" />
</php>
</phpunit>
</phpunit>
67 changes: 67 additions & 0 deletions src/Builders/InvoiceBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use Potelo\MultiPayment\Models\Customer;
use Potelo\MultiPayment\Models\CreditCard;
use Potelo\MultiPayment\Models\InvoiceItem;
use Potelo\MultiPayment\Models\AutomaticPix;
use Potelo\MultiPayment\Models\AutomaticPixCharge;
use Potelo\MultiPayment\Contracts\GatewayContract;

/**
Expand Down Expand Up @@ -87,6 +89,71 @@ public function setExpiresAt($expiresAt): InvoiceBuilder
return $this;
}

/**
* Set an Automatic Pix recurrence on the invoice.
*/
public function setAutomaticPix(AutomaticPix $automaticPix): InvoiceBuilder
{
$this->model->automaticPix = $automaticPix;

return $this;
}

/**
* Set the charge associated with this Automatic Pix invoice.
*/
public function setAutomaticPixCharge(AutomaticPixCharge $charge): InvoiceBuilder
{
$this->model->automaticPixCharge = $charge;

return $this;
}

/**
* Add data for the charge associated with this Automatic Pix invoice.
*/
public function addAutomaticPixCharge(
?string $description = null,
?string $id = null,
?string $endToEndId = null
): InvoiceBuilder {
$charge = new AutomaticPixCharge();
$charge->description = $description;
$charge->id = $id;
$charge->endToEndId = $endToEndId;
$this->model->automaticPixCharge = $charge;

return $this;
}

/**
* Add Automatic Pix recurrence data to the invoice.
*
* @param Carbon|string $startsAt
* @param Carbon|string|null $endsAt
*/
public function addAutomaticPix(
string $authorizationType,
string $frequency,
Carbon|string $startsAt,
string $contractReference,
Carbon|string|null $endsAt = null,
string $retryPolicy = AutomaticPix::RETRY_POLICY_NOT_ALLOWED,
?string $id = null
): InvoiceBuilder {
$automaticPix = new AutomaticPix();
$automaticPix->authorizationType = $authorizationType;
$automaticPix->frequency = $frequency;
$automaticPix->startsAt = $startsAt instanceof Carbon ? $startsAt : Carbon::parse($startsAt);
$automaticPix->contractReference = $contractReference;
$automaticPix->endsAt = is_string($endsAt) ? Carbon::parse($endsAt) : $endsAt;
$automaticPix->retryPolicy = $retryPolicy;
$automaticPix->id = $id;
$this->model->automaticPix = $automaticPix;

return $this;
}

/**
* Set the invoice items
*
Expand Down
49 changes: 49 additions & 0 deletions src/Contracts/AutomaticPixContract.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Potelo\MultiPayment\Contracts;

use Potelo\MultiPayment\Models\Invoice;
use Potelo\MultiPayment\Models\AutomaticPix;
use Potelo\MultiPayment\Models\AutomaticPixCharge;
use Potelo\MultiPayment\Models\AutomaticPixCancellation;
use Potelo\MultiPayment\Exceptions\GatewayException;
use Potelo\MultiPayment\Exceptions\GatewayNotAvailableException;

interface AutomaticPixContract
{
/**
* @throws GatewayException|GatewayNotAvailableException
*/
public function rescheduleAutomaticPixPayment(Invoice $invoice): Invoice;

/**
* @throws GatewayException|GatewayNotAvailableException
*/
public function cancelAutomaticPixScheduledPayment(
AutomaticPixCharge $charge
): AutomaticPixCancellation;

/**
* @throws GatewayException|GatewayNotAvailableException
*/
public function cancelAutomaticPixRecurrence(
AutomaticPix $automaticPix
): AutomaticPixCancellation;

/**
* @throws GatewayException|GatewayNotAvailableException
*/
public function getAutomaticPixCancellation(
AutomaticPixCancellation $cancellation
): AutomaticPixCancellation;

/**
* @return AutomaticPixCancellation[]
* @throws GatewayException|GatewayNotAvailableException
*/
public function listAutomaticPixCancellations(
AutomaticPix $automaticPix,
int $page = 1,
int $limit = 100
): array;
}
2 changes: 1 addition & 1 deletion src/Contracts/GatewayContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Potelo\MultiPayment\Contracts;

interface GatewayContract extends CreditCardContract, CustomerContract, InvoiceContract
interface GatewayContract extends CreditCardContract, CustomerContract, InvoiceContract, AutomaticPixContract
{
public function __toString();
}
9 changes: 9 additions & 0 deletions src/Contracts/InvoiceContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,13 @@ public function chargeInvoiceWithCreditCard(Invoice $invoice): Invoice;
* @throws \Potelo\MultiPayment\Exceptions\GatewayException
*/
public function duplicateInvoice(Invoice $invoice, Carbon $expiresAt, array $gatewayOptions = []): Invoice;

/**
* Cancel an invoice.
*
* @param Invoice $invoice
* @return Invoice
* @throws GatewayException|GatewayNotAvailableException
*/
public function cancelInvoice(Invoice $invoice): Invoice;
}
7 changes: 7 additions & 0 deletions src/Exceptions/GatewayException.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ private function flattenErrors(array $array, array &$messages, string $prefix =
// Constrói a chave completa para o item atual
$newKey = $prefix ? "{$prefix}.{$key}" : $key;

// Normaliza objetos (ex.: stdClass aninhado vindo da Iugu) para array
// antes de prosseguir, evitando "Object of class stdClass could not be
// converted to string" ao tentar interpolar o valor.
if (is_object($value)) {
$value = (array) $value;
}

if (is_array($value) && !empty($value)) {
// Se o valor for um array não vazio, continua a recursão
$this->flattenErrors($value, $messages, $newKey);
Expand Down
6 changes: 6 additions & 0 deletions src/Facades/MultiPayment.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
* @method static \Potelo\MultiPayment\MultiPayment setGateway($gateway)
* @method static Invoice chargeInvoiceWithCreditCard($invoice, ?string $creditCardToken = null, ?string $creditCardId = null)
* @method static \Potelo\MultiPayment\Models\Customer setDefaultCard(string $customerId, string $creditCardId)
* @method static Invoice cancelInvoice(Invoice|string $invoice)
* @method static Invoice rescheduleAutomaticPixPayment(Invoice|string $invoice)
* @method static \Potelo\MultiPayment\Models\AutomaticPixCancellation cancelAutomaticPixRecurrence(\Potelo\MultiPayment\Models\AutomaticPix|string $automaticPix)
* @method static \Potelo\MultiPayment\Models\AutomaticPixCancellation cancelAutomaticPixScheduledPayment(\Potelo\MultiPayment\Models\AutomaticPixCharge|string $charge, ?string $endToEndId = null)
* @method static \Potelo\MultiPayment\Models\AutomaticPixCancellation getAutomaticPixCancellation(\Potelo\MultiPayment\Models\AutomaticPixCancellation|string $cancellation, ?string $cancellationId = null)
* @method static \Potelo\MultiPayment\Models\AutomaticPixCancellation[] listAutomaticPixCancellations(\Potelo\MultiPayment\Models\AutomaticPix|string $automaticPix, int $page = 1, int $limit = 100)
*/
class MultiPayment extends Facade
{
Expand Down
Loading
Loading