Skip to content

PHPAY-97: Asaas — assinaturas completas (listar, buscar, atualizar, remover, carnê e nota fiscal) - #98

Merged
mariolucasdev merged 4 commits into
developfrom
feat/phpay-97
Sep 21, 2026
Merged

mariolucasdev merged 4 commits into
developfrom
feat/phpay-97

Conversation

@mariolucasdev

Copy link
Copy Markdown
Collaborator

Closes #97.

O que muda

As assinaturas do Asaas deixam de ser parciais (✍️) no roadmap. O recurso Subscription tinha só create() e agora cobre os 14 endpoints de assinatura da API do Asaas, conferidos na especificação OpenAPI oficial:

Operação Método Endpoint
Listar getAll() GET /v3/subscriptions
Buscar find() GET /v3/subscriptions/{id}
Atualizar update() PUT /v3/subscriptions/{id}
Pausar / reativar deactivate() / reactivate($id, $nextDueDate) PUT /v3/subscriptions/{id} com status
Remover destroy() DELETE /v3/subscriptions/{id}
Trocar cartão sem cobrar updateCreditCard() PUT /v3/subscriptions/{id}/creditCard
Cobranças geradas getPayments() GET /v3/subscriptions/{id}/payments
Carnê (PDF) paymentBook() GET /v3/subscriptions/{id}/paymentBook
Nota fiscal create/get/update/destroyInvoiceSettings() /v3/subscriptions/{id}/invoiceSettings
Notas emitidas getInvoices() GET /v3/subscriptions/{id}/invoices

Também entram os setters que faltavam: setSubscription(), setAmount(Money|int|float) e setCycle(SubscriptionCycleEnum).

$assinatura = $phpay->subscription()
    ->setCustomer($cliente)
    ->setAmount(Money::reais('49,90'))
    ->setCycle(SubscriptionCycleEnum::MONTHLY)
    ->setSubscription(['billingType' => 'BOLETO', 'nextDueDate' => '2026-10-10'])
    ->create();

file_put_contents('carne.pdf', $phpay->subscription()->paymentBook($assinatura['id']));

Commits

  1. feat(http): HasHttpClient::download(). O carnê responde PDF, e o request() decodificava tudo como JSON, devolvendo []. Os dois agora passam pelo mesmo send(), então a falha continua virando ApiException.
  2. fix(asaas): cycle passa a ser obrigatório na criação, como na especificação do Asaas. O payload sem ele passava pela validação e só falhava no gateway.
  3. feat(asaas): os endpoints acima, com validação do troca-cartão (token, ou cartão e titular, sempre com remoteIp) e da nota fiscal (os sete impostos obrigatórios).
  4. doc(asaas): README, roadmap, CLAUDE.md e examples/asaas/subscriptions.php.

Decisões que merecem revisão

  • deactivate() e reactivate() existem porque o Asaas recomenda pausar em vez de remover. O destroy() leva junto as cobranças pendentes e vencidas. Reativar exige um novo nextDueDate, segundo a documentação do Asaas, por isso ele é parâmetro obrigatório.
  • create(array $subscription) passou a ter o parâmetro opcional. Quem chama não percebe diferença, e o array continua sobrescrevendo o que os setters montaram. Só quebraria quem implementa SubscriptionInterface fora da biblioteca, o mesmo caso do SupportsCustomers na v2.1.0.
  • cycle obrigatório: quem criava assinatura sem ele recebia ApiException do Asaas e agora recebe ValidationException antes da chamada. A requisição já falhava, só falha mais cedo e com mensagem melhor.
  • A especificação do PUT não lista value, embora a própria página diga que dá para alterar o valor. O update() repassa o array como está, sem normalizar Money, e o PHPDoc manda consultar a documentação.

Como testar

composer test roda 354 testes, 968 asserções, todos com HTTP mockado. Os 23 testes novos cobrem:

  • o método, a URI e o corpo de cada endpoint
  • o carnê devolvendo os bytes exatos do PDF, com e sem mês e ano
  • ApiException quando o carnê não existe
  • as validações de cartão e de nota fiscal barrando antes de qualquer HTTP

Não foi exercitado contra o sandbox real.

Checklist

  • composer test passa (Pint, Pest e PHPStan nível 9)
  • Cobri a mudança com testes, usando HTTP mockado (nenhum teste acessa a rede)
  • Atualizei README, CLAUDE.md ou UPGRADE.md, se a mudança afeta quem usa a biblioteca
  • Nenhuma credencial, token ou dado pessoal real foi commitado
  • Li e aceito o Contributor License Agreement

Alguns endpoints respondem PDF ou imagem, não JSON — o carnê de assinatura do Asaas é o primeiro. request() decodificava tudo como JSON e devolvia [] nesses casos. download() devolve o corpo cru, e os dois passam pelo mesmo send(), então a falha continua virando ApiException.
A especificação do Asaas marca cycle como obrigatório em POST /v3/subscriptions, mas o validador não o conferia: o payload sem ele passava e só falhava no gateway, como ApiException. Agora falha antes, como ValidationException, com os valores aceitos na mensagem. SubscriptionCycleEnum lista os sete ciclos.
O recurso Subscription só tinha create(). Agora cobre os 14 endpoints de assinatura da API do Asaas, conferidos na especificação OpenAPI oficial:

- getAll(), find(), update() e destroy()
- deactivate() e reactivate($id, $nextDueDate): a pausa que o Asaas recomenda no lugar de remover, porque destroy() leva junto as cobranças pendentes e vencidas. Reativar exige um novo vencimento, segundo a própria documentação
- updateCreditCard(): troca o cartão sem cobrar, por token ou pelos dados do cartão, com o remoteIp do comprador
- getPayments(): as cobranças já geradas
- paymentBook(): o carnê, como os bytes do PDF
- nota fiscal por cobrança: createInvoiceSettings(), getInvoiceSettings(), updateInvoiceSettings(), destroyInvoiceSettings() e getInvoices()

E os setters que faltavam: setSubscription(), setAmount(Money|int|float), com número cru lido em reais como no resto do Asaas, e setCycle(SubscriptionCycleEnum).

create(array) continua funcionando como sempre: o array sobrescreve o que os setters montaram. O parâmetro passou a ser opcional, então quem implementa SubscriptionInterface fora da biblioteca precisa acompanhar a assinatura nova.
- README: a seção de assinaturas do Asaas passa a cobrir consulta, ciclo de vida, carnê, troca de cartão e nota fiscal. O roadmap marca Assinaturas como pronto, e a nota de pendência sai
- README: o Asaas deixa de ser "o único com as cinco capacidades", que era falso desde o Woovi
- CLAUDE.md: as particularidades das assinaturas do Asaas e o download() no HasHttpClient. A pendência das assinaturas sai de O que ainda está em aberto
- examples/asaas/subscriptions.php mostra as operações novas; o carnê gerado é ignorado pelo git
@mariolucasdev
mariolucasdev merged commit 459fca8 into develop Sep 21, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Asaas: completar as assinaturas — listar, buscar, atualizar, remover, carnê e nota fiscal

1 participant