Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -0,0 +1,548 @@
|
||||
# Manual Payment System (سیستم پرداخت دستی مشتریان)
|
||||
|
||||
## 📌 Overview
|
||||
|
||||
سیستم پرداخت دستی برای مشتریانی که **بدون خرید وام دایا** میخواهند مستقیماً 56 میلیون تومان پرداخت کنند و همان مزایا را دریافت کنند.
|
||||
|
||||
### 🎯 سناریوها
|
||||
|
||||
#### سناریو 1: پرداخت آنلاین (درگاه پرداخت)
|
||||
```
|
||||
کاربر → انتخاب گزینه "پرداخت دستی" در فرانتآفیس
|
||||
↓
|
||||
ایجاد Transaction با Type=ManualPaymentOnline, Amount=56M, Status=Pending
|
||||
↓
|
||||
ریدایرکت به درگاه پرداخت (Zarinpal/Mellat/...)
|
||||
↓
|
||||
Callback از درگاه با RefId
|
||||
↓
|
||||
VerifyManualPaymentCommand → تایید تراکنش
|
||||
↓
|
||||
شارژ کیفپولها (Balance=56M, NetworkBalance=56M, DiscountBalance=56M)
|
||||
↓
|
||||
فعالسازی عضویت باشگاه (ClubMembership)
|
||||
```
|
||||
|
||||
#### سناریو 2: کارتبهکارت با تایید ادمین
|
||||
```
|
||||
کاربر → کارتبهکارت 56 میلیون + ارسال تصویر رسید
|
||||
↓
|
||||
CreateManualPaymentRequestCommand → ثبت درخواست با Status=PendingAdminApproval
|
||||
- تصویر رسید + کد پیگیری استخراج شده توسط کاربر
|
||||
↓
|
||||
ادمین → بررسی درخواست در BackOffice
|
||||
↓
|
||||
ApproveManualPaymentCommand یا RejectManualPaymentCommand
|
||||
↓
|
||||
در صورت تایید:
|
||||
- ایجاد Transaction با RefId=کد پیگیری
|
||||
- شارژ کیفپولها
|
||||
- فعالسازی عضویت باشگاه
|
||||
↓
|
||||
در صورت رد:
|
||||
- ثبت دلیل رد
|
||||
- اطلاعرسانی به کاربر
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ Architecture
|
||||
|
||||
### Domain Layer
|
||||
|
||||
> **وضعیت فعلی پیادهسازی (CMS)**
|
||||
> در نسخهای که الآن در CMS داریم، سناریوی «درخواست پرداخت دستی توسط کاربر» (ManualPaymentRequest + Verify از درگاه) هنوز پیادهسازی نشده و فقط بخش **پرداخت دستی توسط Admin/SuperAdmin** با Entity سادهتر `ManualPayment` و Enumهای `ManualPaymentType` و `ManualPaymentStatus` (Pending/Approved/Rejected/Cancelled) اجرا شده است.
|
||||
> بخشهای زیر که با `ManualPaymentRequest`، `ManualPaymentMethod` و Verify/ProcessManualPayment توضیح داده شدهاند، طراحی کامل سیستم هستند و برای فاز بعدی (FrontOffice + OnlineGateway/CardToCard) استفاده خواهند شد.
|
||||
|
||||
#### **ManualPaymentStatus Enum (طراحی کامل – برای Requestها)**
|
||||
```csharp
|
||||
public enum ManualPaymentStatus
|
||||
{
|
||||
PendingAdminApproval = 0, // در انتظار تایید ادمین (کارتبهکارت)
|
||||
PendingPayment = 1, // در انتظار پرداخت (درگاه آنلاین)
|
||||
PaymentVerified = 2, // پرداخت تایید شده (از درگاه)
|
||||
AdminApproved = 3, // تایید شده توسط ادمین
|
||||
AdminRejected = 4, // رد شده توسط ادمین
|
||||
Completed = 5, // تکمیل شده (کیفپول شارژ شده)
|
||||
Failed = 6 // خطا در پردازش
|
||||
}
|
||||
```
|
||||
|
||||
#### **ManualPaymentMethod Enum**
|
||||
```csharp
|
||||
public enum ManualPaymentMethod
|
||||
{
|
||||
OnlineGateway = 0, // درگاه آنلاین
|
||||
CardToCard = 1 // کارتبهکارت
|
||||
}
|
||||
```
|
||||
|
||||
#### **ManualPaymentRequest Entity (طراحی کامل – هنوز پیاده نشده)**
|
||||
```csharp
|
||||
public class ManualPaymentRequest : BaseAuditableEntity
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
public ManualPaymentMethod Method { get; set; }
|
||||
public ManualPaymentStatus Status { get; set; }
|
||||
public long Amount { get; set; } = 56_000_000; // مبلغ ثابت
|
||||
|
||||
// آنلاین Gateway
|
||||
public string? GatewayName { get; set; } // Zarinpal, Mellat, etc.
|
||||
public string? GatewayTrackingCode { get; set; } // کد پیگیری درگاه
|
||||
public DateTime? GatewayPaymentDate { get; set; }
|
||||
|
||||
// کارتبهکارت
|
||||
public string? ReceiptImageUrl { get; set; } // مسیر تصویر رسید
|
||||
public string? UserProvidedTrackingCode { get; set; } // کد پیگیری که کاربر داده
|
||||
public DateTime? CardToCardDate { get; set; }
|
||||
|
||||
// تایید/رد ادمین
|
||||
public long? ApprovedByAdminId { get; set; }
|
||||
public DateTime? AdminDecisionDate { get; set; }
|
||||
public string? AdminNotes { get; set; } // توضیحات ادمین (دلیل رد)
|
||||
|
||||
// تراکنش نهایی
|
||||
public long? TransactionId { get; set; }
|
||||
public bool IsProcessed { get; set; }
|
||||
public DateTime? ProcessedDate { get; set; }
|
||||
|
||||
// Navigation Properties
|
||||
public virtual User User { get; set; }
|
||||
public virtual User? ApprovedByAdmin { get; set; }
|
||||
public virtual Transactions? Transaction { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Application Layer
|
||||
|
||||
#### **Commands**
|
||||
|
||||
##### 1. CreateManualPaymentRequestCommand (FrontOffice)
|
||||
ایجاد درخواست پرداخت دستی توسط کاربر
|
||||
|
||||
**Request:**
|
||||
```csharp
|
||||
public record CreateManualPaymentRequestCommand : IRequest<CreateManualPaymentRequestResponseDto>
|
||||
{
|
||||
public long UserId { get; init; }
|
||||
public ManualPaymentMethod Method { get; init; }
|
||||
|
||||
// برای OnlineGateway
|
||||
public string? GatewayName { get; init; }
|
||||
public string? ReturnUrl { get; init; } // URL بازگشت بعد از پرداخت
|
||||
|
||||
// برای CardToCard
|
||||
public IFormFile? ReceiptImage { get; init; } // فایل تصویر رسید
|
||||
public string? TrackingCode { get; init; } // کد پیگیری
|
||||
public DateTime? TransactionDate { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```csharp
|
||||
public class CreateManualPaymentRequestResponseDto
|
||||
{
|
||||
public long RequestId { get; set; }
|
||||
public ManualPaymentStatus Status { get; set; }
|
||||
|
||||
// برای OnlineGateway: URL پرداخت
|
||||
public string? PaymentUrl { get; set; }
|
||||
|
||||
// برای CardToCard: پیام موفقیت
|
||||
public string Message { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
**Business Logic:**
|
||||
1. بررسی اینکه کاربر قبلاً درخواست Pending ندارد
|
||||
2. اگر Method=OnlineGateway:
|
||||
- ایجاد ManualPaymentRequest با Status=PendingPayment
|
||||
- فراخوانی Gateway Service برای دریافت URL پرداخت
|
||||
- ذخیره GatewayName و کد درخواست
|
||||
- برگرداندن PaymentUrl به کاربر
|
||||
3. اگر Method=CardToCard:
|
||||
- آپلود تصویر رسید به Storage
|
||||
- ایجاد ManualPaymentRequest با Status=PendingAdminApproval
|
||||
- ذخیره UserProvidedTrackingCode و CardToCardDate
|
||||
- ارسال نوتیفیکیشن به ادمینها
|
||||
|
||||
##### 2. VerifyManualPaymentCommand (Callback از درگاه)
|
||||
تایید پرداخت آنلاین بعد از بازگشت از درگاه
|
||||
|
||||
**Request:**
|
||||
```csharp
|
||||
public record VerifyManualPaymentCommand : IRequest<VerifyManualPaymentResponseDto>
|
||||
{
|
||||
public long RequestId { get; init; }
|
||||
public string GatewayTrackingCode { get; init; }
|
||||
public string? Authority { get; init; } // پارامتر درگاه
|
||||
}
|
||||
```
|
||||
|
||||
**Business Logic:**
|
||||
1. یافتن ManualPaymentRequest با Status=PendingPayment
|
||||
2. فراخوانی Gateway Service برای Verify کردن تراکنش
|
||||
3. اگر تایید شد:
|
||||
- بهروزرسانی Status → PaymentVerified
|
||||
- ذخیره GatewayTrackingCode و GatewayPaymentDate
|
||||
- فراخوانی ProcessManualPaymentCommand برای شارژ کیفپول
|
||||
4. اگر رد شد:
|
||||
- بهروزرسانی Status → Failed
|
||||
|
||||
##### 3. ApproveManualPaymentCommand (Admin)
|
||||
تایید درخواست کارتبهکارت توسط ادمین
|
||||
|
||||
**Request:**
|
||||
```csharp
|
||||
public record ApproveManualPaymentCommand : IRequest<ApproveManualPaymentResponseDto>
|
||||
{
|
||||
public long RequestId { get; init; }
|
||||
public long AdminUserId { get; init; }
|
||||
public string? AdminNotes { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
**Business Logic:**
|
||||
1. بررسی RequestId موجود با Status=PendingAdminApproval
|
||||
2. بررسی دسترسی ادمین
|
||||
3. بهروزرسانی:
|
||||
- Status → AdminApproved
|
||||
- ApprovedByAdminId, AdminDecisionDate, AdminNotes
|
||||
4. فراخوانی ProcessManualPaymentCommand برای شارژ کیفپول
|
||||
|
||||
##### 4. RejectManualPaymentCommand (Admin)
|
||||
رد درخواست کارتبهکارت توسط ادمین
|
||||
|
||||
**Request:**
|
||||
```csharp
|
||||
public record RejectManualPaymentCommand : IRequest<RejectManualPaymentResponseDto>
|
||||
{
|
||||
public long RequestId { get; init; }
|
||||
public long AdminUserId { get; init; }
|
||||
public string RejectionReason { get; init; } // الزامی
|
||||
}
|
||||
```
|
||||
|
||||
**Business Logic:**
|
||||
1. بررسی RequestId موجود
|
||||
2. بهروزرسانی:
|
||||
- Status → AdminRejected
|
||||
- ApprovedByAdminId, AdminDecisionDate
|
||||
- AdminNotes = RejectionReason
|
||||
3. ارسال نوتیفیکیشن به کاربر با دلیل رد
|
||||
|
||||
##### 5. ProcessManualPaymentCommand (Internal)
|
||||
شارژ کیفپولها بعد از تایید پرداخت
|
||||
|
||||
**این Command داخلی است و فقط توسط Verify یا Approve فراخوانی میشود.**
|
||||
|
||||
**Business Logic:**
|
||||
1. ایجاد Transaction:
|
||||
- Type: DepositManual
|
||||
- Amount: 56M
|
||||
- RefId: GatewayTrackingCode یا UserProvidedTrackingCode
|
||||
2. شارژ Balance: +56M
|
||||
3. شارژ NetworkBalance: +56M
|
||||
4. شارژ DiscountBalance: +56M
|
||||
5. فعالسازی ClubMembership (اگر غیرفعال باشد)
|
||||
6. ثبت UserWalletChangeLog
|
||||
7. بهروزرسانی ManualPaymentRequest:
|
||||
- Status → Completed
|
||||
- TransactionId, IsProcessed=true, ProcessedDate
|
||||
8. ارسال نوتیفیکیشن موفقیت به کاربر
|
||||
|
||||
##### 6. GetUserManualPaymentHistoryQuery
|
||||
دریافت تاریخچه پرداختهای دستی کاربر
|
||||
|
||||
**Request:**
|
||||
```csharp
|
||||
public record GetUserManualPaymentHistoryQuery : IRequest<List<ManualPaymentHistoryDto>>
|
||||
{
|
||||
public long UserId { get; init; }
|
||||
}
|
||||
```
|
||||
|
||||
##### 7. GetPendingManualPaymentsQuery (Admin)
|
||||
دریافت لیست درخواستهای در انتظار تایید
|
||||
|
||||
**Request:**
|
||||
```csharp
|
||||
public record GetPendingManualPaymentsQuery : IRequest<List<PendingManualPaymentDto>>
|
||||
{
|
||||
public ManualPaymentStatus? StatusFilter { get; init; } = ManualPaymentStatus.PendingAdminApproval;
|
||||
public int PageNumber { get; init; } = 1;
|
||||
public int PageSize { get; init; } = 20;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💾 Database Schema
|
||||
|
||||
### ManualPaymentRequests Table
|
||||
```sql
|
||||
CREATE TABLE [CMS].[ManualPaymentRequests] (
|
||||
[Id] bigint IDENTITY(1,1) PRIMARY KEY,
|
||||
[UserId] bigint NOT NULL FOREIGN KEY REFERENCES Users(Id),
|
||||
[Method] int NOT NULL,
|
||||
[Status] int NOT NULL,
|
||||
[Amount] bigint NOT NULL DEFAULT 56000000,
|
||||
|
||||
-- آنلاین Gateway
|
||||
[GatewayName] nvarchar(50) NULL,
|
||||
[GatewayTrackingCode] nvarchar(200) NULL,
|
||||
[GatewayPaymentDate] datetime2 NULL,
|
||||
|
||||
-- کارتبهکارت
|
||||
[ReceiptImageUrl] nvarchar(500) NULL,
|
||||
[UserProvidedTrackingCode] nvarchar(200) NULL,
|
||||
[CardToCardDate] datetime2 NULL,
|
||||
|
||||
-- تایید ادمین
|
||||
[ApprovedByAdminId] bigint NULL FOREIGN KEY REFERENCES Users(Id),
|
||||
[AdminDecisionDate] datetime2 NULL,
|
||||
[AdminNotes] nvarchar(max) NULL,
|
||||
|
||||
-- تراکنش
|
||||
[TransactionId] bigint NULL FOREIGN KEY REFERENCES Transactionss(Id),
|
||||
[IsProcessed] bit NOT NULL DEFAULT 0,
|
||||
[ProcessedDate] datetime2 NULL,
|
||||
|
||||
-- Audit
|
||||
[Created] datetime2 NOT NULL,
|
||||
[CreatedBy] nvarchar(max) NULL,
|
||||
[LastModified] datetime2 NULL,
|
||||
[LastModifiedBy] nvarchar(max) NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IX_ManualPaymentRequests_UserId ON ManualPaymentRequests(UserId);
|
||||
CREATE INDEX IX_ManualPaymentRequests_Status ON ManualPaymentRequests(Status);
|
||||
CREATE INDEX IX_ManualPaymentRequests_TransactionId ON ManualPaymentRequests(TransactionId);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Process Flows
|
||||
|
||||
### Flow 1: پرداخت آنلاین
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as کاربر
|
||||
participant FrontOffice as FrontOffice
|
||||
participant CMS as CMS API
|
||||
participant Gateway as درگاه پرداخت
|
||||
|
||||
User->>FrontOffice: انتخاب "پرداخت دستی"
|
||||
FrontOffice->>CMS: CreateManualPaymentRequest (Method=OnlineGateway)
|
||||
CMS->>Gateway: ایجاد درخواست پرداخت
|
||||
Gateway-->>CMS: PaymentUrl
|
||||
CMS-->>FrontOffice: PaymentUrl
|
||||
FrontOffice->>Gateway: ریدایرکت کاربر
|
||||
User->>Gateway: پرداخت 56M
|
||||
Gateway->>CMS: Callback (RefId, Authority)
|
||||
CMS->>Gateway: Verify Payment
|
||||
Gateway-->>CMS: تایید پرداخت
|
||||
CMS->>CMS: ProcessManualPayment (شارژ کیفپول)
|
||||
CMS-->>FrontOffice: موفقیت
|
||||
FrontOffice-->>User: پرداخت موفق
|
||||
```
|
||||
|
||||
### Flow 2: کارتبهکارت
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as کاربر
|
||||
participant FrontOffice as FrontOffice
|
||||
participant CMS as CMS API
|
||||
participant Admin as ادمین (BackOffice)
|
||||
|
||||
User->>User: کارتبهکارت 56M
|
||||
User->>FrontOffice: آپلود رسید + کد پیگیری
|
||||
FrontOffice->>CMS: CreateManualPaymentRequest (Method=CardToCard)
|
||||
CMS->>CMS: ذخیره تصویر + Status=PendingAdminApproval
|
||||
CMS-->>Admin: نوتیفیکیشن (درخواست جدید)
|
||||
Admin->>CMS: GetPendingManualPayments
|
||||
CMS-->>Admin: لیست درخواستها
|
||||
Admin->>Admin: بررسی رسید و کد پیگیری
|
||||
|
||||
alt تایید
|
||||
Admin->>CMS: ApproveManualPayment
|
||||
CMS->>CMS: ProcessManualPayment (شارژ کیفپول)
|
||||
CMS-->>User: نوتیفیکیشن موفقیت
|
||||
else رد
|
||||
Admin->>CMS: RejectManualPayment (دلیل رد)
|
||||
CMS-->>User: نوتیفیکیشن رد با دلیل
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Scenarios
|
||||
|
||||
### Test 1: پرداخت آنلاین موفق
|
||||
```bash
|
||||
# Step 1: ایجاد درخواست
|
||||
POST /api/manualpayment/create
|
||||
{
|
||||
"userId": 123,
|
||||
"method": 0,
|
||||
"gatewayName": "Zarinpal",
|
||||
"returnUrl": "https://example.com/callback"
|
||||
}
|
||||
|
||||
# Response: PaymentUrl
|
||||
|
||||
# Step 2: کاربر پرداخت میکند (Mock Gateway)
|
||||
|
||||
# Step 3: Callback
|
||||
POST /api/manualpayment/verify
|
||||
{
|
||||
"requestId": 456,
|
||||
"gatewayTrackingCode": "ZP-12345",
|
||||
"authority": "A00000000..."
|
||||
}
|
||||
|
||||
# Result: کیفپول شارژ شده، باشگاه فعال
|
||||
```
|
||||
|
||||
### Test 2: کارتبهکارت با تایید ادمین
|
||||
```bash
|
||||
# Step 1: ایجاد درخواست کاربر
|
||||
POST /api/manualpayment/create
|
||||
{
|
||||
"userId": 123,
|
||||
"method": 1,
|
||||
"receiptImage": <file>,
|
||||
"trackingCode": "REF-98765",
|
||||
"transactionDate": "2024-12-01T10:00:00Z"
|
||||
}
|
||||
|
||||
# Step 2: ادمین بررسی میکند
|
||||
GET /api/admin/manualpayment/pending
|
||||
|
||||
# Step 3: ادمین تایید میکند
|
||||
POST /api/admin/manualpayment/approve
|
||||
{
|
||||
"requestId": 456,
|
||||
"adminUserId": 1,
|
||||
"adminNotes": "رسید معتبر است"
|
||||
}
|
||||
|
||||
# Result: کیفپول شارژ شده
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Implementation Tasks
|
||||
|
||||
### CMS Microservice
|
||||
|
||||
#### Domain Layer
|
||||
- [ ] ایجاد `ManualPaymentStatus` enum
|
||||
- [ ] ایجاد `ManualPaymentMethod` enum
|
||||
- [ ] ایجاد `ManualPaymentRequest` entity
|
||||
- [ ] اضافه کردن به `ApplicationDbContext`
|
||||
|
||||
#### Application Layer
|
||||
- [ ] `CreateManualPaymentRequestCommand` + Handler + Validator
|
||||
- [ ] `VerifyManualPaymentCommand` + Handler
|
||||
- [ ] `ApproveManualPaymentCommand` + Handler
|
||||
- [ ] `RejectManualPaymentCommand` + Handler
|
||||
- [ ] `ProcessManualPaymentCommand` + Handler (Internal)
|
||||
- [ ] `GetUserManualPaymentHistoryQuery` + Handler
|
||||
- [ ] `GetPendingManualPaymentsQuery` + Handler
|
||||
- [ ] Interface: `IPaymentGatewayService`
|
||||
- [ ] Interface: `IFileStorageService` (برای آپلود تصویر)
|
||||
|
||||
#### Infrastructure Layer
|
||||
- [ ] `ZarinpalGatewayService` : IPaymentGatewayService
|
||||
- [ ] `LocalFileStorageService` : IFileStorageService
|
||||
- [ ] Migration: `AddManualPaymentSystem`
|
||||
|
||||
#### WebApi Layer (Protobuf/gRPC)
|
||||
- [ ] Proto definitions: `ManualPayment.proto`
|
||||
- [ ] gRPC Service: `ManualPaymentService`
|
||||
|
||||
### FrontOffice
|
||||
|
||||
#### Components
|
||||
- [ ] `ManualPaymentPage.razor` - صفحه انتخاب روش پرداخت
|
||||
- [ ] `OnlinePaymentForm.razor` - فرم پرداخت آنلاین
|
||||
- [ ] `CardToCardForm.razor` - فرم کارتبهکارت (آپلود رسید)
|
||||
- [ ] `PaymentCallbackPage.razor` - صفحه بازگشت از درگاه
|
||||
- [ ] `PaymentHistoryPage.razor` - تاریخچه پرداختهای کاربر
|
||||
|
||||
#### Services
|
||||
- [ ] `ManualPaymentService.cs` - فراخوانی BFF
|
||||
|
||||
### FrontOffice.BFF
|
||||
|
||||
#### Application Layer
|
||||
- [ ] CQRS Handlers برای مپ کردن gRPC به REST
|
||||
- [ ] DTOs برای API های REST
|
||||
|
||||
#### WebApi Layer
|
||||
- [ ] `ManualPaymentController.cs` - REST endpoints
|
||||
|
||||
### BackOffice
|
||||
|
||||
#### Components
|
||||
- [ ] `PendingPaymentsPage.razor` - لیست درخواستهای در انتظار
|
||||
- [ ] `PaymentRequestDetailsModal.razor` - جزئیات + نمایش رسید
|
||||
- [ ] `ApproveRejectButtons.razor` - دکمههای تایید/رد
|
||||
|
||||
#### Services
|
||||
- [ ] `ManualPaymentAdminService.cs` - فراخوانی BFF
|
||||
|
||||
### BackOffice.BFF
|
||||
|
||||
#### Application Layer
|
||||
- [ ] Admin CQRS Handlers
|
||||
- [ ] Admin DTOs
|
||||
|
||||
#### WebApi Layer
|
||||
- [ ] `AdminManualPaymentController.cs` - REST endpoints برای ادمین
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Important Notes
|
||||
|
||||
### 1. Transaction Type
|
||||
- برای پرداخت دستی از `TransactionType.DepositManual` استفاده شود
|
||||
- RefId = GatewayTrackingCode (آنلاین) یا UserProvidedTrackingCode (کارتبهکارت)
|
||||
|
||||
### 2. Security
|
||||
- تایید پرداخت درگاه باید با Signature Verification انجام شود
|
||||
- تصاویر رسید باید با Validation بارگذاری شوند (حجم، فرمت، محتوا)
|
||||
- فقط ادمینها حق تایید/رد کارتبهکارت دارند
|
||||
|
||||
### 3. Idempotency
|
||||
- نباید کاربر بتواند چند درخواست همزمان Pending داشته باشد
|
||||
- هر RequestId فقط یک بار قابل Verify است
|
||||
|
||||
### 4. Notifications
|
||||
- SMS/Email به کاربر بعد از:
|
||||
- ایجاد درخواست کارتبهکارت
|
||||
- تایید/رد ادمین
|
||||
- موفقیت پرداخت آنلاین
|
||||
|
||||
### 5. File Storage
|
||||
- تصاویر رسید باید با GUID ذخیره شوند
|
||||
- مسیر: `/uploads/receipts/{year}/{month}/{guid}.jpg`
|
||||
- حداکثر حجم: 2MB
|
||||
- فرمتهای مجاز: JPG, PNG, PDF
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Related Documentation
|
||||
|
||||
- [daya-loan-integration.md](./daya-loan-integration.md) - سیستم وام دایا
|
||||
- [network-club-commission-system-v1.1.md](./network-club-commission-system-v1.1.md) - بیزینس کلی
|
||||
|
||||
---
|
||||
|
||||
**Created:** 2024-12-01
|
||||
**Status:** ⚠️ Not Implemented Yet (Design Complete)
|
||||
**Priority:** High (برای کاربران بدون وام دایا ضروری است)
|
||||
Reference in New Issue
Block a user