This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
django-oscar-api-checkout is a Django extension that provides a flexible checkout API for django-oscar e-commerce framework. It offers a pluggable payment methods interface with support for multiple payment processors.
IMPORTANT: All development commands MUST be run inside Docker via docker compose due to the PostgreSQL dependency. The project requires a running PostgreSQL database for tests and migrations.
# Run all tests with coverage (via Docker)
docker compose run --rm test uv run python manage.py test oscarapicheckout -v 2 --buffer --noinput
# Run tests via tox (multiple Python/Django versions) - RECOMMENDED
docker compose run --rm test uv run tox
# Run tests for specific environment
docker compose run --rm test uv run tox -e py312-django420-drf316-oscar40
# Run tests for multiple specific environments
docker compose run --rm test uv run tox -e py312-django420-drf316-oscar40,py312-django420-drf316-oscar41# Type check main package and sandbox (via Docker)
docker compose run --rm test uv run mypy oscarapicheckout sandbox# Format code with ruff (via Docker)
docker compose run --rm test uv run ruff format .
# Run pre-commit hooks (via Docker)
docker compose run --rm test make test_precommit# Generate migrations (via Docker)
docker compose run --rm test uv run python manage.py makemigrations
# Run migrations (via Docker)
docker compose run --rm test uv run python manage.py migrate# Generate and compile translation files (via Docker)
docker compose run --rm test make translationsThe docker-compose.yml file defines:
postgres: PostgreSQL database servicetest: Python test environment with mounted code volume
The checkout process follows this state machine:
-
Order Creation (
views.CheckoutView.post):- Validates checkout data via
CheckoutSerializer - Freezes the basket
- Creates order with status
ORDER_STATUS_PENDING("Pending") - Records payment methods in session
- Returns order + payment states
- Validates checkout data via
-
Payment State Management (
utils.py):- Payment states are pickled and stored in session under
CHECKOUT_PAYMENT_STEPS - Each payment method tracks amount and status
- Status flow:
PENDING→COMPLETE/DECLINED→CONSUMED
- Payment states are pickled and stored in session under
-
Order Status Transitions (
utils._update_order_status):- All payments
COMPLETE→ Order becomesAUTHORIZED, payments markedCONSUMED - Any payment
DECLINED→ Order becomesPAYMENT_DECLINED - Payment declined orders can be updated (not recreated) via
utils.OrderUpdater
- All payments
-
Payment Method Plugins (
methods.py):- Base class:
PaymentMethod[T: PaymentMethodData] - Subclass
_record_payment()to implement payment logic - Built-in:
Cash(immediate payment),PayLater(deferred payment) - Plugins return
PaymentStatusobjects (Complete, Declined, Deferred, FormPostRequired)
- Base class:
Serializers (serializers.py):
CheckoutSerializer: Main checkout form, extendsoscarapi.serializers.checkout.CheckoutSerializerPaymentMethodsSerializer: Dynamic serializer built fromsettings.API_ENABLED_PAYMENT_METHODSDiscriminatedUnionSerializer: Handles polymorphic payment method data (discriminated union pattern)SignedTokenRelatedField: Server-signed tokens for baskets/orders to verify client permissions
Views (views.py):
PaymentMethodsView: Lists available payment methods for current user (GET)CheckoutView: Places order and begins payment collection (POST)PaymentStatesView: Checks payment status for pending order (GET)CompleteDeferredPaymentView: Completes payment for "Pay Later" orders (POST)
Payment States (states.py):
Complete: Payment successfully authorized/capturedDeclined: Payment rejectedDeferred: Payment deferred (e.g., "Pay Later")Consumed: Payment has been applied to an authorized orderFormPostRequired: Client must POST form to complete payment (returns form data)
Permissions (permissions.py):
Public: Available to all usersStaffOnly: Staff/admin onlyCustomerOnly: Non-staff only
Fraud Detection (fraud.py):
- Pluggable fraud rules via
settings.API_CHECKOUT_FRAUD_CHECKS - Built-in:
AddressVelocity(rate-limits orders by address) - Rules implement
FraudRuleprotocol withvalidate()method
Payment methods configured in Django settings:
API_ENABLED_PAYMENT_METHODS = [
{
'method': 'oscarapicheckout.methods.Cash',
'permission': 'oscarapicheckout.permissions.StaffOnly',
'method_kwargs': {},
'permission_kwargs': {},
},
]Required order status pipeline:
ORDER_STATUS_PENDING = 'Pending'
ORDER_STATUS_PAYMENT_DECLINED = 'Payment Declined'
ORDER_STATUS_AUTHORIZED = 'Authorized'Payment Method Implementation:
- Subclass
PaymentMethod[YourDataType] - Define
nameandcodeclass attributes - Implement
_record_payment()returningPaymentStatus - Create/allocate/debit payment
Sourceviaget_source() - Record payment events via
make_authorize_event(),make_debit_event()
Handling Declined Orders:
- Declined orders keep the same order number but reset lines/discounts/vouchers
- Basket is thawed and restored to session
- Use
utils.OrderUpdater.update_order()to retry (never create new order)
Testing:
- Test base class:
oscarapicheckout.tests.base.BaseTest - Provides
create_product(),create_basket_with_product() - Uses sandbox settings with PostgreSQL backend
Project uses strict mypy configuration:
- Plugins:
mypy_django_plugin,mypy_drf_plugin - Migrations and tests ignore type errors
- Untyped imports followed for
oscar,oscarapi,drf_recaptcha
The sandbox/ directory contains a test Django project:
- Custom
Ordermodel insandbox.order.models - Settings in
sandbox/settings.py - Credit card example in
sandbox/creditcards/