Almost automatic integration between django-plans and django-payments. This will add payment buttons to the order page and automatically confirm the Order after the payment. Optionally, it can return the corresponding order when a payment is refunded.
Documentation
The full documentation is at https://django-plans-payments.readthedocs.io.
Quickstart
Install and configure django-plans and django-payments apps. Capture mode is not yet supported, so PAYMENT_VARINANTS with 'capture': False will not get confirmed.
Install Django plans payments:
pip install django-plans-payments
Add it to your INSTALLED_APPS, before the plans:
INSTALLED_APPS = (
...
'related_admin',
'plans_payments',
'plans',
...
)
Add Django plans_payments to the URL patterns:
urlpatterns = [
...
url(r'^plans-payments', include('plans_payments.urls')),
...
]
Set django-plans settings and set model to:
PAYMENT_MODEL = 'plans_payments.Payment'
Charge-attempt idempotency
CreatePaymentView refuses to fire duplicate live charge attempts: a request while a previous payment is still in flight (or just captured) redirects to that payment instead of creating a twin, and a request right after a decline waits out a short cooldown, because banks read rapid-fire retries as fraud. Both windows look across all the user’s orders and are configurable:
PLANS_PAYMENTS_JOIN_IN_FLIGHT_SECONDS = 180 # 0 disables joining
PLANS_PAYMENTS_DECLINE_COOLDOWN_SECONDS = 60 # 0 disables the cooldown
Customer IP address
Customer IP address is stored in Payment model and used for some payment providers (i.e. PayU). For security reasons django-plans-payments does acquire the IP only from request REMOTE_ADDR parameter. If you are behind proxy, you will need to setup some mechanism to populate this variable from HTTP_X_FORWARDED_FOR parameter. The suggested solution is to use django-httpforwardedfor or django-xff application for that.
Running Tests
Does the code actually work?
source <YOURVIRTUALENV>/bin/activate (myenv) $ pip install tox (myenv) $ tox
Credits
Tools used in rendering this package:
History
2.3.0 (2026-08-19)
make CreatePaymentView idempotent: an attempt while a previous payment is in flight joins it instead of creating a twin, and an attempt right after a decline waits out a short cooldown (banks read rapid-fire retries as fraud). Configurable via PLANS_PAYMENTS_JOIN_IN_FLIGHT_SECONDS (default 180) and PLANS_PAYMENTS_DECLINE_COOLDOWN_SECONDS (default 60); 0 disables.
fix create_payment_object crashing with BillingInfo.DoesNotExist for users without saved billing info – billing fields fall back to empty strings.
fix renew_accounts charging automatic renewals for free plans: an armed RecurringUserPlan surviving a switch to a free plan took the customer’s money and extended nothing. The renewal is skipped with a warning instead.
2.2.0 (2026-07-23)
add Payment.invalidate_renew_token() - payment providers call it when the gateway reports the stored recurring token as permanently dead (e.g. PayU INVALID_TOKEN). The token is marked unverified so renewal tasks stop selecting the account and get_renew_token() returns None; the new plans_payments.signals.renew_token_invalidated signal lets host apps prompt the user to update their payment method.
add a pre-commit config (black/isort/flake8 at line length 119 plus hygiene hooks) and run it in CI, so local and CI lint cannot drift.
2.1.0 (2026-07-21)
Don’t disable token_verified on an unsuccessful renewal attempt, so a transient payment failure no longer permanently disarms automatic renewals
Add get_renew_data() and pass provider metadata (e.g. Stripe customer_id) through set_renew_token(**kwargs)
Add migration for the new django-payments PaymentStatus.CANCELLED (choices-only, database no-op)
Tests: drop the unused pytz dependency, satisfy current black
2.0.2 (2025-05-29)
fix the release
2.0.1 (2025-05-29)
fix the release
2.0.0 (2025-05-29)
Implement the wallet logic
Drop support for Python 3.8, Django 4.1
Add support for Django 5.2
don’t obscure Exceptions by catching them
1.5.0 (2025-02-28)
Drop support for Python 3.7
Add support for Python 3.13, Django 5.1
fix the wrong assumption that Payment.extra_data["response"] contains a "transactions" key
1.4.1 (2024-04-24)
do not check whether a confirmed payment of a completed order is left anymore
1.4.0 (2024-04-15)
migrate to RecurringUserPlan.renewal_triggered_by
add renewal_triggered_by parameter to Payment.set_renew_token
deprecate automatic_renewal parameter of Payment.set_renew_token; use renewal_triggered_by parameter instead
deprecate None value of renewal_triggered_by parameter of Payment.set_renew_token; set an AbstractRecurringUserPlan.RENEWAL_TRIGGERED_BY instead
1.3.1 (2024-04-15)
fix typo in payment description
1.3.0 (2024-04-12)
add optional returning orders when payments are refunded
1.2.2 (2023-12-20)
add change_reason for django-simple-history
1.2.1 (2023-12-19)
specify sender=Payment for change_payment_status receiver
1.2.0 (2023-10-16)
bugfix release (fix prevoius bad release)
1.1.3 (2023-10-15)
add some indexes to Payment model
1.1.2 (2023-03-29)
reword Payment description to ommit word “Subscribtion” which might raise warnings for banks/card providers
1.1.1 (2023-01-27)
correction release, include wheel update, correctly rebase to master
1.1.0 (2023-01-27)
Fix transaction fee double counting
1.0.1 (2022-12-09)
Fix migrations
1.0.0 (2022-12-08)
Recurring payments functionality
0.2.0 (2018-08-05)
Payment process without capturing should work
Automatic buttons generation
0.1.0 (2018-07-23)
First release on PyPI.
Release files for django-plans-payments 2.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_plans_payments-2.3.0.tar.gz | 26.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_plans_payments-2.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 49.5 kB
Release files / django_plans_payments-2.3.0.tar.gz
| Download URL | django_plans_payments-2.3.0.tar.gz |
|---|---|
| Size | 26.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c24f02df50c5a29120417ad484711b69e28042724b67c90a2b9735bb6d64e274
|
|
BLAKE2b-256 checksum How to use checksums |
e82900af68a7df2a03fa29708d060d575fb5f33f91c2d488f282f899dfa9e333
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / django_plans_payments-2.3.0-py3-none-any.whl
| Download URL | django_plans_payments-2.3.0-py3-none-any.whl |
|---|---|
| Size | 22.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5df2142a1c7abcee73b4b4ecae90027227471df919f1e7f05f3346c5e3249475
|
|
BLAKE2b-256 checksum How to use checksums |
60eebfd55846859662c8cc8ba5774d6732ec864921f6265cf6e4a35df2e54d52
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|