Files
clinicpro/docs/api/settlement.md
T
hamedandClaude Opus 4.8 61ac775175 perf(settlement,rating): paginate 3 unbounded list endpoints (M10-M12)
- M10 GET /settlement: was unbounded; add page/limit + countByUser + data.meta.
- M11 GET /admin/comments/pending: paginate findPending + countPending.
- M12 GET /comments/{doctor}: paginate the fetch-joined roots query via
  Paginator(fetchJoinCollection) + countApprovedRootsByDoctor.

All keep the existing { data: { data: [...] } } envelope and add data.meta
(backward compatible). Default limit 50 / max 100.

Regressions: SettlementListPaginationTest, CommentPaginationTest (both fail
without the limits). Also de-flaked SendCodeMobileRateLimitTest (randomised the
IP block so the persistent per-IP limiter buckets don't accumulate across runs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 20:36:41 +03:30

9.7 KiB

Settlement & Wallet API

Prefix: /api/v1/wallet, /api/v1/settlement


GET /api/v1/wallet/balance

Get authenticated user's wallet balance.

Permission: AUTH

Response 200

{
  "success": true,
  "data": {
    "balance_rials": 2500000,
    "recent_transactions": [
      {
        "uuid": "...",
        "type": "credit",
        "amount_rials": 500000,
        "balance_after": 2500000,
        "description": "دریافت از نوبت شماره ...",
        "created_at": 1717000000
      }
    ]
  }
}

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token

GET /api/v1/wallet/transactions

Get wallet transaction history for the authenticated user (paginated, newest first).

Permission: AUTH

Query Parameters

پارامتر نوع توضیح
page int شماره صفحه (پیش‌فرض ۱)
limit int تعداد در هر صفحه (پیش‌فرض ۵۰، حداکثر ۱۰۰)

Response 200

{
  "success": true,
  "data": {
    "data": [
      {
        "uuid": "...",
        "type": "credit",
        "amount_rials": 500000,
        "balance_after": 2500000,
        "description": "دریافت از نوبت",
        "created_at": 1717000000
      },
      {
        "uuid": "...",
        "type": "debit",
        "amount_rials": 200000,
        "balance_after": 2300000,
        "description": "تسویه‌حساب",
        "created_at": 1716900000
      }
    ],
    "meta": { "totalRecords": 124, "totalPages": 3, "currentPage": 1 }
  }
}

Transaction Type Values:

Value Description
credit Money added to wallet
debit Money removed from wallet

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token

POST /api/v1/settlement

Request a settlement (withdrawal from wallet to bank account).

Permission: AUTH

Request Body (application/json)

{
  "amount_rials": 1000000,
  "iban_id": "iban-uuid-..."
}
Field Type Required Description
amount_rials integer Amount to withdraw (must be ≤ wallet balance)
iban_id string شناسه‌ی یکی از شباهای تأییدشده‌ی نماینده (از GET /api/v1/representation/mebank_account[].id)

شبای انتخابی به‌صورت snapshot (iban, bank_name, owner_name) داخل خود رکورد تسویه ذخیره می‌شود؛ حذف بعدی شبا در پروفایل، این رکورد را تغییر نمی‌دهد. مبلغ همان لحظه‌ی ثبت از کیف‌پول کسر (debit) می‌شود.

Response 201

{
  "success": true,
  "data": {
    "uuid": "settle-uuid-...",
    "amount_rials": 1000000,
    "status": "pending",
    "bank_account": {
      "iban": "IR...",
      "bank_name": "بانک ملت",
      "owner_name": "علی احمدی"
    },
    "created_at": 1717000000
  }
}

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_VALIDATION_001 422 مبلغ نامعتبر/بیش از موجودی، یا شبا تأییدنشده/نامعتبر (field: iban_id)
ERR_VALIDATION_002 422 iban_id ارسال نشده (field: iban_id)
ERR_CONFLICT_001 422 موجودی کافی نیست

GET /api/v1/settlement

Get authenticated user's settlement requests (paginated, newest first).

Permission: AUTH

صفحه‌بندی: ?page و ?limit (پیش‌فرض ۵۰، حداکثر ۱۰۰). پاسخ علاوه بر data.data یک data.meta (totalRecords/totalPages/currentPage) دارد؛ پاکت قبلی دست‌نخورده است.

Response 200

{
  "success": true,
  "data": [
    {
      "uuid": "...",
      "amount_rials": 1000000,
      "status": "pending",
      "note": null,
      "created_at": 1717000000,
      "processed_at": null
    }
  ]
}

Settlement Status Values:

Value Description
pending Awaiting admin review
approved Approved, payment sent
rejected Rejected by admin

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token

GET /api/v1/settlement/{uuid}

Get a single settlement.

Permission: AUTH — must be the owner or ROLE_ADMIN

Response 200

Settlement object with full details including bank_account.

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_FORBIDDEN_001 403 Not the owner
ERR_NOT_FOUND_001 404 Settlement not found

POST /api/v1/settlement/{uuid}/approve

Approve a settlement request. Marks it as paid and debits the wallet.

Permission: ROLE_ADMIN

Path Parameters

Param Type Description
uuid string (UUID) Settlement UUID

Request Body (application/json)

{
  "note": "پرداخت شد — شناسه پیگیری: 123456"
}
Field Type Required
note string

Response 200

Updated settlement object with status: "approved".

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_AUTH_006 403 Not admin
ERR_NOT_FOUND_001 404 Settlement not found
ERR_VALIDATION_001 422 Already processed

POST /api/v1/settlement/{uuid}/reject

Reject a settlement request. Returns the amount back to wallet.

Permission: ROLE_ADMIN

Request Body

{
  "note": "حساب بانکی نادرست است"
}
Field Type Required
note string

Response 200

Updated settlement object with status: "rejected".

Errors

Code HTTP Description
ERR_AUTH_001 401 Missing token
ERR_AUTH_006 403 Not admin
ERR_NOT_FOUND_001 404 Settlement not found
ERR_VALIDATION_002 422 Missing note

FinancialBreakdown (لاگ مالی)

علاوه بر تسویه‌حساب دستی، کیف‌پول نماینده به‌صورت خودکار از طریق CommissionService هنگام پرداخت موفقِ نوبت/اشتراک شارژ می‌شود (WalletTransaction credit). هر واریز یک ردیف FinancialBreakdown ثبت می‌کند که تفکیک کامل تراکنش (ناخالص، هزینه پیامک، مالیات، خالص، درصد و سهم پورسانت، سهم سیستم) را نگه می‌دارد. ثبت idempotent است (بر اساس payment_id). گزارش‌ها از طریق GET /api/v1/admin/financial-breakdowns و GET /api/v1/admin/financial-summary در دسترس‌اند — جزئیات در docs/api/admin.md.


رسید پرداخت و ثبت پرداخت نهایی (ROLE_ADMIN)

منطق کیف‌پول: مبلغ هنگام ثبت درخواست از کیف‌پول نماینده کسر (reserve/debit) می‌شود؛ رد آن را برمی‌گرداند (credit). تأیید و پرداختِ نهایی کیف‌پول را دوباره دست نمی‌زنند (جلوگیری از double-debit).

POST /file/upload/clinic_pro/settlement/receipt

آپلود تصویر رسید پرداخت. بدنه = محتوای خام فایل؛ هدر Content-Disposition: filename="...". Permission: ROLE_ADMIN

Response 200:

{ "success": true, "data": { "uuid": "...", "url": "/uploads/settlements/receipts/2026-06/...", "filename": "...", "filemime": "image/jpeg" } }

POST /api/v1/settlement/{uuid}/receipt

ذخیره‌ی رسید پرداخت بدون نهایی‌سازی. فقط روی تسویه‌ی approved؛ وضعیت تغییر نمی‌کند (همچنان approved). پس از این مرحله دکمه‌ی «تکمیل» در پنل فعال می‌شود. Permission: ROLE_ADMIN

Request Body:

{ "receipt": "/uploads/settlements/receipts/2026-06/..." }
Field Type Required Description
receipt string URL رسیدِ آپلودشده

Response 200: آبجکت تسویه (با receipt ذخیره‌شده، status: "approved").

Errors:

Code HTTP Description
ERR_NOT_FOUND_001 404 درخواست یافت نشد
ERR_VALIDATION_001 422 تسویه approved نیست
ERR_VALIDATION_002 422 receipt خالی (field: receipt)

POST /api/v1/settlement/{uuid}/paid

«تکمیل» — ثبت پرداخت نهایی. فقط روی تسویه‌ی approved. وضعیت → paid و receipt ذخیره می‌شود. کیف‌پول تغییر نمی‌کند (مبلغ هنگام ثبت درخواست کسر شده). پس از تکمیل، آن مبلغ دیگر قابل درخواست تسویه نیست. Permission: ROLE_ADMIN

Request Body:

{ "receipt": "/uploads/settlements/receipts/2026-06/..." }
Field Type Required Description
receipt string URL رسیدِ آپلودشده

Response 200: آبجکت تسویه (شامل receipt و status: "paid").

Errors:

Code HTTP Description
ERR_NOT_FOUND_001 404 درخواست یافت نشد
ERR_VALIDATION_001 422 تسویه approved نیست
ERR_VALIDATION_002 422 receipt خالی (field: receipt)