Files
docs/business/BUSINESS-02-PAYMENT-FINANCE.md
T
masoodafar-web 1b04ba5326 docs: convert all ASCII charts to Mermaid diagrams
Converted 40+ ASCII art diagrams across 12 files to Mermaid:
- flowchart TD/LR for process flows and architecture
- erDiagram for entity relationships
- graph TD for tree structures (binary tree, categories)
- gantt for roadmap sprints

Files: BUSINESS-01 to 05, TECH-01/03/04/05, OVERVIEW-01/02/05
Directory tree structures kept as plain code blocks (Mermaid N/A)
2026-02-18 23:36:39 +03:30

7.0 KiB
Raw Blame History

💰 سیستم مالی، پرداخت و درگاه‌ها

منابع ادغام‌شده: payment-gateway.md, payment-architecture-pyms.md, daya-loan-integration.md, manual-payment-system.md, discount-shop-business.md
آخرین بروزرسانی: اسفند ۱۴۰۴


۱. معماری کلی مالی

flowchart TD
    subgraph GATEWAYS["درگاه‌ها"]
        ZP["ZarinPal\nIPG"]
        DL["Daya Loan\nAPI"]
        MP["Manual Pay\nCard2Card"]
        DW["Discount Wallet\nInternal"]
    end

    ZP --> PYMS["PYMS — Payment Service\ngRPC ↔ CMS ↔ FrontOffice/BackOffice"]
    DL --> PYMS
    MP --> PYMS
    DW --> PYMS

    PYMS --> WALLETS

    subgraph WALLETS["3 Wallet System"]
        W1["💰 Balance\nنقدی"]
        W2["🌟 NetworkBalance\nشبکه"]
        W3["🏷️ DiscountBalance\nتخفیفی"]
    end

۲. درگاه ZarinPal (IPG)

۲.۱ فلوی پرداخت

flowchart TD
    A["کاربر → انتخاب محصول\nدرخواست پرداخت"] --> B["CMS → CreatePaymentRequest\ngRPC to PYMS"]
    B --> C["PYMS → ZarinPal API\nدریافت Authority"]
    C --> D["Redirect کاربر\nصفحه پرداخت ZarinPal"]
    D --> E["بازگشت با Authority\nCMS VerifyPayment"]
    E -->|موفق| F["✅ ثبت سفارش\n+ شارژ کیف‌پول"]
    E -->|ناموفق| G["❌ نمایش پیام خطا"]

۲.۲ تنظیمات ZarinPal

پارامتر مقدار
MerchantId از appsettings
CallbackUrl /payment/callback
Sandbox true (staging) / false (production)
Currency IRR (ریال → تبدیل به تومان در UI)

۳. سیستم وام دایا (DayaLoan)

۳.۱ معماری

flowchart TD
    A["Hangfire Recurring Job\nهر ۲۰ دقیقه — */20 * * * *"] --> B["DayaLoanProcessorJob.Execute"]
    B --> C["بررسی LoanRequests\nStatus = Pending"]
    C --> D["برای هر درخواست:"]
    D --> E["ارسال به DayaLoan API\nAutomaticRetry Attempts=3"]
    E -->|تأیید| F["✅ Balance += 56M\nDiscountBalance += 112M\n+ ثبت Transaction + Log"]
    E -->|رد| G["❌ Status = Rejected\n+ ارسال SMS"]

۳.۲ Mock Mode

// appsettings.json
"DayaLoan": {
    "UseMock": true,         // staging
    "BaseUrl": "https://api.dayaloan.ir",
    "ApiKey": "***",
    "AutoApproveInMock": true
}

۳.۳ مقادیر

آیتم مقدار
مبلغ وام (DayaLoanAmount) ۵۶,۰۰۰,۰۰۰ ریال
شارژ Balance ۵۶,۰۰۰,۰۰۰ ریال
شارژ DiscountBalance ۱۱۲,۰۰۰,۰۰۰ ریال (دو برابر — DayaLoanAmount × 2)
مجموع شارژ ۱۶۸,۰۰۰,۰۰۰ ریال
NetworkBalance شارژ نمی‌شود
بازپرداخت طبق شرایط دایا

۴. پرداخت دستی (کارت‌به‌کارت)

