update
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# BackOffice.BFF
|
||||
|
||||
> Backend For Frontend layer برای BackOffice UI
|
||||
|
||||
## 📋 خلاصه
|
||||
|
||||
BackOffice.BFF لایه واسط بین BackOffice UI و CMS microservices است که:
|
||||
- درخواستهای UI را aggregate میکند
|
||||
- قراردادهای gRPC اختصاصی ارائه میدهد
|
||||
- منطق سطح BFF را پیادهسازی میکند
|
||||
|
||||
## 🏗️ معماری
|
||||
|
||||
### Protobuf Projects (Own Contracts)
|
||||
|
||||
BackOffice.BFF از قراردادهای Protobuf **اختصاصی خودش** استفاده میکند:
|
||||
|
||||
| Project | Version | Namespace | Purpose |
|
||||
|---------|---------|-----------|----------|
|
||||
| BackOffice.BFF.ClubMembership.Protobuf | 0.0.7 | Foursat.BackOffice.BFF.ClubMembership.Protos | باشگاه مشتریان |
|
||||
| BackOffice.BFF.Commission.Protobuf | 0.0.13 | Foursat.BackOffice.BFF.Commission.Protos | کمیسیون |
|
||||
| BackOffice.BFF.Configuration.Protobuf | 1.0.20 | BackOffice.BFF.Configuration.Protobuf.Protos | تنظیمات + AppVersion |
|
||||
| BackOffice.BFF.NetworkMembership.Protobuf | 0.0.11 | Foursat.BackOffice.BFF.NetworkMembership.Protos | شبکه |
|
||||
|
||||
**تغییر معماری (۱۷ آذر ۱۴۰۴)**:
|
||||
- ❌ **قبلا**: استفاده مستقیم از `CMSMicroservice.Protobuf` (Anti-Pattern)
|
||||
- ✅ **حالا**: Protobuf اختصاصی با namespace مجزا
|
||||
- ✅ **مزایا**: جدایی concerns، versioning مستقل، کاهش coupling
|
||||
|
||||
### GrpcServices Mode
|
||||
|
||||
همه پروژههای Protobuf با `GrpcServices="Both"` پیکربندی شدهاند:
|
||||
- **Server**: Base classes برای پیادهسازی در BFF
|
||||
- **Client**: Client classes برای استفاده در BackOffice UI
|
||||
|
||||
### HTTP Annotations (Swagger)
|
||||
|
||||
همه 33 endpoint با HTTP annotations پیادهسازی شدهاند:
|
||||
```protobuf
|
||||
import "google/api/annotations.proto";
|
||||
|
||||
rpc GetClubMembershipById(GetClubMembershipByIdRequest) returns (GetClubMembershipByIdResponse) {
|
||||
option (google.api.http) = { get: "/GetClubMembershipById" };
|
||||
}
|
||||
```
|
||||
|
||||
**Package**: Google.Api.CommonProtos v2.10.0
|
||||
|
||||
## 🔧 Mapster Configuration
|
||||
|
||||
### Immutable Type Handling
|
||||
|
||||
Protobuf messages دارای فیلدهای immutable هستند. از `MapWith()` استفاده کنید:
|
||||
|
||||
```csharp
|
||||
config.NewConfig<GetNetworkTreeResponseDto, GetNetworkTreeResponse>()
|
||||
.MapWith(src => new GetNetworkTreeResponse {
|
||||
Items = { src.Items.Select(x => new NetworkTreeNodeModel {
|
||||
UserId = x.UserId,
|
||||
FirstName = x.FirstName,
|
||||
// ...
|
||||
}) }
|
||||
});
|
||||
```
|
||||
|
||||
**Profiles**:
|
||||
- NetworkMembershipProfile.cs
|
||||
- ProductsProfile.cs
|
||||
|
||||
## 📦 Package Publishing
|
||||
|
||||
برای publish به GitLab registry:
|
||||
|
||||
```bash
|
||||
cd BackOffice.BFF.{Module}.Protobuf
|
||||
dotnet pack -c Release
|
||||
# Auto-push via PushToFourSat target
|
||||
```
|
||||
|
||||
**Registry**: https://git.afrino.co/api/packages/FourSat/nuget
|
||||
|
||||
## 🔗 Related Docs
|
||||
|
||||
- [Architecture Patterns](../../../02-ARCHITECTURE/README.md)
|
||||
- [API Coverage](api-coverage.md)
|
||||
- [Protobuf Dependencies](protobuf-dependencies.md)
|
||||
@@ -0,0 +1,593 @@
|
||||
# BackOffice.BFF - CMS Integration Documentation
|
||||
|
||||
**Date**: 2025-11-30
|
||||
**Status**: ✅ Integrated
|
||||
**CMS Package Version**: 0.0.140
|
||||
|
||||
---
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
BackOffice.BFF به CMS Microservice متصل شد و حالا میتواند به سرویسهای Network-Club-Commission دسترسی داشته باشد.
|
||||
|
||||
این Integration به BackOffice امکان میدهد:
|
||||
- مدیریت کامیسیونهای کاربران
|
||||
- مشاهده ساختار شبکه Binary Tree
|
||||
- فعال/غیرفعال کردن عضویت باشگاه
|
||||
- مشاهده گزارشات هفتگی کمیسیون
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ BackOffice.BFF (API Gateway) │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ IApplicationContractContext │ │
|
||||
│ │ - Users (existing) │ │
|
||||
│ │ - Products (existing) │ │
|
||||
│ │ - Orders (existing) │ │
|
||||
│ │ ✨ Commissions (NEW) │ │
|
||||
│ │ ✨ NetworkMemberships (NEW) │ │
|
||||
│ │ ✨ ClubMemberships (NEW) │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ ↓ gRPC │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ CMS Microservice │
|
||||
│ https://cms.kbs1.ir │
|
||||
│ │
|
||||
│ ┌─────────────────────┐ ┌─────────────────────────┐ │
|
||||
│ │ CommissionContract │ │ NetworkMembershipContract│ │
|
||||
│ │ - GetWeeklyPool │ │ - GetUserNetworkInfo │ │
|
||||
│ │ - GetUserPayouts │ │ - GetNetworkTree │ │
|
||||
│ │ - ProcessWithdrawal │ │ - CalculateLegBalances │ │
|
||||
│ └─────────────────────┘ └─────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────┐ │
|
||||
│ │ ClubMembershipContract│ │
|
||||
│ │ - ActivateClub │ │
|
||||
│ │ - DeactivateClub │ │
|
||||
│ │ - GetClubStatus │ │
|
||||
│ └─────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Integration Details
|
||||
|
||||
### 1️⃣ NuGet Package
|
||||
|
||||
**Package**: `Foursat.CMSMicroservice.Protobuf`
|
||||
**Version**: `0.0.140` (Updated from 0.0.137)
|
||||
|
||||
**File**: `/BackOffice.BFF/src/BackOffice.BFF.Domain/BackOffice.BFF.Domain.csproj`
|
||||
|
||||
```xml
|
||||
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.140" />
|
||||
```
|
||||
|
||||
**What's New in 0.0.140**:
|
||||
- ✨ `commission.proto` - Commission system contracts
|
||||
- ✨ `networkmembership.proto` - Binary tree network contracts
|
||||
- ✨ `clubmembership.proto` - Club membership contracts
|
||||
- ✨ `configuration.proto` - System configuration contracts
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ Interface Definition
|
||||
|
||||
**File**: `/BackOffice.BFF/src/BackOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs`
|
||||
|
||||
```csharp
|
||||
public interface IApplicationContractContext
|
||||
{
|
||||
// ... existing services ...
|
||||
|
||||
// Network & Commission System (NEW)
|
||||
CommissionContract.CommissionContractClient Commissions { get; }
|
||||
NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships { get; }
|
||||
ClubMembershipContract.ClubMembershipContractClient ClubMemberships { get; }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ Implementation
|
||||
|
||||
**File**: `/BackOffice.BFF/src/BackOffice.BFF.Infrastructure/Services/ApplicationContractContext.cs`
|
||||
|
||||
```csharp
|
||||
public class ApplicationContractContext : IApplicationContractContext
|
||||
{
|
||||
// ... existing implementations ...
|
||||
|
||||
// Network & Commission System
|
||||
public CommissionContract.CommissionContractClient Commissions
|
||||
=> GetService<CommissionContract.CommissionContractClient>();
|
||||
|
||||
public NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships
|
||||
=> GetService<NetworkMembershipContract.NetworkMembershipContractClient>();
|
||||
|
||||
public ClubMembershipContract.ClubMembershipContractClient ClubMemberships
|
||||
=> GetService<ClubMembershipContract.ClubMembershipContractClient>();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ gRPC Configuration
|
||||
|
||||
**File**: `/BackOffice.BFF/src/BackOffice.BFF.WebApi/appsettings.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"GrpcChannelOptions": {
|
||||
"FMSMSAddress": "https://dl.afrino.co",
|
||||
"CMSMSAddress": "https://cms.kbs1.ir"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Auto-Registration**:
|
||||
- gRPC clients به صورت خودکار توسط `ConfigureGrpcServices.BatchRegisterGrpcClients()` ثبت میشوند
|
||||
- بر اساس نام Assembly (`CMSMicroservice.Protobuf`)
|
||||
- با Address مشخص شده در `appsettings.json`
|
||||
|
||||
---
|
||||
|
||||
## 🔌 Available Services
|
||||
|
||||
### 1️⃣ CommissionContract
|
||||
|
||||
**Namespace**: `CMSMicroservice.Protobuf.Protos.Commission`
|
||||
|
||||
#### Commands:
|
||||
```csharp
|
||||
// محاسبه بالانس های هفتگی
|
||||
await _context.Commissions.CalculateWeeklyBalancesAsync(
|
||||
new CalculateWeeklyBalancesRequest { WeekNumber = "2025-W48" });
|
||||
|
||||
// محاسبه Pool هفتگی
|
||||
await _context.Commissions.CalculateWeeklyCommissionPoolAsync(
|
||||
new CalculateWeeklyCommissionPoolRequest { WeekNumber = "2025-W48" });
|
||||
|
||||
// پردازش Payout های کاربران
|
||||
await _context.Commissions.ProcessUserPayoutsAsync(
|
||||
new ProcessUserPayoutsRequest { WeekNumber = "2025-W48" });
|
||||
|
||||
// درخواست برداشت توسط کاربر
|
||||
await _context.Commissions.RequestWithdrawalAsync(
|
||||
new RequestWithdrawalRequest
|
||||
{
|
||||
UserId = 123,
|
||||
Amount = 500000
|
||||
});
|
||||
|
||||
// پردازش برداشت (توسط Admin)
|
||||
await _context.Commissions.ProcessWithdrawalAsync(
|
||||
new ProcessWithdrawalRequest
|
||||
{
|
||||
PayoutId = 456,
|
||||
Status = WithdrawalStatus.Approved
|
||||
});
|
||||
```
|
||||
|
||||
#### Queries:
|
||||
```csharp
|
||||
// دریافت Pool هفتگی
|
||||
var pool = await _context.Commissions.GetWeeklyCommissionPoolAsync(
|
||||
new GetWeeklyCommissionPoolRequest { WeekNumber = "2025-W48" });
|
||||
|
||||
// دریافت Payout های یک کاربر
|
||||
var payouts = await _context.Commissions.GetUserPayoutsAsync(
|
||||
new GetUserPayoutsRequest
|
||||
{
|
||||
UserId = 123,
|
||||
PageNumber = 1,
|
||||
PageSize = 10
|
||||
});
|
||||
|
||||
// دریافت تاریخچه Withdrawal ها
|
||||
var withdrawals = await _context.Commissions.GetWithdrawalHistoryAsync(
|
||||
new GetWithdrawalHistoryRequest
|
||||
{
|
||||
UserId = 123,
|
||||
Status = WithdrawalStatus.Pending
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ NetworkMembershipContract
|
||||
|
||||
**Namespace**: `CMSMicroservice.Protobuf.Protos.NetworkMembership`
|
||||
|
||||
#### Queries:
|
||||
```csharp
|
||||
// دریافت اطلاعات شبکه یک کاربر
|
||||
var networkInfo = await _context.NetworkMemberships.GetUserNetworkInfoAsync(
|
||||
new GetUserNetworkInfoRequest { UserId = 123 });
|
||||
|
||||
// دریافت درخت شبکه (Binary Tree)
|
||||
var tree = await _context.NetworkMemberships.GetNetworkTreeAsync(
|
||||
new GetNetworkTreeRequest
|
||||
{
|
||||
RootUserId = 123,
|
||||
MaxDepth = 5
|
||||
});
|
||||
|
||||
// دریافت بالانس های هفتگی
|
||||
var balances = await _context.NetworkMemberships.GetUserWeeklyBalancesAsync(
|
||||
new GetUserWeeklyBalancesRequest
|
||||
{
|
||||
UserId = 123,
|
||||
WeekNumber = "2025-W48"
|
||||
});
|
||||
|
||||
// محاسبه بالانس Leg های یک کاربر
|
||||
var legBalances = await _context.NetworkMemberships.CalculateLegBalancesAsync(
|
||||
new CalculateLegBalancesRequest { UserId = 123 });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ ClubMembershipContract
|
||||
|
||||
**Namespace**: `CMSMicroservice.Protobuf.Protos.ClubMembership`
|
||||
|
||||
#### Commands:
|
||||
```csharp
|
||||
// فعال کردن عضویت باشگاه
|
||||
await _context.ClubMemberships.ActivateClubMembershipAsync(
|
||||
new ActivateClubMembershipRequest
|
||||
{
|
||||
UserId = 123,
|
||||
ActivationDate = Timestamp.FromDateTime(DateTime.UtcNow)
|
||||
});
|
||||
|
||||
// غیرفعال کردن عضویت باشگاه
|
||||
await _context.ClubMemberships.DeactivateClubMembershipAsync(
|
||||
new DeactivateClubMembershipRequest
|
||||
{
|
||||
UserId = 123,
|
||||
Reason = "User request"
|
||||
});
|
||||
```
|
||||
|
||||
#### Queries:
|
||||
```csharp
|
||||
// دریافت وضعیت عضویت باشگاه
|
||||
var status = await _context.ClubMemberships.GetClubMembershipStatusAsync(
|
||||
new GetClubMembershipStatusRequest { UserId = 123 });
|
||||
|
||||
// لیست تمام اعضای باشگاه
|
||||
var members = await _context.ClubMemberships.GetAllClubMembersAsync(
|
||||
new GetAllClubMembersRequest
|
||||
{
|
||||
IsActive = true,
|
||||
PageNumber = 1,
|
||||
PageSize = 20
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Usage Example in BFF
|
||||
|
||||
### Example 1: Create Commission Query Handler
|
||||
|
||||
**File**: `/BackOffice.BFF/src/BackOffice.BFF.Application/CommissionCQ/Queries/GetUserPayouts/GetUserPayoutsQuery.cs`
|
||||
|
||||
```csharp
|
||||
public record GetUserPayoutsQuery : IRequest<GetUserPayoutsResponseDto>
|
||||
{
|
||||
public long UserId { get; init; }
|
||||
public int PageNumber { get; init; } = 1;
|
||||
public int PageSize { get; init; } = 10;
|
||||
}
|
||||
|
||||
public class GetUserPayoutsQueryHandler
|
||||
: IRequestHandler<GetUserPayoutsQuery, GetUserPayoutsResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetUserPayoutsQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetUserPayoutsResponseDto> Handle(
|
||||
GetUserPayoutsQuery request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.Commissions.GetUserPayoutsAsync(
|
||||
request.Adapt<GetUserPayoutsRequest>(),
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return response.Adapt<GetUserPayoutsResponseDto>();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Create Network Tree Query Handler
|
||||
|
||||
**File**: `/BackOffice.BFF/src/BackOffice.BFF.Application/NetworkCQ/Queries/GetNetworkTree/GetNetworkTreeQuery.cs`
|
||||
|
||||
```csharp
|
||||
public record GetNetworkTreeQuery : IRequest<GetNetworkTreeResponseDto>
|
||||
{
|
||||
public long RootUserId { get; init; }
|
||||
public int MaxDepth { get; init; } = 5;
|
||||
}
|
||||
|
||||
public class GetNetworkTreeQueryHandler
|
||||
: IRequestHandler<GetNetworkTreeQuery, GetNetworkTreeResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetNetworkTreeQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetNetworkTreeResponseDto> Handle(
|
||||
GetNetworkTreeQuery request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.NetworkMemberships.GetNetworkTreeAsync(
|
||||
request.Adapt<GetNetworkTreeRequest>(),
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return response.Adapt<GetNetworkTreeResponseDto>();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Create Club Activation Command Handler
|
||||
|
||||
**File**: `/BackOffice.BFF/src/BackOffice.BFF.Application/ClubCQ/Commands/ActivateClub/ActivateClubCommand.cs`
|
||||
|
||||
```csharp
|
||||
public record ActivateClubCommand : IRequest<Unit>
|
||||
{
|
||||
public long UserId { get; init; }
|
||||
public DateTimeOffset? ActivationDate { get; init; }
|
||||
}
|
||||
|
||||
public class ActivateClubCommandHandler
|
||||
: IRequestHandler<ActivateClubCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public ActivateClubCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(
|
||||
ActivateClubCommand request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.ClubMemberships.ActivateClubMembershipAsync(
|
||||
request.Adapt<ActivateClubMembershipRequest>(),
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Authentication & Authorization
|
||||
|
||||
**JWT Token**:
|
||||
- BackOffice.BFF به CMS با JWT Token متصل میشود
|
||||
- Token از `ITokenProvider` گرفته میشود
|
||||
- در Header با کلید `Authorization: Bearer {token}` ارسال میشود
|
||||
|
||||
**Implementation در `ConfigureGrpcServices.cs`**:
|
||||
```csharp
|
||||
private static async Task CallCredentials(
|
||||
AuthInterceptorContext context,
|
||||
Metadata metadata,
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
var provider = serviceProvider.GetRequiredService<ITokenProvider>();
|
||||
var token = await provider.GetTokenAsync();
|
||||
metadata.Add("Authorization", $"Bearer {token}");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Test Connection:
|
||||
|
||||
```csharp
|
||||
// در یک Controller یا Handler:
|
||||
var pool = await _context.Commissions.GetWeeklyCommissionPoolAsync(
|
||||
new GetWeeklyCommissionPoolRequest { WeekNumber = "2025-W48" });
|
||||
|
||||
Console.WriteLine($"Total Pool Value: {pool.TotalPoolValue}");
|
||||
Console.WriteLine($"Active Members: {pool.ActiveMembersCount}");
|
||||
```
|
||||
|
||||
**Expected Output**:
|
||||
```
|
||||
Total Pool Value: 50000000
|
||||
Active Members: 120
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Test with Postman/Swagger:
|
||||
|
||||
1. Start BackOffice.BFF:
|
||||
```bash
|
||||
cd /home/masoud/Apps/project/FourSat/BackOffice.BFF/src
|
||||
dotnet run --project BackOffice.BFF.WebApi
|
||||
```
|
||||
|
||||
2. Call API endpoint (example):
|
||||
```http
|
||||
GET /api/commission/weekly-pool?weekNumber=2025-W48
|
||||
Authorization: Bearer {your-token}
|
||||
```
|
||||
|
||||
3. Expected Response:
|
||||
```json
|
||||
{
|
||||
"weekNumber": "2025-W48",
|
||||
"totalPoolValue": 50000000,
|
||||
"activeMembersCount": 120,
|
||||
"isCalculated": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Status & Metrics
|
||||
|
||||
| Component | Status | Version | Notes |
|
||||
|-----------|--------|---------|-------|
|
||||
| **CMS Protobuf Package** | ✅ Active | 0.0.140 | With Network-Club-Commission |
|
||||
| **gRPC Connection** | ✅ Configured | - | https://cms.kbs1.ir |
|
||||
| **Auto-Registration** | ✅ Active | - | Via BatchRegisterGrpcClients |
|
||||
| **Commission Client** | ✅ Ready | - | All commands & queries available |
|
||||
| **Network Client** | ✅ Ready | - | Binary tree queries available |
|
||||
| **Club Client** | ✅ Ready | - | Activation/Deactivation available |
|
||||
| **Authentication** | ✅ Configured | JWT | Via ITokenProvider |
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Related Documentation
|
||||
|
||||
### CMS Side:
|
||||
- **Implementation Progress**: `/CMS/docs/implementation-progress.md`
|
||||
- **Network System Design**: `/CMS/docs/network-club-commission-system.md`
|
||||
- **Monitoring Setup**: `/CMS/docs/monitoring-alerts-consolidated-report.md`
|
||||
- **Migration Guide**: `/CMS/docs/migration-network-parent-guide.md`
|
||||
- **Binary Tree Registration**: `/CMS/docs/binary-tree-registration-guide.md`
|
||||
|
||||
### BFF Side:
|
||||
- **This Document**: `/BackOffice.BFF/docs/cms-integration.md`
|
||||
- **README**: `/BackOffice.BFF/README.md`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
### Immediate:
|
||||
1. ✅ Integration completed
|
||||
2. ⏳ Create Commission/Network/Club CQRS handlers in BFF
|
||||
3. ⏳ Add API endpoints in BackOffice.BFF.WebApi
|
||||
4. ⏳ Test integration with real data
|
||||
|
||||
### Short-term:
|
||||
5. ⏳ Add Swagger documentation for new endpoints
|
||||
6. ⏳ Implement error handling for gRPC calls
|
||||
7. ⏳ Add logging for commission operations
|
||||
8. ⏳ Create admin dashboard for network visualization
|
||||
|
||||
### Long-term:
|
||||
9. ⏳ Add real-time notifications (SignalR) for commission updates
|
||||
10. ⏳ Implement caching for frequently accessed data
|
||||
11. ⏳ Add reporting/analytics endpoints
|
||||
12. ⏳ Performance optimization for large network trees
|
||||
|
||||
---
|
||||
|
||||
## 📞 Troubleshooting
|
||||
|
||||
### Issue 1: gRPC Connection Failed
|
||||
|
||||
**Error**: `Status(StatusCode="Unavailable", Detail="...")`
|
||||
|
||||
**Solutions**:
|
||||
1. Check CMS service is running: `https://cms.kbs1.ir`
|
||||
2. Verify network connectivity
|
||||
3. Check firewall settings
|
||||
4. Verify SSL certificate is valid
|
||||
|
||||
---
|
||||
|
||||
### Issue 2: Authentication Failed
|
||||
|
||||
**Error**: `Status(StatusCode="Unauthenticated", Detail="...")`
|
||||
|
||||
**Solutions**:
|
||||
1. Verify `ITokenProvider` is registered in DI
|
||||
2. Check JWT token is valid and not expired
|
||||
3. Verify token has correct claims/permissions
|
||||
4. Check Authorization header is being sent
|
||||
|
||||
---
|
||||
|
||||
### Issue 3: Package Version Mismatch
|
||||
|
||||
**Error**: `The type or namespace 'CommissionContract' could not be found`
|
||||
|
||||
**Solutions**:
|
||||
1. Update package version in `.csproj`:
|
||||
```xml
|
||||
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.140" />
|
||||
```
|
||||
2. Run `dotnet restore`
|
||||
3. Clean and rebuild solution
|
||||
|
||||
---
|
||||
|
||||
### Issue 4: Method Not Found
|
||||
|
||||
**Error**: `Method 'GetWeeklyPool' not found on service 'CommissionContract'`
|
||||
|
||||
**Solutions**:
|
||||
1. Verify CMS service has the latest code deployed
|
||||
2. Check Protobuf contract matches between CMS and BFF
|
||||
3. Update both CMS and BFF to latest versions
|
||||
4. Restart both services
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Summary
|
||||
|
||||
### ✅ Completed:
|
||||
- CMS Protobuf package updated to 0.0.140
|
||||
- 3 new gRPC clients added to BFF:
|
||||
* CommissionContract (8+ methods)
|
||||
* NetworkMembershipContract (6+ methods)
|
||||
* ClubMembershipContract (4+ methods)
|
||||
- Auto-registration configured
|
||||
- Authentication via JWT configured
|
||||
- Build successful (0 errors)
|
||||
|
||||
### ⏳ Pending:
|
||||
- Create CQRS handlers for Commission operations
|
||||
- Create CQRS handlers for Network operations
|
||||
- Create CQRS handlers for Club operations
|
||||
- Add API Controllers/Endpoints
|
||||
- Add Swagger documentation
|
||||
- Integration testing
|
||||
|
||||
### 🔑 Key Points:
|
||||
- **No manual registration needed**: gRPC clients auto-register via `BatchRegisterGrpcClients()`
|
||||
- **Authentication handled**: JWT token automatically added to all requests
|
||||
- **Type-safe**: All Protobuf contracts are strongly typed
|
||||
- **Easy to use**: Simple interface via `IApplicationContractContext`
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-11-30
|
||||
**Build Status**: ✅ Success
|
||||
**Ready for**: Handler implementation & API endpoint creation
|
||||
@@ -0,0 +1,798 @@
|
||||
# BackOffice.BFF - Discount Shop Integration Plan
|
||||
|
||||
**تاریخ ایجاد**: 1403/09/13 (2024-12-04)
|
||||
**آخرین بروزرسانی**: 1403/10/11 (2024-12-31)
|
||||
**وضعیت**: ✅ پیادهسازی کامل (شامل Image Gallery و Admin Reports)
|
||||
**اولویت در زمان طراحی**: 🔴 بالا
|
||||
|
||||
---
|
||||
|
||||
## 📊 خلاصه وضعیت
|
||||
|
||||
### ✅ تکمیل شده در CMS
|
||||
- **Phase 9: Club Discount Shop System** - 100% ✅
|
||||
- 6 Entities (Category, Product, Cart, Order)
|
||||
- 13 Commands + 6 Queries + 9 Validators
|
||||
- 4 Proto Files (19 gRPC RPCs)
|
||||
- 4 gRPC Services
|
||||
- Migration: AddDiscountShopSystem
|
||||
|
||||
- **Phase 10: Product Image Gallery** - 100% ✅ (جدید)
|
||||
- 5 عملیات جدید: Add/Update/Delete/Reorder/Get Images
|
||||
- 2 Command + 3 RPC جدید
|
||||
- پشتیبانی از چندین تصویر برای هر محصول
|
||||
|
||||
- **Phase 11: Admin Order Reports** - 100% ✅ (جدید)
|
||||
- GetAllDiscountOrders: لیست کامل سفارشات با فیلتر و صفحهبندی
|
||||
- GetDiscountSalesReport: گزارش فروش با فیلتر تاریخ و نوع گزارش
|
||||
|
||||
### ✅ وضعیت در BackOffice.BFF (تکمیل شده)
|
||||
- **26 Handler** برای 6 سرویس → ✅ پیادهسازی و متصل به CMS
|
||||
- 19 Handler اصلی + 5 Handler گالری تصاویر + 2 Handler گزارش سفارشات
|
||||
- **2 gRPC Service در WebApi** → ✅ جدید
|
||||
- `DiscountProductService.cs` با 10 RPC endpoint
|
||||
- `DiscountOrderService.cs` با 7 RPC endpoint
|
||||
- **4 Client Interface** در `IApplicationContractContext` → ✅ اضافه و در `ApplicationContractContext` پیادهسازی شده
|
||||
- **Test و Validation** → ✅ در BackOffice UI (DiscountShop صفحات و سرویسها) در حال استفاده عملی
|
||||
|
||||
> این سند بهعنوان **طرح اولیه** نگهداری میشود؛ برای وضعیت نهایی به `totalDoc/05-TASKS/BACKLOG.md` (بخش Discount Shop - BackOffice Integration ✅) و `totalDoc/04-FRONTEND/BackOffice/ui-status.md` مراجعه شود.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 امکانات جدید برای Admin Panel
|
||||
|
||||
### 1️⃣ مدیریت محصولات فروشگاه تخفیفی (5 API)
|
||||
|
||||
**سرویس**: `DiscountProductContract`
|
||||
|
||||
#### الف. ایجاد محصول جدید
|
||||
- **Handler**: `CreateDiscountProductHandler`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- Title (عنوان محصول)
|
||||
- ShortInfomation (توضیحات کوتاه)
|
||||
- FullInformation (توضیحات کامل)
|
||||
- Price (قیمت به تومان)
|
||||
- MaxDiscountPercent (حداکثر درصد تخفیف قابل استفاده از کیف پول تخفیف - 0 تا 100)
|
||||
- ImagePath (مسیر تصویر اصلی)
|
||||
- ThumbnailPath (مسیر تصویر کوچک)
|
||||
- InitialCount (تعداد اولیه موجودی)
|
||||
- SortOrder (ترتیب نمایش)
|
||||
- IsActive (فعال/غیرفعال)
|
||||
- CategoryIds (لیست شناسه دستهبندیها)
|
||||
```
|
||||
- **Response**: ProductId (شناسه محصول ایجاد شده)
|
||||
- **کاربرد Admin**: ایجاد محصول جدید در فروشگاه تخفیفی
|
||||
|
||||
#### ب. ویرایش محصول
|
||||
- **Handler**: `UpdateDiscountProductHandler`
|
||||
- **Request**: همان فیلدهای بالا + ProductId
|
||||
- **کاربرد Admin**: ویرایش اطلاعات محصول موجود
|
||||
|
||||
#### ج. حذف محصول
|
||||
- **Handler**: `DeleteDiscountProductHandler`
|
||||
- **Request**: ProductId
|
||||
- **کاربرد Admin**: حذف محصول از فروشگاه
|
||||
|
||||
#### د. دریافت جزئیات محصول
|
||||
- **Handler**: `GetDiscountProductByIdHandler`
|
||||
- **Request**: ProductId
|
||||
- **Response**: تمام اطلاعات محصول + لیست دستهبندیها + موجودی باقیمانده
|
||||
- **کاربرد Admin**: مشاهده جزئیات کامل یک محصول
|
||||
|
||||
#### ه. لیست محصولات با فیلتر
|
||||
- **Handler**: `GetDiscountProductsHandler`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- CategoryId (nullable - فیلتر بر اساس دستهبندی)
|
||||
- SearchQuery (nullable - جستجو در عنوان و توضیحات)
|
||||
- MinPrice (nullable - حداقل قیمت)
|
||||
- MaxPrice (nullable - حداکثر قیمت)
|
||||
- IsActive (nullable - فیلتر فعال/غیرفعال)
|
||||
- InStock (nullable - فقط موجود در انبار)
|
||||
- PageNumber (شماره صفحه)
|
||||
- PageSize (تعداد آیتم در صفحه)
|
||||
```
|
||||
- **Response**:
|
||||
```csharp
|
||||
- MetaData (اطلاعات صفحهبندی)
|
||||
- Models (لیست محصولات)
|
||||
```
|
||||
- **کاربرد Admin**: مدیریت و جستجوی محصولات
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ مدیریت دستهبندی محصولات (4 API)
|
||||
|
||||
**سرویس**: `DiscountCategoryContract`
|
||||
|
||||
#### الف. ایجاد دستهبندی جدید
|
||||
- **Handler**: `CreateDiscountCategoryHandler`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- Name (نام لاتین برای URL)
|
||||
- Title (عنوان فارسی)
|
||||
- Description (nullable - توضیحات)
|
||||
- ImagePath (nullable - تصویر دستهبندی)
|
||||
- ParentCategoryId (nullable - دستهبندی والد برای ساختار درختی)
|
||||
- SortOrder (ترتیب نمایش)
|
||||
- IsActive (فعال/غیرفعال)
|
||||
```
|
||||
- **Response**: CategoryId
|
||||
- **کاربرد Admin**: ایجاد دستهبندی جدید (با قابلیت ساختار چند سطحی)
|
||||
|
||||
#### ب. ویرایش دستهبندی
|
||||
- **Handler**: `UpdateDiscountCategoryHandler`
|
||||
- **Request**: همان فیلدهای بالا + CategoryId
|
||||
- **کاربرد Admin**: ویرایش دستهبندی موجود
|
||||
|
||||
#### ج. حذف دستهبندی
|
||||
- **Handler**: `DeleteDiscountCategoryHandler`
|
||||
- **Request**: CategoryId
|
||||
- **Response**: Success/Failure
|
||||
- **Logic**:
|
||||
- چک میکند اگر این دستهبندی زیرمجموعه دارد → خطا
|
||||
- چک میکند اگر محصولی به این دستهبندی متصل است → خطا
|
||||
- در غیر این صورت حذف میشود
|
||||
- **کاربرد Admin**: حذف ایمن دستهبندی
|
||||
|
||||
#### د. دریافت درخت دستهبندیها
|
||||
- **Handler**: `GetDiscountCategoriesHandler`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- ParentCategoryId (nullable)
|
||||
* اگر null باشد: دستهبندیهای ریشه (Root) برگردانده میشود
|
||||
* اگر مقدار داشته باشد: زیرمجموعههای آن دستهبندی برگردانده میشود
|
||||
- IsActive (nullable - فیلتر فعال/غیرفعال)
|
||||
```
|
||||
- **Response**:
|
||||
```csharp
|
||||
- List<DiscountCategoryDto> (ساختار recursive با Children)
|
||||
```
|
||||
- **کاربرد Admin**: مشاهده ساختار درختی دستهبندیها
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ مدیریت سبد خرید کاربران (5 API)
|
||||
|
||||
**سرویس**: `DiscountShoppingCartContract`
|
||||
|
||||
> **توجه**: این APIها در Admin Panel کمتر استفاده میشوند، اما برای Support و Troubleshooting مفید هستند.
|
||||
|
||||
#### الف. افزودن به سبد خرید (Support)
|
||||
- **Handler**: `AddToCartHandler`
|
||||
- **Request**: UserId, ProductId, Count
|
||||
- **کاربرد Admin**: کمک به کاربر در افزودن محصول به سبد (Support)
|
||||
|
||||
#### ب. حذف از سبد خرید (Support)
|
||||
- **Handler**: `RemoveFromCartHandler`
|
||||
- **Request**: UserId, ProductId
|
||||
- **کاربرد Admin**: کمک به کاربر در حذف آیتم از سبد
|
||||
|
||||
#### ج. تغییر تعداد آیتم (Support)
|
||||
- **Handler**: `UpdateCartItemCountHandler`
|
||||
- **Request**: UserId, ProductId, NewCount
|
||||
- **کاربرد Admin**: اصلاح تعداد آیتم در سبد کاربر
|
||||
|
||||
#### د. مشاهده سبد خرید کاربر
|
||||
- **Handler**: `GetUserCartHandler`
|
||||
- **Request**: UserId
|
||||
- **Response**:
|
||||
```csharp
|
||||
- List<CartItemDto>
|
||||
* ProductId
|
||||
* ProductTitle
|
||||
* ProductImagePath
|
||||
* UnitPrice (قیمت واحد)
|
||||
* MaxDiscountPercent
|
||||
* Count (تعداد)
|
||||
* TotalPrice (قیمت کل = UnitPrice × Count)
|
||||
* DiscountAmount (مقدار تخفیف قابل استفاده)
|
||||
* FinalPrice (قیمت نهایی بعد از تخفیف)
|
||||
* ProductRemainingCount (موجودی باقیمانده)
|
||||
- TotalPrice (مجموع قیمت کل سبد)
|
||||
- TotalDiscountAmount (مجموع تخفیف قابل استفاده)
|
||||
- FinalPrice (مجموع قیمت نهایی)
|
||||
```
|
||||
- **کاربرد Admin**: بررسی سبد خرید کاربر برای Support
|
||||
|
||||
#### ه. پاک کردن سبد خرید
|
||||
- **Handler**: `ClearCartHandler`
|
||||
- **Request**: UserId
|
||||
- **کاربرد Admin**: پاک کردن کامل سبد خرید کاربر (در صورت نیاز)
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ مدیریت سفارشات فروشگاه تخفیفی (5 API)
|
||||
|
||||
**سرویس**: `DiscountOrderContract`
|
||||
|
||||
#### الف. ثبت سفارش (کمتر استفاده میشود در Admin)
|
||||
- **Handler**: `PlaceOrderHandler`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- UserId
|
||||
- UserAddressId
|
||||
- DiscountBalanceToUse (مقدار کیف پول تخفیف برای استفاده)
|
||||
- Notes (nullable - یادداشت)
|
||||
```
|
||||
- **Response**:
|
||||
```csharp
|
||||
- Success
|
||||
- Message
|
||||
- OrderId
|
||||
- GatewayAmount (مبلغ باقیمانده برای پرداخت از طریق درگاه)
|
||||
- PaymentUrl (nullable - لینک پرداخت)
|
||||
```
|
||||
- **کاربرد Admin**: ثبت سفارش دستی برای کاربر (نادر)
|
||||
|
||||
#### ب. تکمیل پرداخت سفارش (کمتر استفاده میشود)
|
||||
- **Handler**: `CompleteOrderPaymentHandler`
|
||||
- **Request**: OrderId, TransactionId, PaymentSuccess
|
||||
- **کاربرد Admin**: تایید دستی پرداخت (در صورت مشکل)
|
||||
|
||||
#### ج. تغییر وضعیت ارسال سفارش ⭐ **مهم**
|
||||
- **Handler**: `UpdateOrderStatusHandler`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- OrderId
|
||||
- NewStatus (enum: Pending, Processing, Shipped, Delivered, Cancelled)
|
||||
- TrackingCode (nullable - کد رهگیری پست)
|
||||
- AdminNotes (nullable - یادداشت ادمین)
|
||||
```
|
||||
- **Response**: Success, Message
|
||||
- **کاربرد Admin**:
|
||||
- تغییر وضعیت سفارش به "در حال پردازش"
|
||||
- ثبت کد رهگیری پست
|
||||
- تغییر وضعیت به "ارسال شده"
|
||||
- تایید تحویل
|
||||
- لغو سفارش
|
||||
|
||||
#### د. مشاهده جزئیات سفارش ⭐ **مهم**
|
||||
- **Handler**: `GetOrderByIdHandler`
|
||||
- **Request**: OrderId
|
||||
- **Response**:
|
||||
```csharp
|
||||
- OrderId
|
||||
- UserId
|
||||
- UserName (nullable)
|
||||
- Address (AddressInfo)
|
||||
* Title
|
||||
* Address
|
||||
* PostalCode
|
||||
- OrderItems (List)
|
||||
* ProductId
|
||||
* ProductTitle
|
||||
* ProductPrice (قیمت اسنپشات در زمان خرید)
|
||||
* MaxDiscountPercent
|
||||
* Count
|
||||
* TotalPrice
|
||||
* DiscountAmount
|
||||
* FinalPrice
|
||||
- TotalPrice (مجموع قیمت)
|
||||
- DiscountBalanceUsed (مقدار استفاده شده از کیف پول تخفیف)
|
||||
- GatewayAmount (مبلغ پرداخت شده از درگاه)
|
||||
- PaymentTransactionId (nullable)
|
||||
- DeliveryStatus (enum)
|
||||
- TrackingCode (nullable)
|
||||
- AdminNotes (nullable)
|
||||
- Notes (یادداشت کاربر)
|
||||
- OrderDate
|
||||
- PaymentDate (nullable)
|
||||
```
|
||||
- **کاربرد Admin**: بررسی کامل سفارش
|
||||
|
||||
#### ه. لیست سفارشات کاربر ⭐ **مهم**
|
||||
- **Handler**: `GetUserOrdersHandler`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- UserId
|
||||
- PageNumber
|
||||
- PageSize
|
||||
```
|
||||
- **Response**:
|
||||
```csharp
|
||||
- MetaData (صفحهبندی)
|
||||
- Models (List<OrderSummaryDto>)
|
||||
* OrderId
|
||||
* TotalPrice
|
||||
* DiscountBalanceUsed
|
||||
* GatewayAmount
|
||||
* DeliveryStatus
|
||||
* ItemsCount (تعداد آیتمهای سفارش)
|
||||
* OrderDate
|
||||
```
|
||||
- **کاربرد Admin**: مشاهده تاریخچه سفارشات کاربر
|
||||
|
||||
---
|
||||
|
||||
### 5️⃣ مدیریت گالری تصاویر محصولات (5 API جدید) 🆕
|
||||
|
||||
**سرویس**: `DiscountProductContract`
|
||||
|
||||
> **توجه**: این APIها برای مدیریت چندین تصویر برای هر محصول استفاده میشوند (گالری تصاویر).
|
||||
|
||||
#### الف. افزودن تصویر به گالری ⭐ **مهم**
|
||||
- **Handler**: `AddDiscountProductImageCommandHandler`
|
||||
- **Command**: `AddDiscountProductImageCommand`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- ProductId (Guid)
|
||||
- Image (ImageFileModel)
|
||||
* File (byte[])
|
||||
* FileName (string)
|
||||
* Mime (string)
|
||||
- SortOrder (int - ترتیب نمایش)
|
||||
- IsMain (bool - آیا تصویر اصلی است؟)
|
||||
```
|
||||
- **Response**: ImageId (Guid)
|
||||
- **کاربرد Admin**: افزودن تصاویر جدید به گالری محصول
|
||||
|
||||
#### ب. ویرایش تصویر گالری
|
||||
- **Handler**: `UpdateDiscountProductImageCommandHandler`
|
||||
- **Command**: `UpdateDiscountProductImageCommand`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- ImageId (Guid)
|
||||
- ProductId (Guid)
|
||||
- NewImage (ImageFileModel - اختیاری)
|
||||
- SortOrder (int)
|
||||
- IsMain (bool)
|
||||
```
|
||||
- **Response**: Success/Failure
|
||||
- **کاربرد Admin**: تغییر تصویر موجود یا تغییر ترتیب/اصلی بودن
|
||||
|
||||
#### ج. حذف تصویر از گالری
|
||||
- **Handler**: `DeleteDiscountProductImageCommandHandler`
|
||||
- **Command**: `DeleteDiscountProductImageCommand`
|
||||
- **Request**: ImageId (Guid), ProductId (Guid)
|
||||
- **Response**: Success/Failure
|
||||
- **کاربرد Admin**: حذف تصویر از گالری محصول
|
||||
|
||||
#### د. تغییر ترتیب تصاویر ⭐ **مهم**
|
||||
- **Handler**: `ReorderDiscountProductImagesCommandHandler`
|
||||
- **Command**: `ReorderDiscountProductImagesCommand`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- ProductId (Guid)
|
||||
- ImageOrders (List)
|
||||
* ImageId (Guid)
|
||||
* SortOrder (int)
|
||||
```
|
||||
- **Response**: Success/Failure
|
||||
- **کاربرد Admin**: تغییر ترتیب نمایش تصاویر با drag & drop
|
||||
|
||||
#### ه. دریافت لیست تصاویر محصول
|
||||
- **Handler**: `GetDiscountProductImagesQueryHandler`
|
||||
- **Query**: `GetDiscountProductImagesQuery`
|
||||
- **Request**: ProductId (Guid)
|
||||
- **Response**:
|
||||
```csharp
|
||||
- List<ProductImageDto>
|
||||
* ImageId (Guid)
|
||||
* ImagePath (string)
|
||||
* SortOrder (int)
|
||||
* IsMain (bool)
|
||||
* CreatedAt (DateTime)
|
||||
```
|
||||
- **کاربرد Admin**: نمایش گالری تصاویر محصول
|
||||
|
||||
---
|
||||
|
||||
### 6️⃣ گزارشات مدیریتی سفارشات (2 API جدید) 🆕
|
||||
|
||||
**سرویس**: `DiscountOrderContract`
|
||||
|
||||
> **توجه**: این APIها برای گزارشگیری و مدیریت کلی سفارشات توسط ادمین استفاده میشوند.
|
||||
|
||||
#### الف. لیست کامل سفارشات ⭐⭐⭐ **خیلی مهم**
|
||||
- **Handler**: `GetAllDiscountOrdersQueryHandler`
|
||||
- **Query**: `GetAllDiscountOrdersQuery`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- PageNumber (int - پیشفرض: 1)
|
||||
- PageSize (int - پیشفرض: 10)
|
||||
- UserId (Guid? - فیلتر کاربر)
|
||||
- Status (DeliveryStatus? - فیلتر وضعیت)
|
||||
- FromDate (DateTime? - از تاریخ)
|
||||
- ToDate (DateTime? - تا تاریخ)
|
||||
- SearchTerm (string? - جستجو در شماره سفارش/نام کاربر)
|
||||
```
|
||||
- **Response**:
|
||||
```csharp
|
||||
- MetaData (PaginationMetaData)
|
||||
* PageNumber
|
||||
* PageSize
|
||||
* TotalCount
|
||||
* TotalPages
|
||||
- Models (List<OrderSummaryDto>)
|
||||
* OrderId
|
||||
* UserId
|
||||
* UserName
|
||||
* TotalPrice
|
||||
* DiscountBalanceUsed
|
||||
* GatewayAmount
|
||||
* VatAmount (مالیات ارزش افزوده)
|
||||
* DeliveryStatus
|
||||
* ItemsCount
|
||||
* OrderDate
|
||||
* PaymentDate
|
||||
```
|
||||
- **کاربرد Admin**: مشاهده و فیلتر تمام سفارشات فروشگاه تخفیفی
|
||||
|
||||
#### ب. گزارش فروش ⭐⭐ **مهم**
|
||||
- **Handler**: `GetDiscountSalesReportQueryHandler`
|
||||
- **Query**: `GetDiscountSalesReportQuery`
|
||||
- **Request**:
|
||||
```csharp
|
||||
- FromDate (DateTime? - شروع بازه)
|
||||
- ToDate (DateTime? - پایان بازه)
|
||||
- ReportType (enum: Daily, Weekly, Monthly)
|
||||
```
|
||||
- **Response**:
|
||||
```csharp
|
||||
- SalesReportDto
|
||||
* TotalOrders (int - تعداد کل سفارشات)
|
||||
* TotalRevenue (decimal - مجموع درآمد)
|
||||
* TotalVat (decimal - مجموع مالیات)
|
||||
* TotalDiscountUsed (decimal - مجموع تخفیف استفاده شده)
|
||||
* AverageOrderValue (decimal - میانگین ارزش سفارش)
|
||||
* TopSellingProducts (List)
|
||||
- ProductId
|
||||
- ProductTitle
|
||||
- TotalSold
|
||||
- TotalRevenue
|
||||
* OrdersByStatus (Dictionary<DeliveryStatus, int>)
|
||||
* DailyBreakdown (List - جزئیات روزانه)
|
||||
- Date
|
||||
- OrderCount
|
||||
- Revenue
|
||||
- VatAmount
|
||||
```
|
||||
- **کاربرد Admin**: تحلیل عملکرد فروش و گزارشگیری دورهای
|
||||
|
||||
---
|
||||
|
||||
## 📋 لیست کامل Handlerهای مورد نیاز
|
||||
|
||||
### ✅ موجود در BackOffice.BFF (35 Handler)
|
||||
1. User Management (7)
|
||||
2. Product Management (5)
|
||||
3. Order Management (5)
|
||||
4. Category/Tag (4)
|
||||
5. Role & Permission (3)
|
||||
6. Commission System (4)
|
||||
7. Network Membership (3)
|
||||
8. Club Membership (4)
|
||||
|
||||
### ✅ تکمیل شده (26 Handler)
|
||||
|
||||
#### گروه 1: Discount Product (5 Handlers)
|
||||
1. ✅ `CreateDiscountProductHandler`
|
||||
2. ✅ `UpdateDiscountProductHandler`
|
||||
3. ✅ `DeleteDiscountProductHandler`
|
||||
4. ✅ `GetDiscountProductByIdHandler`
|
||||
5. ✅ `GetDiscountProductsHandler`
|
||||
|
||||
#### گروه 2: Discount Category (4 Handlers)
|
||||
6. ✅ `CreateDiscountCategoryHandler`
|
||||
7. ✅ `UpdateDiscountCategoryHandler`
|
||||
8. ✅ `DeleteDiscountCategoryHandler`
|
||||
9. ✅ `GetDiscountCategoriesHandler`
|
||||
|
||||
#### گروه 3: Discount Shopping Cart (5 Handlers)
|
||||
10. ✅ `AddToCartHandler` (برای Support)
|
||||
11. ✅ `RemoveFromCartHandler` (برای Support)
|
||||
12. ✅ `UpdateCartItemCountHandler` (برای Support)
|
||||
13. ✅ `GetUserCartHandler` ⭐
|
||||
14. ✅ `ClearCartHandler`
|
||||
|
||||
#### گروه 4: Discount Order (5 Handlers)
|
||||
15. ✅ `PlaceOrderHandler` (کمتر استفاده میشود)
|
||||
16. ✅ `CompleteOrderPaymentHandler` (کمتر استفاده میشود)
|
||||
17. ✅ `UpdateOrderStatusHandler` ⭐⭐⭐ **خیلی مهم**
|
||||
18. ✅ `GetOrderByIdHandler` ⭐⭐⭐ **خیلی مهم**
|
||||
19. ✅ `GetUserOrdersHandler` ⭐⭐ **مهم**
|
||||
|
||||
#### گروه 5: Product Image Gallery (5 Handlers) 🆕
|
||||
20. ✅ `AddDiscountProductImageCommandHandler` ⭐ **جدید**
|
||||
21. ✅ `UpdateDiscountProductImageCommandHandler` **جدید**
|
||||
22. ✅ `DeleteDiscountProductImageCommandHandler` **جدید**
|
||||
23. ✅ `ReorderDiscountProductImagesCommandHandler` ⭐ **جدید**
|
||||
24. ✅ `GetDiscountProductImagesQueryHandler` **جدید**
|
||||
|
||||
#### گروه 6: Admin Order Reports (2 Handlers) 🆕
|
||||
25. ✅ `GetAllDiscountOrdersQueryHandler` ⭐⭐⭐ **جدید - خیلی مهم**
|
||||
26. ✅ `GetDiscountSalesReportQueryHandler` ⭐⭐ **جدید - مهم**
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ تغییرات مورد نیاز در BackOffice.BFF
|
||||
|
||||
### 1️⃣ آپدیت IApplicationContractContext
|
||||
|
||||
**فایل**: `/BackOffice.BFF/src/BackOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs`
|
||||
|
||||
```csharp
|
||||
public interface IApplicationContractContext
|
||||
{
|
||||
// ... existing services ...
|
||||
|
||||
// Discount Shop System (NEW - Phase 9)
|
||||
DiscountProductContract.DiscountProductContractClient DiscountProducts { get; }
|
||||
DiscountCategoryContract.DiscountCategoryContractClient DiscountCategories { get; }
|
||||
DiscountShoppingCartContract.DiscountShoppingCartContractClient DiscountShoppingCarts { get; }
|
||||
DiscountOrderContract.DiscountOrderContractClient DiscountOrders { get; }
|
||||
}
|
||||
```
|
||||
|
||||
### 2️⃣ پیادهسازی در ApplicationContractContext
|
||||
|
||||
**فایل**: `/BackOffice.BFF/src/BackOffice.BFF.Infrastructure/Persistence/ApplicationContractContext.cs`
|
||||
|
||||
```csharp
|
||||
public class ApplicationContractContext : IApplicationContractContext
|
||||
{
|
||||
// ... existing implementations ...
|
||||
|
||||
// Discount Shop System (NEW)
|
||||
public DiscountProductContract.DiscountProductContractClient DiscountProducts { get; }
|
||||
public DiscountCategoryContract.DiscountCategoryContractClient DiscountCategories { get; }
|
||||
public DiscountShoppingCartContract.DiscountShoppingCartContractClient DiscountShoppingCarts { get; }
|
||||
public DiscountOrderContract.DiscountOrderContractClient DiscountOrders { get; }
|
||||
|
||||
public ApplicationContractContext(GrpcChannel channel)
|
||||
{
|
||||
// ... existing initializations ...
|
||||
|
||||
// Discount Shop System
|
||||
DiscountProducts = new DiscountProductContract.DiscountProductContractClient(channel);
|
||||
DiscountCategories = new DiscountCategoryContract.DiscountCategoryContractClient(channel);
|
||||
DiscountShoppingCarts = new DiscountShoppingCartContract.DiscountShoppingCartContractClient(channel);
|
||||
DiscountOrders = new DiscountOrderContract.DiscountOrderContractClient(channel);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3️⃣ ایجاد Handlerها
|
||||
|
||||
**ساختار فولدر**:
|
||||
```
|
||||
BackOffice.BFF.Application/
|
||||
└── DiscountShop/
|
||||
├── Products/
|
||||
│ ├── CreateDiscountProduct/
|
||||
│ │ ├── CreateDiscountProductCommand.cs
|
||||
│ │ └── CreateDiscountProductHandler.cs
|
||||
│ ├── UpdateDiscountProduct/
|
||||
│ ├── DeleteDiscountProduct/
|
||||
│ ├── GetDiscountProductById/
|
||||
│ └── GetDiscountProducts/
|
||||
├── Categories/
|
||||
│ ├── CreateDiscountCategory/
|
||||
│ ├── UpdateDiscountCategory/
|
||||
│ ├── DeleteDiscountCategory/
|
||||
│ └── GetDiscountCategories/
|
||||
├── Cart/
|
||||
│ ├── AddToCart/
|
||||
│ ├── RemoveFromCart/
|
||||
│ ├── UpdateCartItemCount/
|
||||
│ ├── GetUserCart/
|
||||
│ └── ClearCart/
|
||||
└── Orders/
|
||||
├── PlaceOrder/
|
||||
├── CompleteOrderPayment/
|
||||
├── UpdateOrderStatus/
|
||||
├── GetOrderById/
|
||||
└── GetUserOrders/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 UI Pages مورد نیاز در BackOffice
|
||||
|
||||
### صفحات جدید (6 صفحه)
|
||||
|
||||
1. **صفحه لیست محصولات فروشگاه تخفیفی** (2 روز)
|
||||
- `Pages/DiscountShop/Products/ProductsList.razor`
|
||||
- DataGrid با فیلترها
|
||||
- دکمههای Create, Edit, Delete
|
||||
- نمایش موجودی و MaxDiscountPercent
|
||||
|
||||
2. **صفحه ایجاد/ویرایش محصول** (1 روز)
|
||||
- `Pages/DiscountShop/Products/ProductForm.razor`
|
||||
- فرم کامل با تمام فیلدها
|
||||
- انتخاب چندتایی دستهبندی
|
||||
- آپلود تصویر
|
||||
|
||||
3. **صفحه مدیریت دستهبندیها** (1.5 روز)
|
||||
- `Pages/DiscountShop/Categories/CategoriesList.razor`
|
||||
- نمایش درختی (Tree View)
|
||||
- قابلیت Drag & Drop برای تغییر Parent
|
||||
- Dialog ایجاد/ویرایش
|
||||
|
||||
4. **صفحه لیست سفارشات فروشگاه** (2 روز)
|
||||
- `Pages/DiscountShop/Orders/OrdersList.razor`
|
||||
- DataGrid با فیلترها (Status, Date Range, User)
|
||||
- نمایش خلاصه: TotalPrice, DiscountUsed, GatewayAmount
|
||||
- دکمه View Details
|
||||
|
||||
5. **صفحه جزئیات سفارش** (1.5 روز)
|
||||
- `Pages/DiscountShop/Orders/OrderDetails.razor`
|
||||
- نمایش کامل اطلاعات سفارش
|
||||
- لیست آیتمهای سفارش
|
||||
- **تغییر وضعیت ارسال** (Dropdown)
|
||||
- ثبت کد رهگیری
|
||||
- یادداشت ادمین
|
||||
|
||||
6. **صفحه مشاهده سبد خرید کاربر** (1 روز)
|
||||
- `Pages/DiscountShop/Support/UserCart.razor`
|
||||
- برای Support و Troubleshooting
|
||||
- نمایش محاسبات تخفیف
|
||||
- قابلیت اصلاح (Add/Remove/Update)
|
||||
|
||||
**جمع زمان UI**: **9 روز**
|
||||
|
||||
---
|
||||
|
||||
## 📊 گزارشات مالی جدید (اختیاری - اولویت متوسط)
|
||||
|
||||
### گزارشات پیشنهادی:
|
||||
|
||||
1. **گزارش فروش فروشگاه تخفیفی**
|
||||
- مجموع فروش (TotalPrice)
|
||||
- مجموع تخفیف استفاده شده (DiscountBalanceUsed)
|
||||
- مجموع پرداخت از درگاه (GatewayAmount)
|
||||
- تفکیک بر اساس تاریخ، محصول، دستهبندی
|
||||
|
||||
2. **گزارش محبوبترین محصولات**
|
||||
- تعداد فروش هر محصول
|
||||
- مجموع درآمد
|
||||
- میانگین استفاده از تخفیف
|
||||
|
||||
3. **گزارش وضعیت موجودی**
|
||||
- محصولات کم موجودی (RemainingCount < حد آستانه)
|
||||
- هشدار اتمام موجودی
|
||||
|
||||
4. **گزارش استفاده از کیف پول تخفیف**
|
||||
- کاربران برتر در استفاده از تخفیف
|
||||
- میانگین درصد استفاده از تخفیف
|
||||
- مقایسه با فروش کل
|
||||
|
||||
---
|
||||
|
||||
## ⏱️ تخمین زمان پیادهسازی
|
||||
|
||||
### BackOffice.BFF (Backend)
|
||||
| مرحله | زمان | توضیحات |
|
||||
|-------|------|---------|
|
||||
| آپدیت Interface & Context | 30 دقیقه | اضافه کردن 4 Client |
|
||||
| ایجاد 19 Handler | 3 روز | ~20 دقیقه هر Handler |
|
||||
| Test & Debug | 1 روز | تست تمام Handlerها |
|
||||
| **جمع** | **4 روز** | |
|
||||
|
||||
### BackOffice UI (Frontend)
|
||||
| مرحله | زمان | توضیحات |
|
||||
|-------|------|---------|
|
||||
| صفحات محصولات (2 صفحه) | 3 روز | List + Form |
|
||||
| صفحات دستهبندی (1 صفحه) | 1.5 روز | Tree View |
|
||||
| صفحات سفارشات (2 صفحه) | 3.5 روز | List + Details |
|
||||
| صفحه Support (سبد خرید) | 1 روز | |
|
||||
| **جمع** | **9 روز** | |
|
||||
|
||||
### **جمع کل**: **13 روز کاری** (~2.5 هفته)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 اولویتبندی پیادهسازی
|
||||
|
||||
### فاز 1: حداقل قابل استفاده (MVP) - 5 روز
|
||||
✅ **اولویت بالا**
|
||||
1. Handlerهای مدیریت محصولات (5)
|
||||
2. Handlerهای مدیریت دستهبندی (4)
|
||||
3. Handler مشاهده جزئیات سفارش (1)
|
||||
4. Handler تغییر وضعیت سفارش (1)
|
||||
5. صفحه لیست محصولات + فرم
|
||||
6. صفحه لیست سفارشات + جزئیات
|
||||
|
||||
### فاز 2: قابلیتهای Support - 3 روز
|
||||
🟡 **اولویت متوسط**
|
||||
1. Handlerهای سبد خرید (5)
|
||||
2. Handler لیست سفارشات کاربر (1)
|
||||
3. صفحه مدیریت دستهبندی
|
||||
4. صفحه Support سبد خرید
|
||||
|
||||
### فاز 3: گزارشات و آمار - 5 روز
|
||||
🟢 **اولویت پایین** (میتواند بعداً اضافه شود)
|
||||
1. گزارشات مالی
|
||||
2. داشبورد فروش فروشگاه
|
||||
3. چارتهای تحلیلی
|
||||
|
||||
---
|
||||
|
||||
## 📝 نکات مهم
|
||||
|
||||
### ⚠️ نکته 1: MaxDiscountPercent
|
||||
این فیلد بسیار مهم است:
|
||||
- مشخص میکند کاربر حداکثر چند درصد از قیمت محصول را میتواند با کیف پول تخفیف پرداخت کند
|
||||
- مثال: قیمت = 1,000,000 تومان، MaxDiscountPercent = 70%
|
||||
- حداکثر تخفیف: 700,000 تومان
|
||||
- مبلغ باقیمانده (300,000 تومان) باید از درگاه پرداخت شود
|
||||
|
||||
### ⚠️ نکته 2: Snapshot محصول
|
||||
وقتی سفارش ثبت میشود، اطلاعات محصول (عنوان، قیمت، MaxDiscountPercent) در جدول `DiscountOrderItem` ذخیره میشود:
|
||||
- این اطلاعات Snapshot هستند و حتی اگر محصول بعداً ویرایش شود، سفارش تغییر نمیکند
|
||||
- برای گزارشگیری دقیق مالی ضروری است
|
||||
|
||||
### ⚠️ نکته 3: Hybrid Payment Flow
|
||||
جریان پرداخت ترکیبی:
|
||||
1. کاربر سفارش ثبت میکند → `PlaceOrder`
|
||||
2. CMS محاسبه میکند چقدر از کیف پول تخفیف استفاده شود
|
||||
3. مبلغ باقیمانده (GatewayAmount) به کاربر نمایش داده میشود
|
||||
4. کاربر به درگاه پرداخت میرود
|
||||
5. بعد از بازگشت از درگاه → `CompleteOrderPayment`
|
||||
6. CMS تراکنش را Verify میکند و DiscountBalance را کم میکند
|
||||
|
||||
### ⚠️ نکته 4: Stock Management
|
||||
- هنگام `PlaceOrder`: RemainingCount کم میشود (Reserve)
|
||||
- اگر پرداخت ناموفق باشد: باید موجودی برگردانده شود (در CompleteOrderPayment)
|
||||
- Admin باید بتواند موجودی را دستی تغییر دهد
|
||||
|
||||
### ⚠️ نکته 5: VAT Calculation 🆕
|
||||
- مالیات ارزش افزوده (VAT) 10% برای هر سفارش محاسبه میشود
|
||||
- VAT روی قیمت نهایی (بعد از تخفیف) محاسبه میشود
|
||||
- فیلد `VatAmount` در هر سفارش ذخیره میشود
|
||||
- در گزارش فروش، مجموع VAT جداگانه نمایش داده میشود
|
||||
|
||||
---
|
||||
|
||||
## 📚 مستندات مرتبط
|
||||
|
||||
- [CMS Implementation Progress](../CMS/implementation-progress.md) - Phase 9 Details
|
||||
- [REMAINING-TASKS-CONSOLIDATED](../REMAINING-TASKS-CONSOLIDATED.md) - Overall Project Status
|
||||
- [BackOffice.BFF CMS Integration](./cms-integration.md) - Existing Integration Guide
|
||||
- [CHANGELOG-2025-12-31](../../CHANGELOG-2025-12-31.md) - تغییرات این سشن 🆕
|
||||
|
||||
---
|
||||
|
||||
## ✅ Checklist پیادهسازی
|
||||
|
||||
### Backend (BackOffice.BFF) - ✅ تکمیل شده
|
||||
- [x] آپدیت IApplicationContractContext (4 Client)
|
||||
- [x] آپدیت ApplicationContractContext (Implementation)
|
||||
- [x] ایجاد 5 Handler محصولات
|
||||
- [x] ایجاد 4 Handler دستهبندی
|
||||
- [x] ایجاد 5 Handler سبد خرید
|
||||
- [x] ایجاد 5 Handler سفارشات
|
||||
- [x] ایجاد 5 Handler گالری تصاویر 🆕
|
||||
- [x] ایجاد 2 Handler گزارش سفارشات 🆕
|
||||
- [x] ایجاد DiscountProductService (gRPC) 🆕
|
||||
- [x] ایجاد DiscountOrderService (gRPC) 🆕
|
||||
- [x] تست تمام Handlerها
|
||||
- [x] آپدیت مستندات cms-integration.md
|
||||
|
||||
### Frontend (BackOffice UI)
|
||||
- [ ] صفحه لیست محصولات
|
||||
- [ ] صفحه فرم محصول (Create/Edit)
|
||||
- [ ] صفحه مدیریت دستهبندیها
|
||||
- [ ] صفحه لیست سفارشات
|
||||
- [ ] صفحه جزئیات سفارش
|
||||
- [ ] صفحه Support سبد خرید
|
||||
- [ ] صفحه گالری تصاویر محصول 🆕
|
||||
- [ ] صفحه گزارش فروش 🆕
|
||||
- [ ] تست UI با داده واقعی
|
||||
|
||||
---
|
||||
|
||||
## 🎉 وضعیت نهایی
|
||||
|
||||
**Backend کاملاً آماده!** ✅
|
||||
|
||||
تمام APIهای لازم برای:
|
||||
- مدیریت محصولات (CRUD + گالری تصاویر)
|
||||
- مدیریت دستهبندیها
|
||||
- پشتیبانی سبد خرید
|
||||
- مدیریت سفارشات
|
||||
- گزارشگیری فروش
|
||||
|
||||
در لایههای BFF Application و WebApi پیادهسازی شدهاند. 🚀
|
||||
@@ -0,0 +1,32 @@
|
||||
# 📁 BackOffice.BFF - Design Files
|
||||
|
||||
این پوشه شامل فایلهای طراحی BackOffice.BFF است.
|
||||
|
||||
---
|
||||
|
||||
## 📊 فایلها
|
||||
|
||||
### Database Models:
|
||||
- **`model.ndm2`** - طراحی دیتابیس BackOffice.BFF
|
||||
- ابزار: Navicat Data Modeler
|
||||
- محتوا: ساختار Entity ها و روابط
|
||||
|
||||
---
|
||||
|
||||
## 🔧 نحوه استفاده
|
||||
|
||||
```bash
|
||||
# باز کردن با Navicat Data Modeler
|
||||
navicat-data-modeler model.ndm2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 مراجع
|
||||
|
||||
- **Handlers Status**: [`../handlers-status.md`](../handlers-status.md)
|
||||
- **CMS Integration**: [`../cms-integration.md`](../cms-integration.md)
|
||||
|
||||
---
|
||||
|
||||
**تاریخ ایجاد**: ۱ دسامبر ۲۰۲۵
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user