Files
Salon/docs/execplans/payments-moyasar.md
T

139 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Payments Integration (Moyasar, Webhooks, Idempotency)
This ExecPlan is a living document. The sections `Progress`, `Surprises & Discoveries`, `Decision Log`, and `Outcomes & Retrospective` must be kept up to date as work proceeds.
The requirements for ExecPlans live in `PLANS.md` at the repository root. This document must be maintained in accordance with that file.
## Purpose / Big Picture
After this change, the backend can create Moyasar payments, track their state transitions, and reconcile them via webhooks in an idempotent and auditable way. A user can create a booking payment and see it progress from initiated to paid or failed. You can see it working by creating a payment, receiving a webhook callback that marks it as paid, and observing the payment record transition with a recorded provider reference and idempotency key.
## Progress
- [x] (2026-02-28 14:35Z) Created ExecPlan for payments integration (Moyasar + webhooks + idempotency).
- [x] (2026-02-28 15:05Z) Inspected payments models/endpoints and aligned naming with Moyasar scaffolding.
- [x] (2026-02-28 15:20Z) Defined payment state model extensions and idempotency tracking fields.
- [x] (2026-02-28 15:40Z) Implemented payment creation service and API endpoint with provider gateway.
- [x] (2026-02-28 15:55Z) Implemented webhook endpoint with secret verification and status mapping.
- [x] (2026-02-28 16:10Z) Added tests for creation, idempotency, and webhook reconciliation.
- [x] (2026-02-28 16:20Z) Updated `docs/risks.md` to close payment integration gaps once tested.
## Surprises & Discoveries
- Observation: The payments gateway needed an HTTP client dependency, so `requests` was added to backend requirements.
Evidence: `ModuleNotFoundError: No module named 'requests'` when running migrations after adding gateway calls.
## Decision Log
- Decision: Model payment state transitions as explicit status changes with audit-friendly timestamps.
Rationale: Payment flows must be auditable and deterministic under retries.
Date/Author: 2026-02-28, Codex
- Decision: Require idempotency keys on payment creation requests.
Rationale: Prevents duplicate charges when clients retry.
Date/Author: 2026-02-28, Codex
- Decision: Use a dedicated webhook endpoint with signature verification.
Rationale: Ensures authenticity of provider callbacks and protects state integrity.
Date/Author: 2026-02-28, Codex
- Decision: Store provider payloads and webhook payloads on the payment record for auditability.
Rationale: Helps trace payment transitions without introducing a separate event table yet.
Date/Author: 2026-02-28, Codex
## Outcomes & Retrospective
Payment creation, idempotency handling, and webhook reconciliation are implemented for Moyasar. Tests cover creation, idempotency, and webhook status transitions, reducing the largest Phase 1 reliability gap. Refund/capture operations remain future work if required.
## Context and Orientation
Payments live in `backend/apps/payments/` with current models and API endpoints. The system currently stores payment records but does not integrate with Moyasar or reconcile webhooks. Booking flows live in `backend/apps/bookings/` and should link to payments. The project standards require business logic in services and predictable error responses.
## Plan of Work
First, review existing payment models and endpoints to avoid breaking field names. Identify whether `Payment` includes a reference to `Booking`, a `provider_reference`, and a status field. If any are missing, add them along with timestamps for `initiated_at`, `paid_at`, and `failed_at`. Create a migration for the new fields. Ensure status choices include at least `initiated`, `pending`, `paid`, `failed`, and `refunded` if refunds are in scope.
Next, introduce idempotency tracking. Add a `idempotency_key` field to the payment model (unique, indexed) and validate that payment creation requests require it. If a request repeats with the same key, return the existing payment without creating a new provider charge.
Then, implement the Moyasar payment creation service in `backend/apps/payments/services.py`. The service should build the provider request using amount, currency, description, and return URLs, and persist the `provider_reference` (payment id returned by Moyasar). Store the full provider response in a JSON field for audit if available.
Add a dedicated API endpoint for payment creation in `backend/apps/payments/views.py` and `backend/apps/payments/urls.py`. It should:
- Require authentication.
- Validate booking ownership and amount.
- Require `idempotency_key`.
- Call the service to create the provider payment.
- Return the payment record plus any provider redirect URL if applicable.
Then, implement the webhook endpoint (`/api/payments/webhook/`) with signature verification using Moyasars secret. It should parse the event, locate the payment by `provider_reference`, apply an idempotent state transition, and record timestamps. Unknown events should be logged but return 200 to avoid retries if possible.
Finally, add tests in `backend/apps/payments/tests/`:
- Creating a payment succeeds and stores provider reference.
- Creating with the same idempotency key returns the original record.
- Webhook for `paid` updates status and timestamp.
- Webhook with invalid signature is rejected.
- Webhook is idempotent (replay does not change state or duplicate logs).
Update `docs/risks.md` to mark payment integration gaps as addressed.
## Concrete Steps
Run these commands from the repository root (`/home/m7md/kshkool/Salon`).
1. Inspect payments models and endpoints.
- Read `backend/apps/payments/models.py`, `backend/apps/payments/views.py`, and `backend/apps/payments/serializers.py`.
2. Add fields for provider reference, status timestamps, and idempotency.
- Update `backend/apps/payments/models.py` and create a migration.
- Run:
python3 backend/manage.py makemigrations payments
3. Implement services and endpoints.
- Add `backend/apps/payments/services.py`.
- Update serializers and views accordingly.
4. Add webhook endpoint and signature verification.
- Update `backend/apps/payments/urls.py` and `backend/apps/payments/views.py`.
5. Add tests.
- Create `backend/apps/payments/tests/test_payments_flow.py`.
6. Run tests.
- Backend:
source venv/bin/activate
cd backend
python3 -m pytest
## Validation and Acceptance
- Creating a payment with a new idempotency key returns HTTP 201 and a provider reference.
- Creating the same payment with the same idempotency key returns HTTP 200/201 with the original payment (no new provider request).
- A valid webhook updates the payment status to `paid` and sets `paid_at`.
- An invalid webhook signature returns HTTP 400/401 and does not mutate data.
- `python3 -m pytest` passes with the new payments tests.
## Idempotence and Recovery
Payment creation is safe to retry with idempotency keys. Webhook processing is idempotent and can be replayed safely. If a payment status change is applied incorrectly, it can be corrected manually via admin and will be documented in audit fields.
## Artifacts and Notes
Example idempotency pattern:
existing = Payment.objects.filter(idempotency_key=key).first()
if existing:
return existing
Example overlap-safe webhook logic:
if payment.status == PaymentStatus.PAID:
return
payment.mark_paid()
## Interfaces and Dependencies
- `backend/apps/payments/models.py` must include fields: `provider_reference`, `idempotency_key`, `status`, `initiated_at`, `paid_at`, `failed_at`, and (optionally) `provider_payload` (JSON).
- `backend/apps/payments/services.py` must define `create_payment_for_booking(booking, idempotency_key, request_data)` and `verify_webhook_signature(request)`.
- `backend/apps/payments/views.py` must expose `PaymentCreateAPIView` and `payment_webhook` with signature verification.
Plan Maintenance Note: Created on 2026-02-28 to implement Moyasar payments with idempotency and webhook reconciliation as the next Phase 1 reliability milestone.
Plan Maintenance Note (Update): Marked steps complete and recorded dependency and audit decisions after implementing payments and tests on 2026-02-28.