⚠️ وضعیت: طراحی‌شده — پیاده‌سازی نشده

flowchart TD
    A["کاربر → انتخاب کارت‌به‌کارت"] --> B["نمایش شماره‌کارت مقصد\n+ مبلغ"]
    B --> C["کاربر → واریز\n+ آپلود تصویر رسید"]
    C --> D["ادمین BackOffice\nمشاهده لیست درخواست‌ها"]
    D --> E{"تأیید / رد؟"}
    E -->|تأیید| F["✅ شارژ خودکار کیف‌پول"]
    E -->|رد| G["❌ اطلاع‌رسانی به کاربر"]

موجودیت‌های مورد نیاز:

  • ManualPaymentRequest (UserId, Amount, ReceiptImage, Status, AdminNote)
  • ManualPaymentStatus enum: Pending, Approved, Rejected

۵. پرداخت ترکیبی فروشگاه تخفیفی (Hybrid Payment)

۵.۱ فرمول

قیمت محصول = 1,000,000 ریال
MaxDiscountPercent محصول = 40%  (هر محصول درصد تخفیف مخصوص خود را دارد)

سهم تخفیف = MIN(1,000,000 × 40%, DiscountBalanceکاربر) = 400,000
پرداخت نقدی (IPG) = 1,000,000 - 400,000 = 600,000
                                            ─────────
                          مجموع             = 1,000,000

ℹ️ تخفیف ثابت ۳۰% نیست — فیلد Product.MaxDiscountPercent (0-100) تعیین‌کننده است.

۵.۲ فلوی خرید فروشگاه تخفیفی

flowchart TD
    A["کاربر عضو باشگاه\nمشاهده محصول"] --> B["قیمت تخفیف‌خورده نمایش داده می‌شود"]
    B --> C["افزودن به سبد\nبررسی DiscountBalance"]
    C --> D{"موجودی کافی؟"}
    D -->|کافی| E["سهم تخفیف از DiscountBalance\nباقیمانده → IPG ZarinPal"]
    D -->|ناکافی| F["فقط به اندازه موجودی\nباقیمانده بیشتر → IPG"]

۵.۳ دسترسی فروشگاه تخفیفی

شرط نتیجه
IsClubMember = true دسترسی به Discount Store
IsClubMember = false فقط Regular Store
DiscountBalance > 0 می‌تواند از تخفیف استفاده کند
DiscountBalance = 0 پرداخت ۱۰۰% نقدی

۶. PYMS — سرویس پرداخت مرکزی

۶.۱ gRPC Services

service PaymentService {
    rpc CreatePayment (CreatePaymentRequest) returns (CreatePaymentResponse);
    rpc VerifyPayment (VerifyPaymentRequest) returns (VerifyPaymentResponse);
    rpc GetPaymentStatus (GetPaymentStatusRequest) returns (PaymentStatusResponse);
    rpc RefundPayment (RefundPaymentRequest) returns (RefundPaymentResponse);
}

۶.۲ Transaction Types

نوع کد توضیح
PackagePurchase 1 خرید پکیج طلایی
StorePurchase 2 خرید از فروشگاه
DiscountStorePurchase 3 خرید از فروشگاه تخفیفی
CommissionPayout 4 واریز کمیسیون هفتگی
WalletCharge 5 شارژ مستقیم کیف‌پول
ActivationFee 6 هزینه فعالسازی
DayaLoanCharge 7 شارژ از وام دایا

۷. مالیات و VAT

دو نرخ VAT در کد:

  SystemConstants.ShopVAT = 0.1  (10%) — تنظیم سیستمی
  VAT_RATE = 0.09  (9%)                — در فروشگاه تخفیفی (DiscountShop PlaceOrder)

قیمت نمایشی = قیمت پایه × (1 + VAT)
در صورتحساب: قیمت پایه + مالیات جداگانه نمایش داده می‌شود

۸. خلاصه وضعیت پیاده‌سازی

ماژول وضعیت یادداشت
ZarinPal IPG کامل Production ready
وام دایا کامل Mock mode فعال در staging
پرداخت ترکیبی کامل Discount + IPG
Pool هفتگی کامل SP + Hangfire
پرداخت دستی طراحی نیاز به تصمیم مدیریت
Refund طراحی فقط در PYMS تعریف‌شده