update
This commit is contained in:
@@ -0,0 +1,311 @@
|
||||
# Session Log - December 20, 2025
|
||||
|
||||
## خلاصه Session
|
||||
|
||||
این session شامل رفع چندین باگ در صفحات BackOffice و فعالسازی قابلیتهای Products بود.
|
||||
|
||||
---
|
||||
|
||||
## 1. فیکس صفحه `/network/balances`
|
||||
|
||||
### مشکل
|
||||
```
|
||||
ValidationException هنگام لود صفحه بالانسهای هفتگی
|
||||
```
|
||||
|
||||
### علت
|
||||
Mapster mapping برای تبدیل `GetUserWeeklyBalancesRequest` به `GetUserWeeklyBalancesQuery` وجود نداشت.
|
||||
|
||||
### راهحل
|
||||
اضافه کردن mapping در `CommissionProfile.cs`:
|
||||
|
||||
```csharp
|
||||
// File: BackOffice.BFF/src/BackOffice.BFF.WebApi/Common/Mappings/CommissionProfile.cs
|
||||
|
||||
config.NewConfig<GetUserWeeklyBalancesRequest, GetUserWeeklyBalancesQuery>()
|
||||
.Map(dest => dest.PaginationState, src => src.PaginationState);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. فیکس صفحه `/club/members`
|
||||
|
||||
### مشکل
|
||||
```
|
||||
صفحه لود میشد ولی هیچ دادهای نمایش نمیداد
|
||||
```
|
||||
|
||||
### علت
|
||||
Mapster mappings در CMS و BFF برای `GetAllClubMemberships` وجود نداشتند.
|
||||
|
||||
### راهحل
|
||||
ایجاد `ClubMembershipProfile.cs` در هر دو لایه:
|
||||
|
||||
**CMS/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs** (NEW):
|
||||
```csharp
|
||||
public class ClubMembershipProfile : IRegister
|
||||
{
|
||||
void IRegister.Register(TypeAdapterConfig config)
|
||||
{
|
||||
// GetAllClubMemberships mappings
|
||||
config.NewConfig<GetAllClubMembershipsRequest, GetAllClubMembershipsQuery>()
|
||||
.Map(dest => dest.PaginationState, src => src.PaginationState)
|
||||
.Map(dest => dest.Filter, src => src.Filter);
|
||||
|
||||
config.NewConfig<GetAllClubMembershipsResponseDto, GetAllClubMembershipsResponse>()
|
||||
.MapWith(src => new GetAllClubMembershipsResponse
|
||||
{
|
||||
MetaData = src.MetaData != null ? new CMSMicroservice.Protobuf.Common.MetaData
|
||||
{
|
||||
PageIndex = src.MetaData.PageIndex,
|
||||
TotalPages = src.MetaData.TotalPages,
|
||||
TotalCount = src.MetaData.TotalCount
|
||||
} : null,
|
||||
Models = { src.Models?.Select(...) ?? Enumerable.Empty<...>() }
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**BackOffice.BFF/src/BackOffice.BFF.WebApi/Common/Mappings/ClubMembershipProfile.cs** (REWRITTEN):
|
||||
- Mapping از BFF Proto به Query
|
||||
- Mapping از CMS Response به BFF Proto Response
|
||||
- استفاده از alias imports برای disambiguation
|
||||
|
||||
---
|
||||
|
||||
## 3. فیکس صفحه `/club/statistics`
|
||||
|
||||
### مشکل
|
||||
```
|
||||
Status(StatusCode="Unimplemented", Detail="Method cms.ClubMembershipContract/GetClubStatistics is unimplemented")
|
||||
```
|
||||
|
||||
### علت
|
||||
متد `GetClubStatistics` در BFF Service override نشده بود.
|
||||
|
||||
### راهحل
|
||||
|
||||
**1. اضافه کردن override در ClubMembershipService.cs:**
|
||||
```csharp
|
||||
public override async Task<GetClubStatisticsResponse> GetClubStatistics(
|
||||
GetClubStatisticsRequest request, ServerCallContext context)
|
||||
{
|
||||
return await _dispatchRequestToCQRS.Handle<GetClubStatisticsRequest, GetClubStatisticsQuery, GetClubStatisticsResponse>(request, context);
|
||||
}
|
||||
```
|
||||
|
||||
**2. اضافه کردن mappings در CMS ClubMembershipProfile:**
|
||||
```csharp
|
||||
config.NewConfig<GetClubStatisticsRequest, GetClubStatisticsQuery>();
|
||||
|
||||
config.NewConfig<GetClubStatisticsResponseDto, GetClubStatisticsResponse>()
|
||||
.MapWith(src => new GetClubStatisticsResponse
|
||||
{
|
||||
TotalMembers = src.TotalMembers,
|
||||
ActiveMembers = src.ActiveMembers,
|
||||
// ... سایر فیلدها
|
||||
PackageDistribution = { src.PackageDistribution?.Select(...) },
|
||||
MonthlyTrend = { src.MonthlyTrend?.Select(...) }
|
||||
});
|
||||
```
|
||||
|
||||
**3. اضافه کردن mappings در BFF ClubMembershipProfile:**
|
||||
- Mapping از BFF Proto به Query
|
||||
- Mapping از CMS Response DTO به BFF Proto Response
|
||||
|
||||
---
|
||||
|
||||
## 4. فعالسازی قابلیتهای Products
|
||||
|
||||
### مشکل
|
||||
```
|
||||
همه دکمههای صفحه محصولات "در حال توسعه" نشان میدادند
|
||||
```
|
||||
|
||||
### علت
|
||||
کدهای دیالوگها comment شده بودند با TODO markers.
|
||||
|
||||
### راهحل
|
||||
Uncomment کردن کدها در `ProductsMainPage.razor.cs`:
|
||||
|
||||
**فایل: BackOffice/src/BackOffice/Pages/Products/ProductsMainPage.razor.cs**
|
||||
|
||||
```csharp
|
||||
// ✅ CreateNew() - فعال شد
|
||||
public async Task CreateNew()
|
||||
{
|
||||
var dialog = await DialogService.ShowAsync<CreateDialog>("افزودن محصول",
|
||||
new DialogParameters<CreateDialog> { { x => x.Model, new CreateNewProductsRequest() } },
|
||||
new DialogOptions { CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.Small });
|
||||
// ...
|
||||
}
|
||||
|
||||
// ✅ Update() - فعال شد
|
||||
public async Task Update(DataModel model)
|
||||
{
|
||||
var parameters = new DialogParameters<UpdateDialog> { { x => x.Model, model.Adapt<UpdateProductsRequest>() } };
|
||||
var dialog = await DialogService.ShowAsync<UpdateDialog>("ویرایش محصول", parameters, ...);
|
||||
// ...
|
||||
}
|
||||
|
||||
// ✅ OpenGallery() - فعال شد
|
||||
public async Task OpenGallery(DataModel model)
|
||||
{
|
||||
var parameters = new DialogParameters<GalleryDialog>
|
||||
{
|
||||
{ x => x.ProductId, model.Id },
|
||||
{ x => x.ProductTitle, model.Title }
|
||||
};
|
||||
await DialogService.ShowAsync<GalleryDialog>("گالری تصاویر", parameters, ...);
|
||||
}
|
||||
|
||||
// ✅ OpenTagAssignment() - فعال شد
|
||||
public async Task OpenTagAssignment(DataModel model)
|
||||
{
|
||||
var parameters = new DialogParameters<AssignTagsDialog>
|
||||
{
|
||||
{ x => x.ProductId, model.Id },
|
||||
{ x => x.ProductTitle, model.Title }
|
||||
};
|
||||
await DialogService.ShowAsync<AssignTagsDialog>("مدیریت تگهای محصول", parameters, ...);
|
||||
}
|
||||
```
|
||||
|
||||
**Using statement uncomment شد:**
|
||||
```csharp
|
||||
using BackOffice.Pages.Tag.Components; // برای AssignTagsDialog
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. اضافه کردن فیلد "تعداد موجودی" به Products
|
||||
|
||||
### نیاز
|
||||
نمایش و ویرایش تعداد موجودی محصول در فرمها و لیست
|
||||
|
||||
### تغییرات
|
||||
|
||||
**1. فرمهای دیالوگ (CreateDialog.razor & UpdateDialog.razor):**
|
||||
```razor
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
<MudItem xs="6">
|
||||
<MudNumericField T="int" HideSpinButtons="true" @bind-Value="Model.Discount"
|
||||
Disabled="_isLoading" Label="تخفیف (%)" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudNumericField T="int" HideSpinButtons="true" @bind-Value="Model.RemainingCount"
|
||||
Disabled="_isLoading" Label="تعداد موجودی" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
</MudStack>
|
||||
```
|
||||
|
||||
**2. ستون جدید در لیست (ProductsMainPage.razor):**
|
||||
```razor
|
||||
<TemplateColumn Title="موجودی" CellStyle="text-wrap: nowrap;">
|
||||
<CellTemplate>
|
||||
@if (context.Item.RemainingCount <= 0)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Error" Size="Size.Small">ناموجود</MudChip>
|
||||
}
|
||||
else if (context.Item.RemainingCount < 10)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Warning" Size="Size.Small">@context.Item.RemainingCount</MudChip>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudChip T="string" Color="Color.Success" Size="Size.Small">@context.Item.RemainingCount</MudChip>
|
||||
}
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
```
|
||||
|
||||
**3. اضافه کردن فیلد به BFF Commands (فیکس مهم!):**
|
||||
|
||||
مشکل: فیلد `RemainingCount` در BFF Application Commands نبود و باعث میشد مقدار ارسال/دریافت نشه.
|
||||
|
||||
**CreateNewProductsCommand.cs:**
|
||||
```csharp
|
||||
public int Discount { get; init; }
|
||||
public int Rate { get; init; }
|
||||
public int RemainingCount { get; init; } // ← اضافه شد
|
||||
public ImageFileModel ImageFile { get; init; }
|
||||
```
|
||||
|
||||
**UpdateProductsCommand.cs:**
|
||||
```csharp
|
||||
public int Discount { get; init; }
|
||||
public int Rate { get; init; }
|
||||
public int RemainingCount { get; init; } // ← اضافه شد
|
||||
public string ImagePath { get; init; }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## لیست کامل فایلهای تغییر یافته
|
||||
|
||||
### BackOffice.BFF
|
||||
| فایل | نوع تغییر | توضیح |
|
||||
|------|----------|-------|
|
||||
| `WebApi/Common/Mappings/CommissionProfile.cs` | MODIFIED | اضافه شدن mapping برای GetUserWeeklyBalances |
|
||||
| `WebApi/Common/Mappings/ClubMembershipProfile.cs` | REWRITTEN | Mappings کامل برای ClubMembership |
|
||||
| `WebApi/Services/ClubMembershipService.cs` | MODIFIED | اضافه شدن GetClubStatistics override |
|
||||
| `Application/ProductsCQ/Commands/CreateNewProducts/CreateNewProductsCommand.cs` | MODIFIED | اضافه شدن RemainingCount |
|
||||
| `Application/ProductsCQ/Commands/UpdateProducts/UpdateProductsCommand.cs` | MODIFIED | اضافه شدن RemainingCount |
|
||||
|
||||
### CMS
|
||||
| فایل | نوع تغییر | توضیح |
|
||||
|------|----------|-------|
|
||||
| `WebApi/Common/Mappings/ClubMembershipProfile.cs` | NEW | Mappings برای ClubMembership |
|
||||
|
||||
### BackOffice UI
|
||||
| فایل | نوع تغییر | توضیح |
|
||||
|------|----------|-------|
|
||||
| `Pages/Products/ProductsMainPage.razor.cs` | MODIFIED | فعالسازی CreateNew, Update, OpenGallery, OpenTagAssignment |
|
||||
| `Pages/Products/ProductsMainPage.razor` | MODIFIED | اضافه شدن ستون موجودی |
|
||||
| `Pages/Products/Components/CreateDialog.razor` | MODIFIED | اضافه شدن فیلد موجودی |
|
||||
| `Pages/Products/Components/UpdateDialog.razor` | MODIFIED | اضافه شدن فیلد موجودی |
|
||||
|
||||
---
|
||||
|
||||
## نکات فنی مهم
|
||||
|
||||
### 1. Mapster با Proto Types
|
||||
برای proto types که immutable هستند، باید از `MapWith` استفاده کرد:
|
||||
|
||||
```csharp
|
||||
config.NewConfig<SourceDto, ProtoResponse>()
|
||||
.MapWith(src => new ProtoResponse
|
||||
{
|
||||
Field1 = src.Field1,
|
||||
RepeatedField = { src.List?.Select(...) ?? Enumerable.Empty<...>() }
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Alias Imports برای Proto Disambiguation
|
||||
وقتی دو proto با اسم یکسان داریم:
|
||||
|
||||
```csharp
|
||||
using BffProtos = BackOffice.BFF.ClubMembership.Protobuf.Protos.ClubMembership;
|
||||
using CmsProtos = CMSMicroservice.Protobuf.Protos.ClubMembership;
|
||||
```
|
||||
|
||||
### 3. Null-Safe MetaData Mapping
|
||||
```csharp
|
||||
MetaData = src.MetaData != null ? new MetaData
|
||||
{
|
||||
PageIndex = src.MetaData.PageIndex,
|
||||
TotalPages = src.MetaData.TotalPages,
|
||||
TotalCount = src.MetaData.TotalCount
|
||||
} : null
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build Status پایان Session
|
||||
|
||||
```
|
||||
BackOffice.BFF: ✅ Build succeeded (0 errors)
|
||||
CMS: ✅ Build succeeded (0 errors)
|
||||
BackOffice UI: ✅ Build succeeded (0 errors)
|
||||
```
|
||||
Reference in New Issue
Block a user