Metadata-Version: 2.4
Name: payment_infra
Version: 1.0.5
Summary: Reusable Django payment infrastructure with idempotency and webhook support
Author-email: "Offside Integrated Technology (Somtochukwu Emmanuel)" <offsideint@gmail.com>
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: django>=4.2
Requires-Dist: requests>=2.0
Requires-Dist: redis>=7.0.1
Requires-Dist: djangorestframework
Requires-Dist: python-dotenv
Requires-Dist: celery
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-django; extra == "dev"
Requires-Dist: pytest-mock; extra == "dev"
Requires-Dist: coverage; extra == "dev"
Dynamic: license-file

# payment_infra

A reusable Django package for payment orchestration with clean architecture, idempotency, provider abstraction, and webhook handling.

## Features

- Provider abstraction (`paystack`, `stripe`, `monnify`) through a shared interface.
- Idempotent payment initialization flow to avoid duplicate charges.
- Service-layer orchestration (`PaymentService`, `WebhookService`) for testable business logic.
- Django REST API endpoints for charge, verify, and webhook processing.
- Extensible architecture for adding new providers without changing API/service boundaries.

---

## Package Architecture

```text
payment_infra/
├── api/                        # DRF serializers, views, and URL routes
├── application/                # Use-cases/services + provider/repository interfaces
├── domain/                     # Core entities and domain models
├── infrastructure/
│   ├── idempotency/            # Idempotency persistence and locking
│   ├── providers/              # Gateway adapters (Paystack/Stripe/Monnify)
│   ├── repositories/           # Data access adapters
│   └── tasks/                  # Async task hooks (Celery)
└── migrations/                 # Django migrations
```

---

## Installation

### From package index

```bash
pip install payment_infra
```

### For local development

```bash
git clone https://github.com/0FFSIDE1/payment_infra.git
cd payment_infra
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

---

## Quick Start in a Django Project

### 1) Add apps

```python
INSTALLED_APPS = [
    # ...
    "rest_framework",
    "payment_infra",
]
```

### 2) Include URLs

```python
from django.urls import include, path

urlpatterns = [
    # ...
    path("payments/", include("payment_infra.api.urls")),
]
```

### 3) Configure provider settings

Set `DJANGO_PAYMENTS_PROVIDER` to one of:

- `paystack`
- `stripe`
- `monnify`

Provider-specific settings:

#### Paystack

- `PAYSTACK_SECRET_KEY`
- `PAYSTACK_PUBLIC_KEY`
- `PAYSTACK_BASE_URL` (optional)
- `PAYSTACK_CALLBACK_URL`

#### Stripe

- `STRIPE_SECRET_KEY`
- `STRIPE_PUBLIC_KEY`
- `STRIPE_BASE_URL` (optional, defaults to `https://api.stripe.com/v1`)
- `STRIPE_WEBHOOK_SECRET`

#### Monnify

- `MONNIFY_API_KEY`
- `MONNIFY_SECRET_KEY`
- `MONNIFY_CONTRACT_CODE`
- `MONNIFY_PUBLIC_KEY` (optional)
- `MONNIFY_BASE_URL` (optional)

Common runtime settings:

- `DJANGO_SECRET_KEY`
- `REDIS_URL`
- `CACHE_BACKEND`

### 4) Run migrations

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

---

## API Usage

With URLs mounted at `/payments/`:

- `POST /payments/paystack/charge/`
- `GET /payments/paystack/verify/<reference>/`
- `POST /payments/webhooks/`

### Example: initialize charge

```bash
curl -X POST http://localhost:8000/payments/paystack/charge/ \
  -H "Content-Type: application/json" \
  -d '{
    "email": "customer@example.com",
    "amount": "1000.00",
    "currency": "NGN",
    "idempotency_key": "trx-20260411103000-abc123",
    "callback_url": "https://example.com/payment/callback"
  }'
```

### Example: verify payment

```bash
curl -X GET "http://localhost:8000/payments/paystack/verify/<reference>/"
```

---

## Programmatic Usage

```python
from decimal import Decimal
from payment_infra.infrastructure.providers.registry import get_payment_service

service = get_payment_service()

result = service.process_payment(
    email="customer@example.com",
    amount=Decimal("1000.00"),
    currency="NGN",
    idempotency_key="trx-20260411103000-abc123",
    metadata={"callback_url": "https://example.com/payment/callback"},
)
```

---

## Testing

Run all tests:

```bash
pytest
```

Run only non-integration tests:

```bash
pytest -m "not integration"
```

---

## Security Notes

- Always use HTTPS callback/webhook URLs in production.
- Keep provider secret keys in environment variables (never commit them).
- Verify webhook signatures before processing events.
- Use unique idempotency keys per client request to prevent duplicate processing.

---

## Contributing

1. Create a feature branch.
2. Add/modify tests for changes.
3. Run `pytest` locally.
4. Open a pull request.

---

## License

MIT — see [`LICENSE`](LICENSE).
