Metadata-Version: 2.4
Name: django-gocardless-billing
Version: 0.1.1
Summary: Reusable Django app for GoCardless Direct Debit billing: webhooks, billing requests, signals, and admin.
Author: Visian Systems
License-Expression: MIT
Project-URL: Homepage, https://gitlab.com/visian/infra-structure/django-gocardless-billing
Project-URL: Repository, https://gitlab.com/visian/infra-structure/django-gocardless-billing
Project-URL: Issues, https://gitlab.com/visian/infra-structure/django-gocardless-billing/-/issues
Keywords: django,gocardless,billing,subscription,saas,payments,direct-debit,bacs
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: Django>=4.2
Requires-Dist: gocardless-pro>=3.6.0
Requires-Dist: requests>=2.28
Provides-Extra: celery
Requires-Dist: celery>=5.3; extra == "celery"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-django; extra == "dev"
Requires-Dist: factory-boy; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"

# django-gocardless-billing

A reusable Django app for GoCardless Direct Debit billing. Handles webhook intake,
idempotency, async Celery processing, Billing Request flows, subscriptions, and
Django signals — so each of your SaaS projects gets UK Direct Debit billing in
minutes, not days.

Companion package to [`django-stripe-billing`](https://pypi.org/project/django-stripe-billing/).

**Full configuration guide (env vars, Dashboard, production, Celery):** see **[CONFIGURATION.md](CONFIGURATION.md)**.

## Features

- **Billing Request + Flow** — `create_billing_request_flow()` (instant first payment + BACS mandate)
- **Subscriptions** — `create_subscription_for_mandate()` after mandate activation
- **Webhook receiver** — signature verification, idempotency, audit trail
- **Async processing** — optional Celery task with exponential backoff
- **Django signals** — connect custom logic per event type without touching the package
- **Outgoing webhooks** — Zapier / Make / n8n integration per event type
- **Admin** — `GoCardlessWebhookEvent` with status badges
- **Python 3.10+**, **Django 4.2+**

## Quick Start

### 1. Install

```bash
pip install django-gocardless-billing
# Optional: async webhook processing
pip install django-gocardless-billing[celery]
```

### 2. Add to INSTALLED_APPS

```python
INSTALLED_APPS = [
    ...
    'django_gocardless_billing',
]
```

### 3. Configure

```python
GOCARDLESS_BILLING = {
    'GOCARDLESS_ACCESS_TOKEN': env('GOCARDLESS_ACCESS_TOKEN_SANDBOX'),
    'GOCARDLESS_WEBHOOK_SECRET': env('GOCARDLESS_WEBHOOK_SECRET_SANDBOX'),
    'GOCARDLESS_MODE': 'sandbox',  # 'sandbox' or 'live'
    'ENVIRONMENT': env('ENVIRONMENT', default='production'),
    'SUCCESS_URL': 'https://myapp.com/gocardless/success/',
    'EXIT_URL': 'https://myapp.com/subscribe/',
    'PROJECT_SLUG': 'my_saas',
    'PLAN_RESOLVER': 'myapp.billing.resolve_gocardless_plan',
    'OUTGOING_WEBHOOK_URLS': {
        'gocardless.payments.confirmed': env('WEBHOOK_GC_PAYMENT_CONFIRMED', ''),
        'gocardless.payments.failed': env('WEBHOOK_GC_PAYMENT_FAILED', ''),
    },
}
```

> **Zero-config migration**: If you already have top-level `GOCARDLESS_ACCESS_TOKEN`,
> `GOCARDLESS_WEBHOOK_SECRET`, `GOCARDLESS_MODE`, or `REDIRECT_DOMAIN`, the package
> reads them automatically.

### 4. Implement PLAN_RESOLVER

```python
# myapp/billing.py
def resolve_gocardless_plan(plan_id: str) -> dict:
  return {
      'amount': 1999,           # pence
      'currency': 'GBP',
      'interval_unit': 'monthly',  # or 'yearly'
      'name': 'Pro Monthly',
      'description': 'Pro Monthly — first payment',
  }
```

### 5. Add URL

```python
urlpatterns = [
    path('webhooks/', include('django_gocardless_billing.urls')),
    # Exposes: POST /webhooks/gocardless/
]
```

### 6. Run migrations

```bash
python manage.py migrate
```

---

## Creating a Billing Request Flow

```python
from django_gocardless_billing.checkout import create_billing_request_flow

billing_request, flow = create_billing_request_flow(
    user=request.user,
    plan_id='pro_monthly',
    customer_id=profile.gocardless_customer_id or None,
    on_customer_created=lambda cid: save_customer_id(profile, cid),
)
return redirect(flow.authorisation_url, code=303)
```

---

## Connecting Business Logic via Signals

```python
from django.dispatch import receiver
from django_gocardless_billing.signals import payment_confirmed, payment_failed

@receiver(payment_confirmed)
def on_payment_confirmed(sender, event, **kwargs):
    metadata = event.get('metadata') or {}
    plan_id = metadata.get('plan_id')
    # Update UserProfile, grant access, send emails, etc.

@receiver(payment_failed)
def on_payment_failed(sender, event, **kwargs):
    ...
```

Register receivers in your app's `AppConfig.ready()`.

---

## Available Signals

| Signal | GoCardless event |
| ------ | ---------------- |
| `billing_request_fulfilled` | `billing_requests.fulfilled` |
| `mandate_active` | `mandates.active` |
| `payment_confirmed` | `payments.confirmed` |
| `payment_failed` | `payments.failed` |
| `subscription_created` | `subscriptions.created` |
| `subscription_cancelled` | `subscriptions.cancelled` / `finished` |

Each signal receives `event` (a plain dict) in `kwargs`.

---

## Architecture

```text
django_gocardless_billing/
├── conf.py           # GOCARDLESS_BILLING settings + legacy fallback
├── client.py         # GoCardless Pro SDK client
├── models.py         # GoCardlessWebhookEvent
├── signals.py        # Django signals
├── webhooks.py       # HandlerRegistry + built-in handlers
├── checkout.py       # create_billing_request_flow()
├── subscriptions.py  # create_subscription_for_mandate()
├── plans.py          # PLAN_RESOLVER integration
├── profile.py        # Direct Debit profile readiness
├── tasks.py          # Celery / sync processing
├── views.py          # HTTP webhook receiver
└── urls.py           # path('gocardless/', ...)
```

See [CONFIGURATION.md](CONFIGURATION.md) for full setup (sandbox/live, webhooks, production).
See [INTEGRATION.md](INTEGRATION.md) for migration paths from in-app GoCardless code.

## Development

```bash
cd django-gocardless-billing
pip install -e ".[dev]"
pytest
```

## License

MIT
