558 lines
18 KiB
Markdown
558 lines
18 KiB
Markdown
|
|
# Plan: فعالسازی مرحلهای Handler های کامنتشده
|
|||
|
|
|
|||
|
|
**تاریخ:** 8 دسامبر 2025
|
|||
|
|
**وضعیت:** در انتظار اجرا
|
|||
|
|
**تعداد کل فایلهای کامنتشده:** 37 فایل در 3 دسته
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## خلاصه اجرایی
|
|||
|
|
|
|||
|
|
در `BackOffice.BFF.Application.csproj` سه دسته handler کامنت شدهاند:
|
|||
|
|
|
|||
|
|
1. **DiscountOrderCQ/** (18 فایل) - عدم تطابق Proto با CMS
|
|||
|
|
2. **DiscountShoppingCartCQ/** (16 فایل) - عدم تطابق Proto
|
|||
|
|
3. **CommissionCQ/Commands/ProcessWithdrawal/** (3 فایل) - مشکل تبدیل StringValue
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## مرحله 1: ProcessWithdrawal (30 دقیقه - ساده ✅)
|
|||
|
|
|
|||
|
|
### ویژگی بیزینسی
|
|||
|
|
مدیریت درخواستهای برداشت کمیسیون توسط ادمین (تایید/رد)
|
|||
|
|
|
|||
|
|
### فایلهای دخیل
|
|||
|
|
```
|
|||
|
|
CommissionCQ/Commands/ProcessWithdrawal/
|
|||
|
|
├── ProcessWithdrawalCommand.cs
|
|||
|
|
├── ProcessWithdrawalCommandHandler.cs
|
|||
|
|
└── ProcessWithdrawalCommandValidator.cs
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### مشکل فعلی
|
|||
|
|
```csharp
|
|||
|
|
// Handler - خط 25
|
|||
|
|
var grpcRequest = new ProcessWithdrawalRequest
|
|||
|
|
{
|
|||
|
|
PayoutId = request.WithdrawalId,
|
|||
|
|
IsApproved = true, // ⚠️ هاردکد شده!
|
|||
|
|
Reason = request.AdminNote != null
|
|||
|
|
? new StringValue { Value = request.AdminNote }
|
|||
|
|
: null
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### تغییرات مورد نیاز
|
|||
|
|
|
|||
|
|
#### 1. آپدیت Command
|
|||
|
|
```csharp
|
|||
|
|
// ProcessWithdrawalCommand.cs
|
|||
|
|
public record ProcessWithdrawalCommand : IRequest<ProcessWithdrawalResponseDto>
|
|||
|
|
{
|
|||
|
|
public long WithdrawalId { get; init; }
|
|||
|
|
public bool IsApproved { get; init; } // ✅ جدید
|
|||
|
|
public string? Reason { get; init; } // نامگذاری مجدد از AdminNote
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2. آپدیت Handler
|
|||
|
|
```csharp
|
|||
|
|
// ProcessWithdrawalCommandHandler.cs
|
|||
|
|
var grpcRequest = new ProcessWithdrawalRequest
|
|||
|
|
{
|
|||
|
|
PayoutId = request.WithdrawalId,
|
|||
|
|
IsApproved = request.IsApproved, // ✅ از command گرفته شود
|
|||
|
|
Reason = !string.IsNullOrEmpty(request.Reason)
|
|||
|
|
? new StringValue { Value = request.Reason }
|
|||
|
|
: null
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
var response = await _context.Commissions.ProcessWithdrawalAsync(
|
|||
|
|
grpcRequest,
|
|||
|
|
cancellationToken);
|
|||
|
|
|
|||
|
|
return new ProcessWithdrawalResponseDto
|
|||
|
|
{
|
|||
|
|
Success = true,
|
|||
|
|
Message = "Withdrawal processed successfully"
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3. Uncomment WebApi Service
|
|||
|
|
```csharp
|
|||
|
|
// CommissionService.cs - خطوط 90-96
|
|||
|
|
public override async Task<Empty> ProcessWithdrawal(
|
|||
|
|
ProcessWithdrawalRequest request,
|
|||
|
|
ServerCallContext context)
|
|||
|
|
{
|
|||
|
|
await _dispatchRequestToCQRS.Handle<
|
|||
|
|
ProcessWithdrawalRequest,
|
|||
|
|
ProcessWithdrawalCommand,
|
|||
|
|
ProcessWithdrawalResponseDto>(request, context);
|
|||
|
|
return new Empty();
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4. حذف از Exclude List
|
|||
|
|
```xml
|
|||
|
|
<!-- BackOffice.BFF.Application.csproj -->
|
|||
|
|
<!-- حذف این خط: -->
|
|||
|
|
<Compile Remove="CommissionCQ/Commands/ProcessWithdrawal/**/*.cs" />
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### چکلیست
|
|||
|
|
- [ ] آپدیت ProcessWithdrawalCommand با فیلد IsApproved
|
|||
|
|
- [ ] آپدیت ProcessWithdrawalCommandHandler - حذف hardcode
|
|||
|
|
- [ ] Uncomment متد در CommissionService.cs
|
|||
|
|
- [ ] حذف از exclude در Application.csproj
|
|||
|
|
- [ ] Build و تست
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## مرحله 2: DiscountShoppingCartCQ (2-3 ساعت - متوسط 📊)
|
|||
|
|
|
|||
|
|
### ویژگی بیزینسی
|
|||
|
|
مدیریت سبد خرید فروشگاه تخفیف برای مشتریان
|
|||
|
|
|
|||
|
|
### فایلهای دخیل
|
|||
|
|
```
|
|||
|
|
DiscountShoppingCartCQ/
|
|||
|
|
├── Commands/ (12 فایل)
|
|||
|
|
│ ├── AddToCart/ ✅ تطابق دارد
|
|||
|
|
│ ├── RemoveFromCart/ ✅ تطابق دارد
|
|||
|
|
│ ├── UpdateCartItemCount/ ✅ تطابق دارد
|
|||
|
|
│ └── ClearCart/ ✅ تطابق دارد
|
|||
|
|
└── Queries/ (4 فایل)
|
|||
|
|
├── GetUserCart/ ⚠️ نیاز به Mapster
|
|||
|
|
└── سایر queries...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### مشکل فعلی: GetUserCartResponse
|
|||
|
|
|
|||
|
|
#### Handler انتظار دارد:
|
|||
|
|
```csharp
|
|||
|
|
public class GetUserCartResponseDto
|
|||
|
|
{
|
|||
|
|
public long UserId { get; set; } // ❌ در CMS proto نیست
|
|||
|
|
public decimal TotalPrice { get; set; }
|
|||
|
|
public decimal TotalDiscountedPrice { get; set; } // ❌ نام متفاوت
|
|||
|
|
public decimal TotalSavings { get; set; } // ❌ نام متفاوت
|
|||
|
|
public List<CartItemDto> Items { get; set; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class CartItemDto
|
|||
|
|
{
|
|||
|
|
public long Id { get; set; } // ❌ در CMS proto نیست
|
|||
|
|
public decimal DiscountedPrice { get; set; } // ❌ نام: final_price
|
|||
|
|
public DateTime AddedAt { get; set; } // ❌ نام: created (Timestamp)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### CMS Proto دارد:
|
|||
|
|
```protobuf
|
|||
|
|
message GetUserCartResponse {
|
|||
|
|
repeated CartItemDto items = 1;
|
|||
|
|
int64 total_price = 2;
|
|||
|
|
int64 total_discount_amount = 3; // ← TotalSavings
|
|||
|
|
int64 final_price = 4; // ← TotalDiscountedPrice
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
message CartItemDto {
|
|||
|
|
int64 product_id = 1;
|
|||
|
|
string product_title = 2;
|
|||
|
|
string product_image_path = 3;
|
|||
|
|
int64 unit_price = 4;
|
|||
|
|
int32 max_discount_percent = 5;
|
|||
|
|
int32 count = 6;
|
|||
|
|
int64 total_price = 7;
|
|||
|
|
int64 discount_amount = 8;
|
|||
|
|
int64 final_price = 9; // ← DiscountedPrice
|
|||
|
|
int32 product_remaining_count = 10;
|
|||
|
|
google.protobuf.Timestamp created = 11; // ← AddedAt
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### تغییرات مورد نیاز
|
|||
|
|
|
|||
|
|
#### 1. ساخت Mapster Profile
|
|||
|
|
```csharp
|
|||
|
|
// BackOffice.BFF.WebApi/Common/Mappings/DiscountShoppingCartProfile.cs
|
|||
|
|
using Mapster;
|
|||
|
|
using BackOffice.BFF.Application.DiscountShoppingCartCQ.Queries.GetUserCart;
|
|||
|
|
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
|||
|
|
|
|||
|
|
namespace BackOffice.BFF.WebApi.Common.Mappings;
|
|||
|
|
|
|||
|
|
public class DiscountShoppingCartProfile : IRegister
|
|||
|
|
{
|
|||
|
|
void IRegister.Register(TypeAdapterConfig config)
|
|||
|
|
{
|
|||
|
|
// Map GetUserCart Response
|
|||
|
|
config.NewConfig<GetUserCartResponse, GetUserCartResponseDto>()
|
|||
|
|
.MapWith(src => new GetUserCartResponseDto
|
|||
|
|
{
|
|||
|
|
// UserId باید از request گرفته شود (در handler)
|
|||
|
|
TotalPrice = src.TotalPrice,
|
|||
|
|
TotalDiscountedPrice = src.FinalPrice,
|
|||
|
|
TotalSavings = src.TotalDiscountAmount,
|
|||
|
|
Items = src.Items.Select(item => new CartItemDto
|
|||
|
|
{
|
|||
|
|
// Id ندارد - میتواند 0 باشد یا از product_id استفاده شود
|
|||
|
|
Id = item.ProductId,
|
|||
|
|
ProductId = item.ProductId,
|
|||
|
|
ProductTitle = item.ProductTitle,
|
|||
|
|
ProductImagePath = item.ProductImagePath,
|
|||
|
|
UnitPrice = item.UnitPrice,
|
|||
|
|
MaxDiscountPercent = item.MaxDiscountPercent,
|
|||
|
|
Count = item.Count,
|
|||
|
|
TotalPrice = item.TotalPrice,
|
|||
|
|
DiscountedPrice = item.FinalPrice,
|
|||
|
|
AddedAt = item.Created.ToDateTime()
|
|||
|
|
}).ToList()
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2. آپدیت Handler
|
|||
|
|
```csharp
|
|||
|
|
// GetUserCartQueryHandler.cs
|
|||
|
|
public async Task<GetUserCartResponseDto> Handle(
|
|||
|
|
GetUserCartQuery request,
|
|||
|
|
CancellationToken cancellationToken)
|
|||
|
|
{
|
|||
|
|
var grpcRequest = new GetUserCartRequest
|
|||
|
|
{
|
|||
|
|
UserId = request.UserId
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
var response = await _context.DiscountShoppingCarts.GetUserCartAsync(
|
|||
|
|
grpcRequest,
|
|||
|
|
cancellationToken: cancellationToken);
|
|||
|
|
|
|||
|
|
var result = TypeAdapter.Adapt(
|
|||
|
|
response,
|
|||
|
|
response.GetType(),
|
|||
|
|
typeof(GetUserCartResponseDto)) as GetUserCartResponseDto;
|
|||
|
|
|
|||
|
|
// UserId را از request میگیریم چون در proto نیست
|
|||
|
|
result.UserId = request.UserId;
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3. حذف از Exclude List
|
|||
|
|
```xml
|
|||
|
|
<!-- BackOffice.BFF.Application.csproj -->
|
|||
|
|
<!-- حذف این خط: -->
|
|||
|
|
<Compile Remove="DiscountShoppingCartCQ/**/*.cs" />
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### چکلیست
|
|||
|
|
- [ ] ساخت DiscountShoppingCartProfile.cs
|
|||
|
|
- [ ] آپدیت GetUserCartQueryHandler با Mapster
|
|||
|
|
- [ ] تست mapping با داده واقعی
|
|||
|
|
- [ ] حذف از exclude در Application.csproj
|
|||
|
|
- [ ] Build و تست endpoint
|
|||
|
|
|
|||
|
|
### سوال کلیدی ⚠️
|
|||
|
|
**آیا BackOffice.BFF نیاز به مدیریت سبد خرید دارد؟**
|
|||
|
|
- اگر خیر: Document کنیم "Not applicable - FrontOffice only"
|
|||
|
|
- اگر بله: Mapster profile بسازیم
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## مرحله 3: DiscountOrderCQ (6-8 ساعت - پیچیده 🔴)
|
|||
|
|
|
|||
|
|
### ویژگی بیزینسی
|
|||
|
|
مدیریت سفارشهای فروشگاه تخفیف توسط ادمین
|
|||
|
|
|
|||
|
|
### فایلهای دخیل
|
|||
|
|
```
|
|||
|
|
DiscountOrderCQ/
|
|||
|
|
├── Commands/ (10 فایل)
|
|||
|
|
│ ├── PlaceOrder/ ⚠️ Proto مختلف
|
|||
|
|
│ ├── CompletePayment/ ⚠️ Proto مختلف
|
|||
|
|
│ ├── UpdateOrderStatus/ ⚠️ Proto مختلف
|
|||
|
|
│ └── سایر commands...
|
|||
|
|
└── Queries/ (8 فایل)
|
|||
|
|
├── GetOrderById/ ⚠️ Proto مختلف
|
|||
|
|
├── GetAllUserOrders/ ⚠️ Proto مختلف
|
|||
|
|
└── سایر queries...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### مشکل اصلی: دو Proto متفاوت
|
|||
|
|
|
|||
|
|
#### تفاوتهای کلیدی
|
|||
|
|
|
|||
|
|
**1. PlaceOrderRequest**
|
|||
|
|
|
|||
|
|
Handler انتظار دارد:
|
|||
|
|
```csharp
|
|||
|
|
UserId, AddressId, DiscountBalanceAmount, GatewayAmount
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
CMS Proto دارد:
|
|||
|
|
```protobuf
|
|||
|
|
user_id, user_address_id, discount_balance_to_use, notes (StringValue)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**2. PlaceOrderResponse**
|
|||
|
|
|
|||
|
|
Handler انتظار دارد:
|
|||
|
|
```csharp
|
|||
|
|
OrderId, TrackingCode, RequiresGatewayPayment, GatewayPayableAmount
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
CMS Proto دارد:
|
|||
|
|
```protobuf
|
|||
|
|
success, message, order_id, gateway_amount, payment_url (StringValue)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**3. GetOrderByIdResponse - تفاوت اصلی**
|
|||
|
|
|
|||
|
|
Handler انتظار دارد:
|
|||
|
|
```csharp
|
|||
|
|
public class OrderDto
|
|||
|
|
{
|
|||
|
|
public long Id { get; set; }
|
|||
|
|
public int Status { get; set; } // ← int
|
|||
|
|
public string StatusTitle { get; set; } // ← محاسبه شده
|
|||
|
|
public bool IsPaid { get; set; } // ← bool
|
|||
|
|
public DateTime? PaidAt { get; set; }
|
|||
|
|
public string UserFullName { get; set; }
|
|||
|
|
public string UserMobile { get; set; }
|
|||
|
|
public string DeliveryAddress { get; set; } // ← string
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
CMS Proto دارد:
|
|||
|
|
```protobuf
|
|||
|
|
message OrderDto {
|
|||
|
|
int64 id = 1;
|
|||
|
|
DeliveryStatus delivery_status = 2; // ← enum
|
|||
|
|
bool payment_completed = 3; // ← bool
|
|||
|
|
google.protobuf.Timestamp created = 4;
|
|||
|
|
AddressDto address = 5; // ← object
|
|||
|
|
// StatusTitle ندارد - باید derive شود
|
|||
|
|
// PaidAt ندارد - باید از created استفاده شود
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
enum DeliveryStatus {
|
|||
|
|
DELIVERY_PENDING = 0;
|
|||
|
|
DELIVERY_PROCESSING = 1;
|
|||
|
|
DELIVERY_SHIPPED = 2;
|
|||
|
|
DELIVERY_DELIVERED = 3;
|
|||
|
|
DELIVERY_CANCELLED = 4;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### تصمیم کلیدی ⚠️
|
|||
|
|
|
|||
|
|
**گزینه A: استفاده از CMS Proto (پیشنهادی)**
|
|||
|
|
- ✅ CMS قبلاً پیادهسازی شده
|
|||
|
|
- ✅ ریسک کمتر
|
|||
|
|
- ❌ نیاز به rewrite کردن 18 handler
|
|||
|
|
- ❌ 6-8 ساعت کار
|
|||
|
|
|
|||
|
|
**گزینه B: استفاده از BFF Proto**
|
|||
|
|
- ✅ Handler ها آماده هستند
|
|||
|
|
- ❌ نیاز به آپدیت CMS microservice
|
|||
|
|
- ❌ ریسک بالا
|
|||
|
|
- ❌ تستهای بیشتر
|
|||
|
|
|
|||
|
|
### تغییرات مورد نیاز (گزینه A)
|
|||
|
|
|
|||
|
|
#### 1. ساخت Mapster Profile جامع
|
|||
|
|
```csharp
|
|||
|
|
// DiscountOrderProfile.cs
|
|||
|
|
public class DiscountOrderProfile : IRegister
|
|||
|
|
{
|
|||
|
|
void IRegister.Register(TypeAdapterConfig config)
|
|||
|
|
{
|
|||
|
|
// PlaceOrder Command → CMS Request
|
|||
|
|
config.NewConfig<PlaceOrderCommand, CMSPlaceOrderRequest>()
|
|||
|
|
.MapWith(src => new CMSPlaceOrderRequest
|
|||
|
|
{
|
|||
|
|
UserId = src.UserId,
|
|||
|
|
UserAddressId = src.AddressId,
|
|||
|
|
DiscountBalanceToUse = src.DiscountBalanceAmount,
|
|||
|
|
Notes = !string.IsNullOrEmpty(src.Notes)
|
|||
|
|
? new StringValue { Value = src.Notes }
|
|||
|
|
: null
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// CMS Response → DTO
|
|||
|
|
config.NewConfig<CMSPlaceOrderResponse, PlaceOrderResponseDto>()
|
|||
|
|
.MapWith(src => new PlaceOrderResponseDto
|
|||
|
|
{
|
|||
|
|
OrderId = src.OrderId,
|
|||
|
|
TrackingCode = src.OrderId.ToString(),
|
|||
|
|
RequiresGatewayPayment = src.GatewayAmount > 0,
|
|||
|
|
GatewayPayableAmount = src.GatewayAmount,
|
|||
|
|
PaymentUrl = src.PaymentUrl?.Value
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// GetOrderById - پیچیدهترین mapping
|
|||
|
|
config.NewConfig<CMSOrderDto, OrderDto>()
|
|||
|
|
.MapWith(src => new OrderDto
|
|||
|
|
{
|
|||
|
|
Id = src.Id,
|
|||
|
|
Status = (int)src.DeliveryStatus,
|
|||
|
|
StatusTitle = GetStatusTitle(src.DeliveryStatus),
|
|||
|
|
IsPaid = src.PaymentCompleted,
|
|||
|
|
PaidAt = src.PaymentCompleted
|
|||
|
|
? src.Created.ToDateTime()
|
|||
|
|
: null,
|
|||
|
|
UserFullName = src.UserFullName,
|
|||
|
|
UserMobile = src.UserMobile,
|
|||
|
|
DeliveryAddress = FormatAddress(src.Address),
|
|||
|
|
// ... بقیه فیلدها
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// GetAllUserOrders
|
|||
|
|
config.NewConfig<CMSGetAllUserOrdersResponse, GetAllUserOrdersResponseDto>()
|
|||
|
|
.MapWith(src => new GetAllUserOrdersResponseDto
|
|||
|
|
{
|
|||
|
|
MetaData = new MetaData
|
|||
|
|
{
|
|||
|
|
PageNumber = src.MetaData.CurrentPage,
|
|||
|
|
PageSize = src.MetaData.PageSize,
|
|||
|
|
TotalPages = src.MetaData.TotalPage,
|
|||
|
|
TotalCount = src.MetaData.TotalCount
|
|||
|
|
},
|
|||
|
|
Orders = src.Orders.Select(o => new OrderSummaryDto
|
|||
|
|
{
|
|||
|
|
Id = o.Id,
|
|||
|
|
Status = (int)o.DeliveryStatus,
|
|||
|
|
StatusTitle = GetStatusTitle(o.DeliveryStatus),
|
|||
|
|
// ...
|
|||
|
|
}).ToList()
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string GetStatusTitle(DeliveryStatus status) => status switch
|
|||
|
|
{
|
|||
|
|
DeliveryStatus.DeliveryPending => "در انتظار پردازش",
|
|||
|
|
DeliveryStatus.DeliveryProcessing => "در حال پردازش",
|
|||
|
|
DeliveryStatus.DeliveryShipped => "ارسال شده",
|
|||
|
|
DeliveryStatus.DeliveryDelivered => "تحویل داده شده",
|
|||
|
|
DeliveryStatus.DeliveryCancelled => "لغو شده",
|
|||
|
|
_ => "نامشخص"
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
private static string FormatAddress(AddressDto address)
|
|||
|
|
{
|
|||
|
|
if (address == null) return string.Empty;
|
|||
|
|
|
|||
|
|
return $"{address.Province}, {address.City}, {address.Street}, " +
|
|||
|
|
$"پلاک {address.PlateNumber}, واحد {address.Unit}";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2. بازنویسی Handlers (نمونه)
|
|||
|
|
```csharp
|
|||
|
|
// PlaceOrderCommandHandler.cs
|
|||
|
|
public async Task<PlaceOrderResponseDto> Handle(
|
|||
|
|
PlaceOrderCommand request,
|
|||
|
|
CancellationToken cancellationToken)
|
|||
|
|
{
|
|||
|
|
var grpcRequest = TypeAdapter.Adapt(
|
|||
|
|
request,
|
|||
|
|
request.GetType(),
|
|||
|
|
typeof(CMSPlaceOrderRequest)) as CMSPlaceOrderRequest;
|
|||
|
|
|
|||
|
|
var response = await _context.DiscountOrders.PlaceOrderAsync(
|
|||
|
|
grpcRequest,
|
|||
|
|
cancellationToken: cancellationToken);
|
|||
|
|
|
|||
|
|
return TypeAdapter.Adapt(
|
|||
|
|
response,
|
|||
|
|
response.GetType(),
|
|||
|
|
typeof(PlaceOrderResponseDto)) as PlaceOrderResponseDto;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3. حذف از Exclude List
|
|||
|
|
```xml
|
|||
|
|
<!-- BackOffice.BFF.Application.csproj -->
|
|||
|
|
<!-- حذف این خط: -->
|
|||
|
|
<Compile Remove="DiscountOrderCQ/**/*.cs" />
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### چکلیست
|
|||
|
|
- [ ] تصمیمگیری: CMS proto یا BFF proto؟
|
|||
|
|
- [ ] مقایسه دقیق line-by-line دو proto
|
|||
|
|
- [ ] ساخت DiscountOrderProfile.cs جامع
|
|||
|
|
- [ ] بازنویسی PlaceOrderCommandHandler
|
|||
|
|
- [ ] بازنویسی CompletePaymentCommandHandler
|
|||
|
|
- [ ] بازنویسی UpdateOrderStatusCommandHandler
|
|||
|
|
- [ ] بازنویسی GetOrderByIdQueryHandler
|
|||
|
|
- [ ] بازنویسی GetAllUserOrdersQueryHandler
|
|||
|
|
- [ ] تست کامل flow: Place → Pay → Update → Get
|
|||
|
|
- [ ] حذف از exclude در Application.csproj
|
|||
|
|
- [ ] Build و تست همه endpoints
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## جدول خلاصه
|
|||
|
|
|
|||
|
|
| Handler Group | تعداد فایل | Proto Source | BFF Proto | Mapster Profile | پیچیدگی | زمان تخمینی | اولویت بیزینسی |
|
|||
|
|
|---------------|-----------|--------------|-----------|-----------------|---------|-------------|----------------|
|
|||
|
|
| ProcessWithdrawal | 3 | BFF.Commission | ✅ | ❌ نیاز نیست | ساده | 30 دقیقه | متوسط ⚠️ |
|
|||
|
|
| DiscountShoppingCart | 16 | CMS | ✅ (متفاوت) | ❌ باید ساخت | متوسط | 2-3 ساعت | متوسط ⚠️ |
|
|||
|
|
| DiscountOrder | 18 | CMS | ✅ (کاملاً متفاوت) | ❌ باید ساخت | پیچیده | 6-8 ساعت | بالا 🔴 |
|
|||
|
|
| **جمع کل** | **37** | - | - | - | - | **8.5-11.5 ساعت** | - |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## سوالات کلیدی برای تصمیمگیری
|
|||
|
|
|
|||
|
|
### 1. DiscountShoppingCartCQ
|
|||
|
|
**سوال:** آیا BackOffice نیاز به مدیریت سبد خرید دارد؟
|
|||
|
|
- اگر **خیر**: این feature فقط برای FrontOffice است → Document و نگهداری exclude
|
|||
|
|
- اگر **بله**: ادمین باید بتواند سبد خرید کاربران را ببیند → Mapster profile بسازیم
|
|||
|
|
|
|||
|
|
### 2. DiscountOrderCQ
|
|||
|
|
**سوال:** کدام proto را استفاده کنیم؟
|
|||
|
|
- **گزینه A (پیشنهادی)**: CMS proto
|
|||
|
|
- Handler ها را rewrite میکنیم
|
|||
|
|
- 6-8 ساعت کار
|
|||
|
|
- ریسک کم
|
|||
|
|
- **گزینه B**: BFF proto
|
|||
|
|
- CMS microservice را آپدیت میکنیم
|
|||
|
|
- زمان نامشخص
|
|||
|
|
- ریسک بالا
|
|||
|
|
|
|||
|
|
### 3. اولویت اجرا
|
|||
|
|
کدام مرحله اول اجرا شود؟
|
|||
|
|
- **پیشنهاد:** ProcessWithdrawal (سریعترین ROI)
|
|||
|
|
- سپس: بر اساس نیاز بیزینسی
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## مراحل بعدی
|
|||
|
|
|
|||
|
|
### فوری
|
|||
|
|
1. ✅ تصمیم: DiscountShoppingCart نیاز هست؟
|
|||
|
|
2. ✅ تصمیم: DiscountOrder از کدام proto؟
|
|||
|
|
3. ✅ شروع با ProcessWithdrawal (30 دقیقه)
|
|||
|
|
|
|||
|
|
### کوتاهمدت
|
|||
|
|
4. اگر نیاز: DiscountShoppingCart (2-3 ساعت)
|
|||
|
|
5. Planning دقیق DiscountOrder (1 ساعت)
|
|||
|
|
|
|||
|
|
### میانمدت
|
|||
|
|
6. پیادهسازی DiscountOrder (6-8 ساعت)
|
|||
|
|
7. تست integration کامل
|
|||
|
|
8. Document کردن تغییرات
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**تاریخ آخرین آپدیت:** 8 دسامبر 2025
|
|||
|
|
**وضعیت:** منتظر تصمیمگیری و شروع اجرا
|
|||
|
|
**مسئول:** تیم توسعه BackOffice.BFF
|