From d9767ff0a70fdff5a177411306229fc52e239c32 Mon Sep 17 00:00:00 2001 From: mohammad Date: Sat, 28 Feb 2026 12:47:59 +0300 Subject: [PATCH] Add payments ExecPlan and set as active --- AGENTS.md | 3 +- PLANS.md | 2 +- docs/execplans/payments-moyasar.md | 134 +++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 docs/execplans/payments-moyasar.md diff --git a/AGENTS.md b/AGENTS.md index 6d449e5..2a65edb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -61,7 +61,8 @@ Build a reliable, maintainable salon booking platform with Django (backend) and - Avoid destructive git commands unless explicitly asked. - Update `docs/risks.md` when adding or closing a significant gap. - Keep README instructions current when tooling changes. +- Prefer feature branches for significant work; commit early with clear summary messages. # ExecPlans -When writing complex features or significant refactors, use an ExecPlan (as described in PLANS.md) from design to implementation. The active ExecPlan is `docs/execplans/booking-integrity.md`. +When writing complex features or significant refactors, use an ExecPlan (as described in PLANS.md) from design to implementation. The active ExecPlan is `docs/execplans/payments-moyasar.md`. diff --git a/PLANS.md b/PLANS.md index d7ca6a7..4e4b8e6 100644 --- a/PLANS.md +++ b/PLANS.md @@ -4,7 +4,7 @@ This document describes the requirements for an execution plan ("ExecPlan"), a d ## Active ExecPlans -The current execution plan is `docs/execplans/booking-integrity.md`. It focuses on booking integrity (availability checks, staff schedules, overlap prevention) as the next Phase 1 reliability milestone. Keep it updated in line with the requirements below. +The current execution plan is `docs/execplans/payments-moyasar.md`. It focuses on Moyasar payments integration with webhooks and idempotency as the next Phase 1 reliability milestone. Keep it updated in line with the requirements below. ## How to use ExecPlans and PLANS.md diff --git a/docs/execplans/payments-moyasar.md b/docs/execplans/payments-moyasar.md new file mode 100644 index 0000000..9891388 --- /dev/null +++ b/docs/execplans/payments-moyasar.md @@ -0,0 +1,134 @@ +# 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). +- [ ] Inspect current payments models, endpoints, and any Moyasar scaffolding to align naming. +- [ ] Define payment state model and idempotency tracking. +- [ ] Implement payment creation service and API endpoint. +- [ ] Implement webhook endpoint with signature verification. +- [ ] Add tests for creation, idempotency, and webhook reconciliation. +- [ ] Update `docs/risks.md` to close payment integration gaps once tested. + +## Surprises & Discoveries + +- Observation: None yet. + Evidence: No implementation work has started. + +## 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 + +## Outcomes & Retrospective + +Planned changes will provide end-to-end payment creation, reconciliation via webhooks, and idempotency protections, filling the largest Phase 1 reliability gap. + +## 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 Moyasar’s 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.