Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/Contracts/AutomaticPixContract.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Potelo\MultiPayment\Contracts;

use Potelo\MultiPayment\Exceptions\GatewayException;
use Potelo\MultiPayment\Exceptions\GatewayNotAvailableException;

/**
* Operações de Pix Automático (recorrência do Bacen).
*
* Por ser específico de gateways que suportam o Pix Automático, fica fora do
* GatewayContract para não obrigar implementações que não suportam recorrência.
*/
interface AutomaticPixContract
{
/**
* Solicita o cancelamento de uma recorrência de Pix Automático.
*
* @param string $recurrenceId UUID da recorrência (receiver_recurrence_id).
* @return object Resposta do gateway.
* @throws GatewayException|GatewayNotAvailableException
*/
public function cancelAutomaticPixRecurrence(string $recurrenceId): object;
}
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
1 change: 1 addition & 0 deletions src/Facades/MultiPayment.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* @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 object cancelAutomaticPixRecurrence(string $recurrenceId)
*/
class MultiPayment extends Facade
{
Expand Down
34 changes: 33 additions & 1 deletion src/Gateways/IuguGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Iugu;
use Iugu_Customer;
use Carbon\Carbon;
use Iugu_APIRequest;
use Iugu_PaymentToken;
use Iugu_PaymentMethod;
use IuguObjectNotFound;
Expand All @@ -19,10 +20,11 @@
use Potelo\MultiPayment\Contracts\GatewayContract;
use Potelo\MultiPayment\Exceptions\GatewayException;
use Potelo\MultiPayment\Exceptions\ChargingException;
use Potelo\MultiPayment\Contracts\AutomaticPixContract;
use Potelo\MultiPayment\Exceptions\GatewayNotAvailableException;
use Potelo\MultiPayment\Exceptions\ModelAttributeValidationException;

class IuguGateway implements GatewayContract
class IuguGateway implements GatewayContract, AutomaticPixContract
{
private const STATUS_PENDING = 'pending';
private const STATUS_PAID = 'paid';
Expand Down Expand Up @@ -377,6 +379,36 @@ public function duplicateInvoice(Invoice $invoice, Carbon $expiresAt, array $gat
return $this->parseInvoice($iuguInvoice);
}

/**
* @inheritDoc
*
* Endpoint: PUT /automatic_pix/receiver_recurrences/{id}/cancel
*/
public function cancelAutomaticPixRecurrence(string $recurrenceId): object
{
$url = Iugu::getBaseURI() . '/automatic_pix/receiver_recurrences/' . $recurrenceId . '/cancel';

try {
$response = (new Iugu_APIRequest())->request('PUT', $url);
} catch (\IuguRequestException | IuguObjectNotFound $e) {
if (str_contains($e->getMessage(), '502 Bad Gateway')) {
throw new GatewayNotAvailableException($e->getMessage());
} else {
throw new GatewayException($e->getMessage());
}
} catch (\IuguAuthenticationException $e) {
throw new GatewayNotAvailableException($e->getMessage());
} catch (\Exception $e) {
throw new GatewayException("Error cancelling automatic pix recurrence: {$e->getMessage()}");
}

if (!empty($response->errors)) {
throw new GatewayException('Error cancelling automatic pix recurrence', (array) $response->errors);
}

return $response;
}

/**
* @inheritDoc
*/
Expand Down
19 changes: 19 additions & 0 deletions src/MultiPayment.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Potelo\MultiPayment\Builders\CustomerBuilder;
use Potelo\MultiPayment\Builders\CreditCardBuilder;
use Potelo\MultiPayment\Exceptions\GatewayException;
use Potelo\MultiPayment\Contracts\AutomaticPixContract;
use Potelo\MultiPayment\Helpers\ConfigurationHelper;
use Potelo\MultiPayment\Exceptions\GatewayNotAvailableException;
use Potelo\MultiPayment\Exceptions\ModelAttributeValidationException;
Expand Down Expand Up @@ -267,4 +268,22 @@ public function setDefaultCard(string $customerId, string $creditCardId): Custom
return $customer->setDefaultCard($creditCardId);
}

/**
* Cancela uma recorrência de Pix Automático no gateway.
*
* @param string $recurrenceId UUID da recorrência (receiver_recurrence_id).
* @return object
* @throws MultiPaymentException
* @throws GatewayException
* @throws GatewayNotAvailableException
*/
public function cancelAutomaticPixRecurrence(string $recurrenceId): object
{
if (!$this->gateway instanceof AutomaticPixContract) {
throw new MultiPaymentException('The selected gateway does not support automatic pix.');
}

return $this->gateway->cancelAutomaticPixRecurrence($recurrenceId);
}

}
Loading