Repository navigation
PHPAY-173: feat: describe a charge once, for more than one gateway - #175
Merged
Merged
Conversation
ChargeIntent is to a charge what Customer is to the payer: one description, and each gateway translates it in its own *ChargeRequest::fromIntent(), where the knowledge of that schema already lives. SupportsChargeIntents declares an operation rather than a resource getter, the shape SupportsRefunds already uses. It carries two methods because SupportsCharges answers 'does this gateway charge?' and never 'does it charge that way?' - all ten declare charges and even so the Rede only does credit, so supportedMethods() is what keeps a Pix charge from being handed to a gateway that cannot do Pix. supportedMethods() describes the portable path, not the gateway's catalogue: the Asaas sells billets through setCharge() and they are absent here, because declaring a method the call would refuse is the same mistake as declaring a capability and throwing from inside it. Where a gateway expires a charge by duration instead of by date, a due date is refused rather than converted. The Woovi takes expiresIn in seconds and the Mercado Pago takes date_of_expiration with an offset; converting would mean assuming a timezone, and the library assumes none anywhere. The Inter's Pix key moved to the gateway configuration, since the same key answers for every charge of that clientId. It sits after $client in the constructor because inserting it earlier would break positional construction. setCharge(array) is untouched and stays the way to send that gateway's raw payload.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fase 1 de #173, com as três decisões do desenho fechadas como combinado.
O que entra
Method(pix, boleto, crédito, débito)src/Support/Method.phpChargeIntentsrc/Support/ChargeIntent.phpSupportsChargeIntentssrc/Contracts/SupportsChargeIntents.phpCapability::CHARGE_INTENTSsrc/Contracts/Capability.phpcreateCharge()esupportedMethods()na facadesrc/PHPay.phpfromIntent()+ os dois métodosA prova
O mesmo
ChargeIntentnos três primeiros, e o corpo que de fato sai:value149.9— reais14990— centavos{"original": "149.90"}— reais em string, o terceiro formatoE o mesmo
CustomerviracpfCnpj,taxID,payer.identification.numberedevedor.cpf. Tudo asseverado sobre o corpo da requisição, não sobre oretorno.
As três decisões, implementadas
1.
supportedMethods()numa interface nova.SupportsChargesficaintacta — acrescentar método a interface publicada quebraria quem a implementa
fora do repositório. A forma é a do
SupportsRefunds: estendeSupportsCharges, declara operação, tem case naCapabilitye guard nafacade.
2. A Efí fica para a fase 3, e entra roteando por dentro: lá
charge()éboleto e
pixCharge()é a cobrança Pix, e será ocreateCharge()a decidir.Confirmei por que a alternativa está fora:
Efi::charge(): Chargeé tipadoconcreto, então despachar por método tornaria o retorno
Charge|PixChargeequebraria todo
Charge $c = $efi->charge();existente.3. A chave Pix do Inter foi para a configuração (
pixKeyemGateway::INTER->options()), no construtor depois de$client. A posiçãoé feia e é deliberada:
$clienté o sétimo parâmetro, e inserir antesquebraria construção posicional.
setKey()continua para quem atende mais deuma chave.
Uma decisão que o desenho não explicitou
supportedMethods()devolve o quecreateCharge()aceita hoje, não ocatálogo do gateway. O Asaas vende boleto e cartão por
setCharge(), e elesnão aparecem ali — declarar um meio que a chamada recusaria é o mesmo erro
que declarar capacidade e lançar de dentro dela, que é a primeira regra do
CLAUDE.md. Está no PHPDoc da interface e na documentação.Vencimento: recusar em vez de converter
A Woovi expira por
expiresIn(segundos) e o Mercado Pago pordate_of_expiration(data e hora com fuso). Converter umdueDateexigiriaassumir um fuso horário, e a biblioteca não assume nenhum em lugar nenhum —
então os dois recusam, com a mensagem apontando o campo nativo via
withExtra(). O Asaas é o inverso: exigedueDatemesmo no Pix, e arecusa diz que é limite do gateway.
O que não foi tocado
setCharge(array)segue intacto e segue sendo o caminho do payload cru. Sãodois caminhos convivendo, e isso é custo permanente de documentação — é o
preço de não quebrar a v2, e está dito em
docs/cobranca-portavel.md.Portão
para isso que o gerador existe
minimumganhou o ramo da capacidade nova: 105verificações, e ele exercita os dois sentidos sem rede
toHaveCount(8)→9, alista do Mercado Pago, as
options()do Inter). Nenhuma era defeito: são asafirmações que o projeto planta de propósito para pegar case novo, e
pegaram.
Fase 2 e 3
Ficam em #173. A 2 é
comItens()para PagBank, Pagar.me e AbacatePay, quemontam cobrança por itens e não por valor; a 3 é
boleto(),cartao()e um VOCard, que traz PAN e merece revisão própria.