django-checkouts 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_checkouts-1.0.1/.github/workflows/release.yml +73 -0
- django_checkouts-1.0.1/.gitignore +14 -0
- django_checkouts-1.0.1/.python-version +1 -0
- django_checkouts-1.0.1/.release-please-manifest.json +1 -0
- django_checkouts-1.0.1/.superpowers/sdd/task-1-report.md +148 -0
- django_checkouts-1.0.1/.superpowers/sdd/task-2-report.md +68 -0
- django_checkouts-1.0.1/.superpowers/sdd/task-8-report.md +99 -0
- django_checkouts-1.0.1/CHANGELOG.md +50 -0
- django_checkouts-1.0.1/CLAUDE.md +133 -0
- django_checkouts-1.0.1/LICENSE +28 -0
- django_checkouts-1.0.1/PKG-INFO +146 -0
- django_checkouts-1.0.1/README.rst +115 -0
- django_checkouts-1.0.1/django_checkouts/__init__.py +9 -0
- django_checkouts-1.0.1/django_checkouts/apps.py +12 -0
- django_checkouts-1.0.1/django_checkouts/capabilities.py +107 -0
- django_checkouts-1.0.1/django_checkouts/checks.py +62 -0
- django_checkouts-1.0.1/django_checkouts/client.py +30 -0
- django_checkouts-1.0.1/django_checkouts/credentials.py +73 -0
- django_checkouts-1.0.1/django_checkouts/enums.py +199 -0
- django_checkouts-1.0.1/django_checkouts/exceptions.py +147 -0
- django_checkouts-1.0.1/django_checkouts/gateways/__init__.py +7 -0
- django_checkouts-1.0.1/django_checkouts/gateways/base.py +84 -0
- django_checkouts-1.0.1/django_checkouts/gateways/commands.py +126 -0
- django_checkouts-1.0.1/django_checkouts/gateways/contracts.py +47 -0
- django_checkouts-1.0.1/django_checkouts/gateways/options.py +15 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/__init__.py +8 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/capabilities.py +48 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/gateway.py +235 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/handlers/__init__.py +49 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/handlers/checkouts.py +247 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/handlers/events.py +77 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/handlers/invoices.py +40 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/handlers/subscriptions.py +232 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/mapping.py +1120 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/options.py +21 -0
- django_checkouts-1.0.1/django_checkouts/gateways/stripe/webhooks.py +76 -0
- django_checkouts-1.0.1/django_checkouts/integrations/__init__.py +3 -0
- django_checkouts-1.0.1/django_checkouts/integrations/drf.py +42 -0
- django_checkouts-1.0.1/django_checkouts/py.typed +0 -0
- django_checkouts-1.0.1/django_checkouts/registry.py +91 -0
- django_checkouts-1.0.1/django_checkouts/resources/__init__.py +19 -0
- django_checkouts-1.0.1/django_checkouts/resources/_validation.py +11 -0
- django_checkouts-1.0.1/django_checkouts/resources/checkouts.py +42 -0
- django_checkouts-1.0.1/django_checkouts/resources/events.py +37 -0
- django_checkouts-1.0.1/django_checkouts/resources/invoices.py +21 -0
- django_checkouts-1.0.1/django_checkouts/resources/setups.py +35 -0
- django_checkouts-1.0.1/django_checkouts/resources/subscriptions.py +68 -0
- django_checkouts-1.0.1/django_checkouts/resources/webhooks.py +23 -0
- django_checkouts-1.0.1/django_checkouts/testing/__init__.py +8 -0
- django_checkouts-1.0.1/django_checkouts/testing/contracts.py +212 -0
- django_checkouts-1.0.1/django_checkouts/testing/fakes.py +40 -0
- django_checkouts-1.0.1/django_checkouts/types/__init__.py +51 -0
- django_checkouts-1.0.1/django_checkouts/types/checkouts.py +103 -0
- django_checkouts-1.0.1/django_checkouts/types/common.py +107 -0
- django_checkouts-1.0.1/django_checkouts/types/events.py +68 -0
- django_checkouts-1.0.1/django_checkouts/types/invoices.py +93 -0
- django_checkouts-1.0.1/django_checkouts/types/setups.py +98 -0
- django_checkouts-1.0.1/django_checkouts/types/subscriptions.py +159 -0
- django_checkouts-1.0.1/django_checkouts/version.py +24 -0
- django_checkouts-1.0.1/django_checkouts/webhooks.py +173 -0
- django_checkouts-1.0.1/django_checkouts.egg-info/PKG-INFO +146 -0
- django_checkouts-1.0.1/django_checkouts.egg-info/SOURCES.txt +116 -0
- django_checkouts-1.0.1/django_checkouts.egg-info/dependency_links.txt +1 -0
- django_checkouts-1.0.1/django_checkouts.egg-info/requires.txt +5 -0
- django_checkouts-1.0.1/django_checkouts.egg-info/scm_file_list.json +112 -0
- django_checkouts-1.0.1/django_checkouts.egg-info/scm_version.json +8 -0
- django_checkouts-1.0.1/django_checkouts.egg-info/top_level.txt +1 -0
- django_checkouts-1.0.1/docs/__init__.py +3 -0
- django_checkouts-1.0.1/docs/conf.py +9 -0
- django_checkouts-1.0.1/docs/errors-and-retries.rst +48 -0
- django_checkouts-1.0.1/docs/gateway-options.rst +34 -0
- django_checkouts-1.0.1/docs/index.rst +25 -0
- django_checkouts-1.0.1/docs/integracao-sandbox-asaas.md +186 -0
- django_checkouts-1.0.1/docs/integracao-sandbox-pagseguro.md +164 -0
- django_checkouts-1.0.1/docs/integracao-sandbox-stripe.md +166 -0
- django_checkouts-1.0.1/docs/migration-pre-1.0.rst +60 -0
- django_checkouts-1.0.1/docs/plano-testes-sandbox.md +157 -0
- django_checkouts-1.0.1/docs/quickstart.rst +69 -0
- django_checkouts-1.0.1/docs/reconciliation.rst +35 -0
- django_checkouts-1.0.1/docs/subscriptions.rst +62 -0
- django_checkouts-1.0.1/docs/superpowers/plans/2026-08-07-recurring-checkout-lifecycle.md +883 -0
- django_checkouts-1.0.1/docs/superpowers/specs/2026-08-06-django-checkouts-recurring-lifecycle-design.md +825 -0
- django_checkouts-1.0.1/docs/webhooks.rst +32 -0
- django_checkouts-1.0.1/docs/writing-a-gateway.rst +40 -0
- django_checkouts-1.0.1/pyproject.toml +133 -0
- django_checkouts-1.0.1/release-please-config.json +11 -0
- django_checkouts-1.0.1/setup.cfg +4 -0
- django_checkouts-1.0.1/test_settings.py +38 -0
- django_checkouts-1.0.1/tests/__init__.py +1 -0
- django_checkouts-1.0.1/tests/conftest.py +35 -0
- django_checkouts-1.0.1/tests/gateways/__init__.py +1 -0
- django_checkouts-1.0.1/tests/gateways/stripe/__init__.py +1 -0
- django_checkouts-1.0.1/tests/gateways/stripe/fixtures/event_invoice_paid.json +49 -0
- django_checkouts-1.0.1/tests/gateways/stripe/fixtures/event_unknown.json +16 -0
- django_checkouts-1.0.1/tests/gateways/stripe/fixtures/invoice_failed.json +45 -0
- django_checkouts-1.0.1/tests/gateways/stripe/fixtures/invoice_paid.json +61 -0
- django_checkouts-1.0.1/tests/gateways/stripe/fixtures/session_open.json +20 -0
- django_checkouts-1.0.1/tests/gateways/stripe/fixtures/session_paid.json +20 -0
- django_checkouts-1.0.1/tests/gateways/stripe/fixtures/subscription_active.json +45 -0
- django_checkouts-1.0.1/tests/gateways/stripe/fixtures/subscription_canceling.json +34 -0
- django_checkouts-1.0.1/tests/gateways/stripe/test_checkouts.py +639 -0
- django_checkouts-1.0.1/tests/gateways/stripe/test_errors.py +169 -0
- django_checkouts-1.0.1/tests/gateways/stripe/test_events.py +157 -0
- django_checkouts-1.0.1/tests/gateways/stripe/test_invoices.py +175 -0
- django_checkouts-1.0.1/tests/gateways/stripe/test_subscriptions.py +380 -0
- django_checkouts-1.0.1/tests/gateways/stripe/test_webhooks.py +239 -0
- django_checkouts-1.0.1/tests/test_capabilities.py +68 -0
- django_checkouts-1.0.1/tests/test_checks.py +89 -0
- django_checkouts-1.0.1/tests/test_client.py +196 -0
- django_checkouts-1.0.1/tests/test_contract_suite.py +139 -0
- django_checkouts-1.0.1/tests/test_credentials.py +40 -0
- django_checkouts-1.0.1/tests/test_drf.py +88 -0
- django_checkouts-1.0.1/tests/test_gateway_dispatch.py +140 -0
- django_checkouts-1.0.1/tests/test_public_interface.py +210 -0
- django_checkouts-1.0.1/tests/test_registry.py +56 -0
- django_checkouts-1.0.1/tests/test_types.py +387 -0
- django_checkouts-1.0.1/tests/test_webhooks.py +106 -0
- django_checkouts-1.0.1/uv.lock +1357 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
permissions: {}
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
release:
|
|
12
|
+
name: Release Please
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
16
|
+
issues: write
|
|
17
|
+
pull-requests: write
|
|
18
|
+
outputs:
|
|
19
|
+
release_created: ${{ steps.release.outputs.release_created }}
|
|
20
|
+
tag_name: ${{ steps.release.outputs.tag_name }}
|
|
21
|
+
steps:
|
|
22
|
+
- id: release
|
|
23
|
+
uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4
|
|
24
|
+
with:
|
|
25
|
+
config-file: release-please-config.json
|
|
26
|
+
manifest-file: .release-please-manifest.json
|
|
27
|
+
|
|
28
|
+
build:
|
|
29
|
+
name: Build distributions
|
|
30
|
+
needs: release
|
|
31
|
+
if: ${{ needs.release.outputs.release_created == 'true' }}
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
permissions:
|
|
34
|
+
contents: read
|
|
35
|
+
steps:
|
|
36
|
+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
37
|
+
with:
|
|
38
|
+
ref: ${{ needs.release.outputs.tag_name }}
|
|
39
|
+
# setuptools_scm calcula a versão a partir da tag do git: sem
|
|
40
|
+
# histórico/tags a build cai no fallback_version "0.0.0".
|
|
41
|
+
fetch-depth: 0
|
|
42
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: "3.13"
|
|
45
|
+
- name: Install build tools
|
|
46
|
+
run: python -m pip install "build>=1.2,<2" "twine>=6,<7"
|
|
47
|
+
- name: Build distributions
|
|
48
|
+
run: python -m build
|
|
49
|
+
- name: Validate distributions
|
|
50
|
+
run: python -m twine check dist/*
|
|
51
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
52
|
+
with:
|
|
53
|
+
name: python-package-distributions
|
|
54
|
+
path: dist/
|
|
55
|
+
if-no-files-found: error
|
|
56
|
+
|
|
57
|
+
publish:
|
|
58
|
+
name: Publish distributions to PyPI
|
|
59
|
+
needs: build
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
environment:
|
|
62
|
+
name: pypi
|
|
63
|
+
url: https://pypi.org/p/django-checkouts
|
|
64
|
+
permissions:
|
|
65
|
+
id-token: write
|
|
66
|
+
steps:
|
|
67
|
+
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
|
68
|
+
with:
|
|
69
|
+
name: python-package-distributions
|
|
70
|
+
path: dist/
|
|
71
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
72
|
+
with:
|
|
73
|
+
packages-dir: dist/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{".":"1.0.1"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Task 1 — vocabulário normalizado, DTOs e erros
|
|
2
|
+
|
|
3
|
+
## Implementação
|
|
4
|
+
|
|
5
|
+
- Substituído o vocabulário público de `Provider` por `Gateway`, preservando
|
|
6
|
+
`Provider = Gateway` durante a migração dos módulos legados.
|
|
7
|
+
- Adicionados os enums normalizados de assinatura, fatura, evento, recurso,
|
|
8
|
+
alterações e retry, todos com rótulos traduzíveis via `pgettext_lazy`.
|
|
9
|
+
- Criada a taxonomia pública de erros com `RetryAdvice`, a árvore de erros de
|
|
10
|
+
gateway e aliases compatíveis para `ProviderTemporaryError`,
|
|
11
|
+
`ProviderPermanentError` e `CheckoutNotFound`.
|
|
12
|
+
- Criado `GatewayOptions`, os DTOs públicos de checkout, assinatura, fatura e
|
|
13
|
+
evento, e a reexportação explícita em `django_checkouts.types`.
|
|
14
|
+
- As dataclasses são congeladas, slotted e keyword-only (exceto
|
|
15
|
+
`RetryAdvice`, cuja forma posicional é a indicada pela especificação).
|
|
16
|
+
- Centralizados os validadores de quantidades, moeda, UTC, criação de checkout
|
|
17
|
+
e alterações de assinatura. Resultados e eventos fazem uma cópia defensiva
|
|
18
|
+
de `raw` com `MappingProxyType(deepcopy(dict(...)))` e omitem esse campo do
|
|
19
|
+
`repr` e da comparação.
|
|
20
|
+
|
|
21
|
+
## TDD
|
|
22
|
+
|
|
23
|
+
1. RED: criado `tests/test_types.py` com os três testes prescritos (dinheiro,
|
|
24
|
+
imutabilidade/`raw`, quantidade) e executado
|
|
25
|
+
`uv run pytest tests/test_types.py -q`. A coleta falhou como esperado com
|
|
26
|
+
`ImportError: cannot import name 'Gateway'`.
|
|
27
|
+
2. RED ampliado: antes da implementação, os testes passaram a abranger itens
|
|
28
|
+
vazios/moedas mistas/recorrência incompatível, quantidades booleanas,
|
|
29
|
+
conflitos de alteração, UTC, cópia defensiva de `raw` e `RetryAdvice`.
|
|
30
|
+
A execução continuou falhando pela mesma API inexistente.
|
|
31
|
+
3. GREEN: após a implementação, `uv run pytest tests/test_types.py
|
|
32
|
+
tests/test_base.py -q --no-cov` passou com **32 testes**.
|
|
33
|
+
|
|
34
|
+
## Comandos e resultados
|
|
35
|
+
|
|
36
|
+
| Comando | Resultado |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `uv run pytest tests/test_types.py -q` (RED) | coleta falhou: `Gateway` ausente |
|
|
39
|
+
| `uv run pytest tests/test_types.py tests/test_base.py -q --no-cov` | 32 passed |
|
|
40
|
+
| `uv run pytest -q` | 102 passed; cobertura total 94,39% |
|
|
41
|
+
| `uv run mypy django_checkouts` | sucesso, sem problemas |
|
|
42
|
+
| `uvx ruff check django_checkouts/enums.py django_checkouts/exceptions.py django_checkouts/gateways django_checkouts/types tests/test_types.py` | sucesso |
|
|
43
|
+
| `git diff --check` | sucesso |
|
|
44
|
+
|
|
45
|
+
O comando literal do brief, sem `--no-cov`, executa os 32 testes com sucesso,
|
|
46
|
+
mas termina com código 1 porque o gate global de 90% de cobertura é aplicado a
|
|
47
|
+
um subconjunto da suíte (64,03%); a suíte completa passa o gate com 94,39%.
|
|
48
|
+
|
|
49
|
+
## Arquivos alterados
|
|
50
|
+
|
|
51
|
+
- `django_checkouts/enums.py`
|
|
52
|
+
- `django_checkouts/exceptions.py`
|
|
53
|
+
- `django_checkouts/gateways/__init__.py`
|
|
54
|
+
- `django_checkouts/gateways/options.py`
|
|
55
|
+
- `django_checkouts/types/__init__.py`
|
|
56
|
+
- `django_checkouts/types/common.py`
|
|
57
|
+
- `django_checkouts/types/checkouts.py`
|
|
58
|
+
- `django_checkouts/types/subscriptions.py`
|
|
59
|
+
- `django_checkouts/types/invoices.py`
|
|
60
|
+
- `django_checkouts/types/events.py`
|
|
61
|
+
- `tests/test_types.py`
|
|
62
|
+
|
|
63
|
+
## Auto-revisão
|
|
64
|
+
|
|
65
|
+
- Conferidos os valores de todos os novos enums e os campos de `Checkout`,
|
|
66
|
+
`Subscription`, `Invoice`, `WebhookEvent` e `EventPage` por introspecção de
|
|
67
|
+
dataclasses.
|
|
68
|
+
- Confirmados `Price` e todos os DTOs no `__all__` explícito.
|
|
69
|
+
- Confirmadas as normalizações de moeda e UTC, a imutabilidade de dataclasses,
|
|
70
|
+
a ocultação de `raw` no `repr` e a proteção contra mutação da raiz de `raw`.
|
|
71
|
+
- Mantida compatibilidade de imports legados necessária à suíte atual; não
|
|
72
|
+
foram implementadas tarefas posteriores de gateways/resources.
|
|
73
|
+
|
|
74
|
+
## Pontos de atenção
|
|
75
|
+
|
|
76
|
+
- `uvx ruff check .` ainda acusa duas violações preexistentes em
|
|
77
|
+
`django_checkouts/registry.py` (`S112` e `BLE001`); elas não pertencem a
|
|
78
|
+
este escopo. O lint de todos os arquivos alterados está limpo.
|
|
79
|
+
- A especificação pede `MappingProxyType` na raiz de `raw`; portanto, valores
|
|
80
|
+
aninhados continuam objetos mutáveis da cópia defensiva, exatamente conforme
|
|
81
|
+
a construção prescrita.
|
|
82
|
+
|
|
83
|
+
## Correção da revisão — 2026-08-15
|
|
84
|
+
|
|
85
|
+
### RED/GREEN
|
|
86
|
+
|
|
87
|
+
1. RED: ampliados `tests/test_types.py` e `tests/test_base.py`; a execução de
|
|
88
|
+
`uv run pytest tests/test_types.py tests/test_base.py -q --no-cov` falhou
|
|
89
|
+
com 5 falhas esperadas: resultados aceitavam `bool`/`float`, `RetryAdvice`
|
|
90
|
+
aceitava argumentos posicionais, `GatewayError` retinha token externo e o
|
|
91
|
+
status financeiro desconhecido ainda levantava `ProviderPermanentError`.
|
|
92
|
+
2. GREEN: adicionada validação estrita de inteiro a todos os montantes públicos
|
|
93
|
+
de resultado; valores negativos continuam permitidos para créditos e
|
|
94
|
+
reembolsos. `RetryAdvice` passou a ser `frozen`, `slots` e `kw_only`.
|
|
95
|
+
Mensagens externas de gateway são substituídas por diagnóstico seguro antes
|
|
96
|
+
de serem armazenadas. `BaseCheckoutProvider.map_status` agora levanta
|
|
97
|
+
`GatewayProtocolError`; a herança preserva a compatibilidade com o alias
|
|
98
|
+
`ProviderPermanentError`.
|
|
99
|
+
|
|
100
|
+
### Evidência de testes
|
|
101
|
+
|
|
102
|
+
| Comando | Resultado |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| `uv run pytest tests/test_types.py tests/test_base.py -q --no-cov` (RED) | 5 failed, 31 passed — falhas esperadas descritas acima |
|
|
105
|
+
| `uv run pytest tests/test_types.py tests/test_base.py -q --no-cov` (GREEN) | 36 passed |
|
|
106
|
+
| `uv run pytest tests/providers/stripe/test_checkout.py -q --no-cov` | 32 passed |
|
|
107
|
+
| `uv run pytest -q` | 106 passed; cobertura total 94,67% |
|
|
108
|
+
| `uv run mypy django_checkouts` | sucesso, sem problemas |
|
|
109
|
+
| `uvx ruff check django_checkouts/exceptions.py django_checkouts/base.py django_checkouts/types tests/test_types.py tests/test_base.py` | sucesso |
|
|
110
|
+
| `git diff --check` | sucesso |
|
|
111
|
+
|
|
112
|
+
### Auto-revisão da correção
|
|
113
|
+
|
|
114
|
+
- Conferidos os sete campos monetários solicitados: todos recusam `bool` e
|
|
115
|
+
`float`; nenhum impõe positividade nos resultados de gateway.
|
|
116
|
+
- Confirmado que segredos e tokens fornecidos via `gateway_message` não são
|
|
117
|
+
armazenados nem aparecem em `repr`/`str`.
|
|
118
|
+
- Confirmado que o mapeamento desconhecido é `GatewayProtocolError`, mantendo
|
|
119
|
+
captura legada como `ProviderPermanentError` para provedores existentes.
|
|
120
|
+
- Não há preocupações pendentes no escopo desta correção.
|
|
121
|
+
|
|
122
|
+
## Correção da re-revisão — 2026-08-15
|
|
123
|
+
|
|
124
|
+
### RED/GREEN
|
|
125
|
+
|
|
126
|
+
1. RED: adicionados testes públicos para um `gateway_status` contendo uma
|
|
127
|
+
credencial, para `typing.get_type_hints` de todos os DTOs reexportados e de
|
|
128
|
+
`GatewayOptions`, e para os três campos datetime obrigatórios de eventos.
|
|
129
|
+
`uv run pytest tests/test_types.py tests/test_base.py -q --no-cov` falhou
|
|
130
|
+
com 5 falhas esperadas: o status externo aparecia na exceção, `Mapping` não
|
|
131
|
+
era resolvível durante a introspecção e os três valores `None` eram aceitos.
|
|
132
|
+
2. GREEN: `map_status` mantém a orientação para atualizar `STATUS_MAP`, mas
|
|
133
|
+
não inclui o valor remoto na mensagem. As dependências das anotações dos
|
|
134
|
+
DTOs e de `GatewayOptions` agora são importadas em runtime, preservando
|
|
135
|
+
`from __future__ import annotations`. Foi criado `normalize_required_utc`,
|
|
136
|
+
reutilizando a normalização UTC existente e recusando `None` nos três
|
|
137
|
+
campos obrigatórios.
|
|
138
|
+
|
|
139
|
+
### Evidência de testes
|
|
140
|
+
|
|
141
|
+
| Comando | Resultado |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `uv run pytest tests/test_types.py tests/test_base.py -q --no-cov` (RED) | 5 failed, 36 passed — falhas esperadas descritas acima |
|
|
144
|
+
| `uv run pytest tests/test_types.py tests/test_base.py -q --no-cov` (GREEN) | 41 passed |
|
|
145
|
+
| `uv run pytest -q` | 111 passed; cobertura total 95,91% |
|
|
146
|
+
| `uv run mypy django_checkouts` | sucesso, sem problemas |
|
|
147
|
+
| `uvx ruff check django_checkouts/base.py django_checkouts/types django_checkouts/gateways/options.py tests/test_types.py tests/test_base.py` | sucesso |
|
|
148
|
+
| `git diff --check` | sucesso |
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Task 2 — capabilities e despacho tipado
|
|
2
|
+
|
|
3
|
+
## Escopo entregue
|
|
4
|
+
|
|
5
|
+
- Capabilities aninhadas, `frozen` e com `slots`; os conjuntos são normalizados
|
|
6
|
+
para `frozenset` e o mapa de meios de pagamento é protegido por
|
|
7
|
+
`MappingProxyType`.
|
|
8
|
+
- Os dez comandos internos tipados e os contratos `ExecutionContext` e
|
|
9
|
+
`CommandHandler`.
|
|
10
|
+
- `BaseCheckoutGateway` com índice de handlers por tipo **exato**, validação antes
|
|
11
|
+
do contexto de I/O, tradução sanitizada de exceções externas e `check()` vazio.
|
|
12
|
+
- Testes de capabilities, despacho exato, ausência de handler, validação pré-I/O,
|
|
13
|
+
propagação da variante e sanitização do erro externo.
|
|
14
|
+
|
|
15
|
+
## Evidência TDD
|
|
16
|
+
|
|
17
|
+
1. **RED** — após criar `tests/test_capabilities.py` e
|
|
18
|
+
`tests/test_gateway_dispatch.py`, executei:
|
|
19
|
+
|
|
20
|
+
```console
|
|
21
|
+
uv run pytest tests/test_capabilities.py tests/test_gateway_dispatch.py -q
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
A coleta falhou como esperado com `ModuleNotFoundError` para
|
|
25
|
+
`django_checkouts.capabilities`, pois os módulos de Task 2 ainda não existiam.
|
|
26
|
+
2. **GREEN** — implementei somente os módulos previstos no briefing. A rodada
|
|
27
|
+
focada sem cobertura passou: `7 passed in 0.08s`.
|
|
28
|
+
3. **REFACTOR** — a anotação da coleção de handlers passou a usar
|
|
29
|
+
`CommandHandler[Any]`, permitindo handlers concretos de diferentes resultados
|
|
30
|
+
sem relaxar o despacho exato em runtime. A rodada focada, Ruff e mypy foram
|
|
31
|
+
repetidos após a alteração.
|
|
32
|
+
|
|
33
|
+
## Arquivos alterados
|
|
34
|
+
|
|
35
|
+
- `django_checkouts/capabilities.py`
|
|
36
|
+
- `django_checkouts/gateways/commands.py`
|
|
37
|
+
- `django_checkouts/gateways/contracts.py`
|
|
38
|
+
- `django_checkouts/gateways/base.py`
|
|
39
|
+
- `tests/test_capabilities.py`
|
|
40
|
+
- `tests/test_gateway_dispatch.py`
|
|
41
|
+
|
|
42
|
+
## Verificação
|
|
43
|
+
|
|
44
|
+
```console
|
|
45
|
+
uv run pytest tests/test_capabilities.py tests/test_gateway_dispatch.py -q --no-cov
|
|
46
|
+
# 7 passed
|
|
47
|
+
|
|
48
|
+
uvx ruff check django_checkouts/capabilities.py django_checkouts/gateways tests/test_capabilities.py tests/test_gateway_dispatch.py
|
|
49
|
+
# All checks passed!
|
|
50
|
+
|
|
51
|
+
uv run mypy django_checkouts
|
|
52
|
+
# Success: no issues found in 27 source files
|
|
53
|
+
|
|
54
|
+
uv run pytest
|
|
55
|
+
# 118 passed; cobertura total 96.31%
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Auto-revisão e ressalvas
|
|
59
|
+
|
|
60
|
+
- O despacho usa `type(command)`, portanto subclasses não reutilizam handlers de
|
|
61
|
+
comandos-base por engano.
|
|
62
|
+
- `validate()` é chamado antes de criar o contexto e antes de qualquer handler
|
|
63
|
+
poder chamar `context.call`; comandos inválidos e sem handler não fazem I/O.
|
|
64
|
+
- `call()` preserva apenas `CheckoutError`; demais `Exception` viram
|
|
65
|
+
`GatewayPermanentError` sem expor a mensagem externa.
|
|
66
|
+
- Não foram implementados handlers ou gateways concretos, que pertencem às tarefas
|
|
67
|
+
posteriores. Handlers concretos devem fazer I/O exclusivamente via
|
|
68
|
+
`ExecutionContext.call` para conservar a tradução de erros públicos.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Task 8 report — release surface, documentation, and delivery
|
|
2
|
+
|
|
3
|
+
## Scope delivered
|
|
4
|
+
|
|
5
|
+
- Replaced the package root with the exact public exports `CheckoutClient`,
|
|
6
|
+
`Gateway`, and `get_checkout_gateway`.
|
|
7
|
+
- Added `tests/test_public_interface.py` to lock exact root exports, all ten
|
|
8
|
+
resource method signatures, statically checked result types via `assert_type`,
|
|
9
|
+
absence of Stripe SDK names in normalized public annotations, and absence of
|
|
10
|
+
the pre-1.0 modules and compatibility exports.
|
|
11
|
+
- Removed the pre-1.0 base, DTO, authentication, Stripe implementation, registry
|
|
12
|
+
compatibility, enums, errors, checks alias, fixtures, and tests. The retained
|
|
13
|
+
low-level webhook helpers now use gateway terminology consistently.
|
|
14
|
+
- Updated `test_settings.py` to configure
|
|
15
|
+
`django_checkouts.gateways.stripe.StripeGateway`.
|
|
16
|
+
- Replaced the README with the resource-oriented quickstart, explicit gateway
|
|
17
|
+
implementation status, persistence boundary, delivery commands, and
|
|
18
|
+
BSD-3-Clause notice. Added the 1.0 changelog.
|
|
19
|
+
- Added a warning-clean Sphinx site with configuration plus quickstart,
|
|
20
|
+
subscriptions, webhooks, reconciliation, errors/retries, typed gateway
|
|
21
|
+
options, gateway authoring, and complete pre-1.0 migration pages. Every
|
|
22
|
+
public page states that the library owns no persistence.
|
|
23
|
+
- Documented absolute seat quantities, all proration and cancellation choices,
|
|
24
|
+
resume semantics, raw-body verification, `(variant, event_id)` uniqueness,
|
|
25
|
+
half-open reconciliation windows with overlap/deduplication, all four retry
|
|
26
|
+
dispositions, Stripe portability limits, and the gateway contract suite.
|
|
27
|
+
|
|
28
|
+
## TDD evidence
|
|
29
|
+
|
|
30
|
+
The structural test was written before production removal. The prescribed RED
|
|
31
|
+
run:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
uv run pytest tests/test_public_interface.py -q
|
|
35
|
+
# 2 failed, 2 passed
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The failures were the intended ones: the root still exported only the old
|
|
39
|
+
factory and the old modules were still importable. Exact resource signatures
|
|
40
|
+
and the Stripe-annotation boundary already passed. After replacing the surface:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
uv run pytest tests/test_public_interface.py -q --no-cov
|
|
44
|
+
# 4 passed
|
|
45
|
+
uv run mypy tests/test_public_interface.py
|
|
46
|
+
# Success: no issues found in 1 source file
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The direct mypy run proves that every `assert_type` result contract is checked
|
|
50
|
+
statically, in addition to the runtime structural assertions.
|
|
51
|
+
|
|
52
|
+
## Fresh delivery verification
|
|
53
|
+
|
|
54
|
+
| Command | Result |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| `uv sync --all-extras --all-groups` | resolved 60 packages; checked 57 |
|
|
57
|
+
| `uv run pytest` | 196 passed; 95.36% coverage |
|
|
58
|
+
| `uv run mypy django_checkouts` | success across 45 source files |
|
|
59
|
+
| `uv run mypy tests/test_public_interface.py` | success |
|
|
60
|
+
| `uvx ruff check .` | all checks passed |
|
|
61
|
+
| `uv run sphinx-build -W -b html docs docs/_build/html` | build succeeded with warnings as errors |
|
|
62
|
+
| `uv build` | wheel and sdist built successfully |
|
|
63
|
+
| legacy-term scan | matches only `docs/migration-pre-1.0.rst` |
|
|
64
|
+
| public Stripe-annotation scan | no output |
|
|
65
|
+
| `git diff --check` | success |
|
|
66
|
+
|
|
67
|
+
Both a universal wheel and source distribution exist in `dist/`. A second
|
|
68
|
+
post-commit build derives their version from the clean immutable release commit,
|
|
69
|
+
without a dirty-tree suffix.
|
|
70
|
+
|
|
71
|
+
## Clean wheel installation
|
|
72
|
+
|
|
73
|
+
Installed the built wheel plus Stripe into a new `uv` virtual environment
|
|
74
|
+
outside the repository. With Django 5.2.17 and Stripe 15.5.0, the smoke test:
|
|
75
|
+
|
|
76
|
+
- imported the three exact package exports and `StripeGateway`;
|
|
77
|
+
- confirmed every removed module is undiscoverable;
|
|
78
|
+
- confirmed `py.typed` and the packaged BSD license;
|
|
79
|
+
- confirmed no removed Stripe package path exists in the wheel.
|
|
80
|
+
|
|
81
|
+
The temporary environment was deleted after the successful check.
|
|
82
|
+
|
|
83
|
+
The clean-tree wheel smoke test also asserted that its embedded setuptools-scm
|
|
84
|
+
version contains the release commit revision.
|
|
85
|
+
|
|
86
|
+
## Design notes
|
|
87
|
+
|
|
88
|
+
- The tests tied exclusively to deleted modules were removed with those modules;
|
|
89
|
+
the complete gateway lifecycle and contract suites remain and pass.
|
|
90
|
+
- The low-level `django_checkouts.webhooks` utilities were retained because the
|
|
91
|
+
Task 8 deletion list did not remove that module. Their constructor vocabulary
|
|
92
|
+
was changed from `provider` to `gateway`, eliminating the compatibility
|
|
93
|
+
surface and satisfying the release scan.
|
|
94
|
+
- `default_app_config` was removed from the root because modern supported Django
|
|
95
|
+
versions discover `DjangoCheckoutsConfig` directly.
|
|
96
|
+
|
|
97
|
+
## Concerns
|
|
98
|
+
|
|
99
|
+
None.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Todas as mudanças relevantes deste projeto são registradas aqui.
|
|
4
|
+
|
|
5
|
+
## [1.0.1](https://github.com/davisilvarafacho/django-checkouts/compare/v1.0.0...v1.0.1) (2026-09-05)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* alinhar sublinhado do titulo no README.rst ([e885ac9](https://github.com/davisilvarafacho/django-checkouts/commit/e885ac970f754b1b1d808b5ac6445b7306a4cce6))
|
|
11
|
+
* alinhar sublinhado do título no README.rst ([542511e](https://github.com/davisilvarafacho/django-checkouts/commit/542511e1c1eab4153dac23ee60565919b3465b73))
|
|
12
|
+
|
|
13
|
+
## 1.0.0 (2026-09-05)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* add resource-oriented checkout client ([f047bdd](https://github.com/davisilvarafacho/django-checkouts/commit/f047bdded3f73f595ca02b62a3250b7309b22cbc))
|
|
19
|
+
* add Stripe recurring lifecycle ([c1b5449](https://github.com/davisilvarafacho/django-checkouts/commit/c1b54498c20cb4edf20a852cb2db4b0bfaf39a0c))
|
|
20
|
+
* add Stripe webhooks and reconciliation ([2fd4706](https://github.com/davisilvarafacho/django-checkouts/commit/2fd4706d777e926dbfca575d901f852fed66df92))
|
|
21
|
+
* add typed gateway dispatch ([c4c981e](https://github.com/davisilvarafacho/django-checkouts/commit/c4c981e0f8f2cc304e2f741fee9d1c607fc4ee91))
|
|
22
|
+
* adicionar setup de forma de pagamento ([83c1fb5](https://github.com/davisilvarafacho/django-checkouts/commit/83c1fb546b9269ed40af0dbb16d2492386d8208c))
|
|
23
|
+
* define normalized checkout contracts ([cb5a15e](https://github.com/davisilvarafacho/django-checkouts/commit/cb5a15ec6ba68b4e7e95cc815def27c05629195c))
|
|
24
|
+
* expor fatos financeiros de faturas Stripe ([4695875](https://github.com/davisilvarafacho/django-checkouts/commit/4695875a903e1ce4b628b41837efb86eefed7e8a))
|
|
25
|
+
* port Stripe checkout gateway ([ea47443](https://github.com/davisilvarafacho/django-checkouts/commit/ea47443512288400175d063cec9c351780f7395b))
|
|
26
|
+
* publish gateway integration contracts ([dddca1c](https://github.com/davisilvarafacho/django-checkouts/commit/dddca1c9aee029318375c1e8c26040a75102e819))
|
|
27
|
+
* publish recurring gateway interface ([733964a](https://github.com/davisilvarafacho/django-checkouts/commit/733964ae0cd9b253ac8c3a75dd83e205fd3bcbc2))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Bug Fixes
|
|
31
|
+
|
|
32
|
+
* completar ciclo de setup de pagamento ([3c0b988](https://github.com/davisilvarafacho/django-checkouts/commit/3c0b988c9d8a78b3fd2723c939c131787f3d0d73))
|
|
33
|
+
* deeply normalize Stripe checkout responses ([d76b0b5](https://github.com/davisilvarafacho/django-checkouts/commit/d76b0b5c5be2cc758df54970de2cf1d7654e8d4a))
|
|
34
|
+
* harden normalized gateway contracts ([9a4fdd9](https://github.com/davisilvarafacho/django-checkouts/commit/9a4fdd90072ad7686277960eff78c03223af7eb8))
|
|
35
|
+
* normalizar eventos de setup ([ce17107](https://github.com/davisilvarafacho/django-checkouts/commit/ce17107186e2153b72efb4e9e5a432e67d7f48a1))
|
|
36
|
+
* normalize Stripe SDK checkout responses ([30d0af7](https://github.com/davisilvarafacho/django-checkouts/commit/30d0af77eada641a7d75eeda7a05303beb345f33))
|
|
37
|
+
* reject Stripe inline subscription prices ([3236c2c](https://github.com/davisilvarafacho/django-checkouts/commit/3236c2c4687538219dc8e461dd6788b688ff7da9))
|
|
38
|
+
|
|
39
|
+
## 1.0.0
|
|
40
|
+
|
|
41
|
+
- Publica `CheckoutClient`, `Gateway` e `get_checkout_gateway` como entradas
|
|
42
|
+
oficiais do pacote.
|
|
43
|
+
- Adiciona recursos tipados para checkouts, assinaturas, faturas, webhooks e
|
|
44
|
+
reconciliação de eventos.
|
|
45
|
+
- Completa o ciclo Stripe de checkout e cobrança recorrente, com opções
|
|
46
|
+
específicas tipadas e tradução pública de erros.
|
|
47
|
+
- Publica integração opcional com DRF, fake determinístico e suíte de contrato
|
|
48
|
+
para gateways externos.
|
|
49
|
+
- Remove a superfície experimental anterior a 1.0; consulte o guia de migração.
|
|
50
|
+
- Mantém o projeto sob a licença BSD-3-Clause.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## O que é
|
|
6
|
+
|
|
7
|
+
`django-checkouts` — biblioteca (não projeto Django) que dá uma interface única e tipada
|
|
8
|
+
para checkout hospedado de Stripe, PagBank e Asaas, com foco no mercado brasileiro.
|
|
9
|
+
**MVP em construção:** só o Stripe está implementado; PagBank e Asaas ainda não existem
|
|
10
|
+
como código (só como docs de pesquisa em `docs/`).
|
|
11
|
+
|
|
12
|
+
A lib **não tem models, views, urls nem migrations** — ela nunca toca o banco. Recebe
|
|
13
|
+
argumentos simples, devolve dataclasses normalizados; a persistência é do projeto que a usa.
|
|
14
|
+
|
|
15
|
+
## Comandos
|
|
16
|
+
|
|
17
|
+
```console
|
|
18
|
+
uv sync --all-extras # ambiente (uv >= 0.11.28, Python 3.12 via .python-version)
|
|
19
|
+
uv run pytest # suíte completa; gate de 90% de cobertura
|
|
20
|
+
uv run pytest tests/providers/stripe/test_checkout.py::TestCreateCheckout::test_builds_inline_price_data
|
|
21
|
+
uv run pytest -q --no-cov # rodada rápida sem o relatório de cobertura
|
|
22
|
+
uv run mypy django_checkouts
|
|
23
|
+
uvx ruff check .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`pytest` usa `test_settings.py` como `DJANGO_SETTINGS_MODULE` (sqlite em memória, uma
|
|
27
|
+
variante `stripe` já configurada com credenciais falsas).
|
|
28
|
+
|
|
29
|
+
## Arquitetura
|
|
30
|
+
|
|
31
|
+
### O contrato dos providers (`base.py`)
|
|
32
|
+
|
|
33
|
+
`BaseCheckoutProvider` divide público de protegido, e a divisão é o coração da lib:
|
|
34
|
+
|
|
35
|
+
- **Público e concreto** (`create_checkout`, `retrieve_checkout`, `cancel_checkout`,
|
|
36
|
+
`verify_webhook`) — vive na base, valida tudo o que dá para validar sem rede e levanta
|
|
37
|
+
`ValidationError`/`CapabilityNotSupported` **antes de qualquer I/O**.
|
|
38
|
+
- **Protegido e abstrato** (`_create_checkout`, `_retrieve_checkout`, `_cancel_checkout`,
|
|
39
|
+
`_parse_webhook`) — é o que um provider novo escreve. Recebe um `CheckoutRequest` já
|
|
40
|
+
validado e pode confiar nele.
|
|
41
|
+
|
|
42
|
+
`build_request()` é o funil de validação; `CheckoutRequest` existe justamente para que
|
|
43
|
+
acrescentar um campo em `create_checkout` não mude a assinatura de todos os providers.
|
|
44
|
+
|
|
45
|
+
### Registry e configuração (`registry.py`)
|
|
46
|
+
|
|
47
|
+
Providers são "variantes nomeadas" em `settings.CHECKOUT_VARIANTS`:
|
|
48
|
+
`{"stripe": ("caminho.pontilhado.Classe", {**kwargs_do_construtor})}`.
|
|
49
|
+
`get_checkout_provider("stripe")` cacheia a instância em `PROVIDER_CACHE`;
|
|
50
|
+
`get_checkout_provider("asaas", api_key=...)` (com overrides) **não** cacheia — é o caso
|
|
51
|
+
multi-tenant. `conftest.py` limpa o cache entre testes por autouse fixture.
|
|
52
|
+
|
|
53
|
+
### As duas direções de autenticação
|
|
54
|
+
|
|
55
|
+
Fácil de confundir; são módulos separados de propósito:
|
|
56
|
+
|
|
57
|
+
- `credentials.py` — **saída** (app → gateway). `BaseAuth`/`TokenAuth` aplicam o header de
|
|
58
|
+
API numa sessão de requests. Token com `repr=False` para não vazar em traceback.
|
|
59
|
+
- `webhooks.py` — **entrada** (gateway → app). `BaseWebhookAuth` prova a origem e devolve
|
|
60
|
+
o payload já decodificado. Comparação de segredo sempre com `hmac.compare_digest`.
|
|
61
|
+
`HeaderTokenWebhookAuth` (modelo Asaas) e `Sha256BodyWebhookAuth` (modelo PagBank) já
|
|
62
|
+
existem, sem provider que as use ainda.
|
|
63
|
+
|
|
64
|
+
Ambos expõem `validate() -> list[CheckMessage]`, e `checks.py` transforma isso em saída do
|
|
65
|
+
`manage.py check` — credencial ausente vira erro de deploy, não 401 no primeiro cliente.
|
|
66
|
+
|
|
67
|
+
`authentication.py` é a camada DRF opcional: `webhook_auth_for(Provider.STRIPE)` fabrica a
|
|
68
|
+
authentication class, e o `WebhookPayload` verificado chega em `request.auth`. O
|
|
69
|
+
`request.user` vira um `FakeGatewayUser` — usuário falso, sem banco, que só existe porque o
|
|
70
|
+
DRF exige o par `(user, auth)`.
|
|
71
|
+
|
|
72
|
+
### Invariantes que atravessam tudo
|
|
73
|
+
|
|
74
|
+
- **Dinheiro é sempre `int` em centavos.** R$ 49,90 é `4990`. `amount_decimal` /
|
|
75
|
+
`amount_total_decimal` existem só para exibição.
|
|
76
|
+
- **Todo objeto de resposta carrega `raw`** — o payload cru intacto. Para visão tipada do
|
|
77
|
+
cru, cada provider declara uma subclasse de `ProviderState` (`from_raw` descarta chaves
|
|
78
|
+
desconhecidas, então campo novo do provedor não quebra nada).
|
|
79
|
+
- **Corpo cru de webhook, sempre.** Reserializar o JSON invalida a assinatura do Stripe e o
|
|
80
|
+
hash do PagBank.
|
|
81
|
+
- **`map_status` levanta no desconhecido; `map_event` devolve `None`.** Não há
|
|
82
|
+
`CheckoutStatus.UNKNOWN`: um status não mapeado circularia como estado legítimo e só
|
|
83
|
+
apareceria na conciliação de dinheiro. Evento desconhecido é o oposto — os provedores
|
|
84
|
+
emitem dezenas de eventos sem relação com checkout, e derrubar o webhook por causa deles
|
|
85
|
+
travaria a fila de notificações da conta.
|
|
86
|
+
- **Nada que não seja `CheckoutError` sai de um provider.** Se `requests.Timeout` ou
|
|
87
|
+
`KeyError` vazar, é bug. A divisão `ProviderTemporaryError` vs `ProviderPermanentError`
|
|
88
|
+
carrega a semântica de retry no próprio tipo.
|
|
89
|
+
- **Capacidades opcionais são declaradas, não improvisadas.** `CAPABILITIES`,
|
|
90
|
+
`SUPPORTED_PAYMENT_METHODS` e `SUPPORTED_CYCLES` fazem a base recusar de forma uniforme,
|
|
91
|
+
antes da rede, em vez de cada provider levantar `NotImplementedError` do seu jeito.
|
|
92
|
+
- **`BillingCycle` tem opções fechadas** (nomes seguem os do Asaas, o vocabulário mais
|
|
93
|
+
restrito dos três). Expor o par `interval`+`interval_count` do Stripe não sobreviveria à
|
|
94
|
+
tradução. Cada provider converte: `QUARTERLY` → `("month", 3)` no Stripe.
|
|
95
|
+
|
|
96
|
+
### Escrever um provider novo
|
|
97
|
+
|
|
98
|
+
Subclassear `BaseCheckoutProvider`; definir `name`, `STATUS_MAP`, `EVENT_MAP`,
|
|
99
|
+
`CAPABILITIES`, `SUPPORTED_PAYMENT_METHODS`, `SUPPORTED_CYCLES`, `state_class`; no
|
|
100
|
+
`__init__` montar `self.auth` e `self.webhook_auth`; implementar os quatro métodos
|
|
101
|
+
protegidos. O Stripe (`providers/stripe/checkout.py`) é o modelo de referência — inclusive
|
|
102
|
+
do `_call()`, que traduz os erros do SDK para a taxonomia da lib. Note que o `STATUS_MAP`
|
|
103
|
+
dele é chaveado por `f"{status}/{payment_status}"`, porque no Stripe "a sessão terminou" e
|
|
104
|
+
"o dinheiro entrou" são campos diferentes.
|
|
105
|
+
|
|
106
|
+
## Convenções
|
|
107
|
+
|
|
108
|
+
- **Português (pt-BR) em docstrings, mensagens de erro e comentários.** As mensagens são
|
|
109
|
+
longas de propósito: dizem o que fazer, não só o que falhou. Mantenha esse tom.
|
|
110
|
+
- Enums são `models.TextChoices` com `pgettext_lazy` — serializam como string direto num
|
|
111
|
+
campo de model e o rótulo é traduzível.
|
|
112
|
+
- **Identidade de provedor é `Provider`, nunca string solta.** `name = Provider.STRIPE`,
|
|
113
|
+
`get_checkout_provider(Provider.STRIPE)`, `webhook_auth_for(Provider.PAGSEGURO)`. Como é
|
|
114
|
+
`TextChoices`, o membro casa com a chave string do `CHECKOUT_VARIANTS` em `settings` —
|
|
115
|
+
e o settings do usuário continua com string crua, porque um módulo de settings não deve
|
|
116
|
+
importar a lib. String crua no código só para variante com nome próprio (`"stripe-br"`,
|
|
117
|
+
multi-tenant); por isso as anotações são `Provider | str`.
|
|
118
|
+
- Ruff: um import por linha (`force-single-line`) e `from __future__ import annotations`
|
|
119
|
+
obrigatório no topo de todo módulo, inclusive testes.
|
|
120
|
+
- Nenhum teste toca a rede: SDK e respostas HTTP são substituídos, com fixtures de payload
|
|
121
|
+
real em `tests/providers/<provider>/fixtures/`. A fixture `load_fixture` do `conftest.py`
|
|
122
|
+
resolve o caminho ao lado do módulo de teste.
|
|
123
|
+
- Versão vem do `setuptools_scm` (tag git) e é escrita em `django_checkouts/version.py`,
|
|
124
|
+
que é gitignored.
|
|
125
|
+
|
|
126
|
+
## `docs/`
|
|
127
|
+
|
|
128
|
+
Notas de pesquisa, não documentação de usuário: `integracao-sandbox-{stripe,pagseguro,asaas}.md`
|
|
129
|
+
levantam as particularidades de cada API (credenciais, sandbox, formato de webhook) e
|
|
130
|
+
marcam com ⚠️ o que **não** foi confirmado na fonte oficial. `plano-testes-sandbox.md`
|
|
131
|
+
descreve uma suíte contra sandbox real, ainda não implementada. Ao implementar PagBank ou
|
|
132
|
+
Asaas, esses arquivos são o ponto de partida — e os itens ⚠️ precisam de validação antes de
|
|
133
|
+
virarem código.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Davi Rafacho
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|