O que diz a GoCardless
| Reason | Tipo | HTTP | Texto de GoCardless |
|---|---|---|---|
idempotent_creation_conflict | invalid_state | 409 | A resource already exists for the supplied idempotency key. |
A página de limites da GoCardless completa-o: se já existir um recurso com essa chave, a resposta é um 409 com links.conflicting_resource_id, que assinala o recurso já criado. As chaves podem ter até 128 caracteres e a GoCardless guarda-as durante pelo menos 30 dias.

O problema que resolve
Um pedido pode demorar: a GoCardless corta os que ultrapassam 29 segundos, e a rede pode cortar antes. Se o Odoo pede uma cobrança e não recebe resposta, não sabe se a GoCardless a criou. Repetir o pedido sem mais é perigoso; a própria documentação da GoCardless avisa que repetir sem chave de idempotência após um tempo limite esgotado pode cobrar o mesmo pagamento duas vezes.
Com chave, a segunda tentativa não cria nada: se a primeira chegou, a GoCardless responde com este 409 e o identificador da cobrança que já existe.
Como o conector o usa
O conector envia uma chave de idempotência em cada pedido que cria uma cobrança, um reembolso, uma nova tentativa ou o pedido do mandato. A chave não é aleatória. Calcula-se com a operação, a transação do Odoo e o identificador da base de dados, de modo que:
- repetir a mesma cobrança envia exatamente a mesma chave;
- uma cópia da base para testes não colide com a de produção, mesmo que as duas emitam a mesma fatura.
Quando chega o 409, o conector lê conflicting_resource_id, pede esse recurso à GoCardless e adota-o como resposta. Para si não há erro: a transação fica associada à cobrança que já existia, e a fatura segue o seu curso normal.
Quando a GoCardless não responde
Se o pedido ficar sem resposta, o conector repete-o uma vez com a mesma chave. Sem chave, não repete nada. Se também não houver resposta, avisa sem dar a cobrança por perdida: «A GoCardless não respondeu, por isso ainda não se sabe se aceitou o pedido. Será enviado novamente, em segurança, dentro de uma hora.». A transação fica pendente, não em erro, porque em erro o Odoo poderia gerar outra cobrança com outra referência e outra chave.
Estes textos saem no idioma de quem lança a cobrança; se for uma ação agendada, como a renovação de uma subscrição ou o reenvio do próprio conector, são escritos sem ninguém à frente: numa base de dados criada em português saem assim, e numa criada em inglês e passada depois para português, em inglês: «GoCardless did not answer, so it is not known yet whether it took the request. It will be sent again, safely, within the hour.».

O que fazer
Com o conector, normalmente nada: o 409 resolve-se sozinho. Se o vir noutro programa ligado à mesma conta da GoCardless, verifique duas coisas. A primeira, que não esteja a reutilizar uma chave para operações diferentes. A segunda, que o recurso de conflicting_resource_id seja o que esperava: se for, a nova tentativa funcionou como deve. Se não for, guarde o request_id da resposta: a GoCardless pede que o inclua ao contactar o seu suporte, e o conector acrescenta-o às suas mensagens de erro.
Um 409 significa que o cliente pagou duas vezes?
Pelo contrário. Significa que a GoCardless recusou criar a segunda cobrança porque a chave já tinha uma. O cliente paga uma única vez.
O que acontece se se alterar a referência da transação?
Muda a chave, e a GoCardless trata-o como uma cobrança nova. Por isso o conector deixa pendente, e não em erro, uma cobrança sem resposta: assim não se cria outra com outra referência.
Com o nosso conector
No Odoo 17, 18, 19 e 20 o conector aplica a regra que a GoCardless pede para não cobrar duas vezes: chave fixa por operação, repetição apenas com a mesma chave e adoção do recurso existente quando chega o 409.
Continue a ler
Verificado no código do conector (versão 17.0, 18.0, 19.0 e 20.0) e nas fontes indicadas
Fontes
- docs.gocardless.com/docs/api-reference/limits
- Código do módulo: flexigo_payment_gocardless: models/payment_provider.py, linha 462 em 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) e 20.0 (688d86b)
- Código do módulo: flexigo_payment_gocardless: models/payment_provider.py, linha 352 em 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) e 20.0 (688d86b)
- Código do módulo: flexigo_payment_gocardless: models/payment_transaction.py, linha 68 em 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) e 20.0 (688d86b)
- Código do módulo: flexigo_payment_gocardless: models/payment_provider.py, linha 391 em 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) e 20.0 (688d86b)
- Código do módulo: flexigo_payment_gocardless: models/payment_provider.py, linha 357 em 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) e 20.0 (688d86b)
- Código do módulo: flexigo_payment_gocardless: models/payment_provider.py, linha 373 em 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) e 20.0 (688d86b)
- Código do módulo: flexigo_payment_gocardless: models/payment_transaction.py, linha 299 em 17.0 (d203ee6), linha 299 em 18.0 (e2ab18b), linha 299 em 19.0 (ce7f5a3) e linha 310 em 20.0 (688d86b)
- Código do módulo: flexigo_payment_gocardless: i18n/pt.po, linha 476 em 17.0 (d203ee6), linha 476 em 18.0 (e2ab18b), linha 476 em 19.0 (ce7f5a3) e linha 482 em 20.0 (688d86b)
- Código do módulo: flexigo_payment_gocardless: i18n/pt.po, linha 30 em 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) e 20.0 (688d86b)
- Código do módulo: flexigo_payment_gocardless: __manifest__.py, linha 31 em 17.0 (d203ee6), 18.0 (e2ab18b), 19.0 (ce7f5a3) e 20.0 (688d86b)
- docs.gocardless.com/docs/api-reference/responses-and-errors
- Código do módulo: flexigo_payment_gocardless: models/payment_transaction.py, linha 123 em 17.0 (d203ee6), linha 123 em 18.0 (e2ab18b), linha 123 em 19.0 (ce7f5a3) e linha 126 em 20.0 (688d86b)
- Código do módulo: flexigo_payment_gocardless: models/payment_transaction.py, linha 247 em 17.0 (d203ee6), linha 247 em 18.0 (e2ab18b), linha 247 em 19.0 (ce7f5a3) e linha 258 em 20.0 (688d86b)
- github.com/odoo/odoo/blob/17.0/odoo/http.py
