21 KiB
📝 Changelog - ۷ دی ۱۴۰۴ (27 December 2025)
Session: بهینهسازیهای Mapping + SystemConstants + SMS Templates + AppVersion UI + Commission System Fixes
🎯 خلاصه Session
این session شامل موارد زیر بود:
- SystemConstants - انتقال مقادیر ثابت از hardcode به کلاس مرکزی
- SMS Templates - متمرکز کردن همه قالبهای پیامک
- SMS for Daya Loan - ارسال پیامک هنگام تأیید وام دایا
- AppVersion UI - تکمیل صفحه مدیریت نسخه در BackOffice
- Mapping Fixes - رفع مشکلات Mapster
- Commission Status Refactoring - انتقال تبدیل Status از BFF به FrontOffice
- ProcessWithdrawal Fix - رفع خطای "PayoutId invalid" در BackOffice
- WeekDisplayName Fix - نمایش صحیح نام هفته به جای فرمت 1404-W40
- Withdrawals Page Fix - رفع مشکل لود نشدن صفحه تأیید برداشتها
- Network Balances Enhancement - افزودن نام کاربر و جزئیات Carryover به صفحه balanceها
- WeekDefinitionId Mapping Fix - رفع مشکل ارسال WeekDefinitionId=0 در FrontOffice.BFF
✨ تغییرات
1. 💰 SystemConstants - مقادیر ثابت ✅
فایل: CMSMicroservice.Domain/Common/SystemConstants.cs
public static class SystemConstants
{
// Club Configuration
public const decimal ClubJoiningPercentage = 0.35m; // 35% کمیسیون پیوستن به باشگاه
public const decimal ClubActivationThreshold = 0.5m; // 50% آستانه فعالسازی
// Commission Configuration
public const int MaxCalculationAttempts = 3; // حداکثر تلاش محاسبه
public const int DefaultCommissionPoolDays = 7; // روزهای استخر کمیسیون
// Package Amounts
public const long GoldenPackageAmount = 56_000_000; // 56 میلیون - پکیج طلایی
public const long DayaLoanAmount = 56_000_000; // 56 میلیون - وام دایا
}
Handlers آپدیت شده:
| Handler | تغییر |
|---|---|
ProcessDayaLoanApprovalCommandHandler |
استفاده از SystemConstants.DayaLoanAmount |
ValidateGoldenPackagePurchaseQueryHandler |
استفاده از SystemConstants.GoldenPackageAmount |
| سایر handlers با 56_000_000 | همه به ثابت تبدیل شدند |
2. 📱 SmsTemplates - قالبهای متمرکز پیامک ✅
فایل جدید: CMSMicroservice.Domain/Common/SmsTemplates.cs
public static class SmsTemplates
{
private static string GetUserName(string? firstName)
=> string.IsNullOrWhiteSpace(firstName) ? "کاربر" : firstName;
public static string DayaLoanReceived(string? firstName, long amount)
=> $"{GetUserName(firstName)} عزیز، مبلغ {amount:N0} ریال وام دایا به کیف پول شما واریز شد. کارابازار";
public static string ClubActivated(string? firstName)
=> $"{GetUserName(firstName)} عزیز، حساب باشگاه شما فعال شد. کارابازار";
public static string PackagePurchased(string? firstName, string packageName)
=> $"{GetUserName(firstName)} عزیز، پکیج {packageName} با موفقیت خریداری شد. کارابازار";
public static string CommissionDeposited(string? firstName, long amount)
=> $"{GetUserName(firstName)} عزیز، مبلغ {amount:N0} ریال کمیسیون به کیف پول شما واریز شد. کارابازار";
public static string WithdrawalSuccess(string? firstName, long amount)
=> $"{GetUserName(firstName)} عزیز، درخواست برداشت {amount:N0} ریال با موفقیت انجام شد. کارابازار";
public static string NetworkJoined(string? firstName, string referrerName)
=> $"{GetUserName(firstName)} عزیز، به شبکه {referrerName} پیوستید. کارابازار";
public static string NewDownline(string? firstName, string newMemberName)
=> $"{GetUserName(firstName)} عزیز، {newMemberName} به زیرمجموعه شما اضافه شد. کارابازار";
public static string OtpCode(string code)
=> $"کد تأیید شما: {code}\nکارابازار";
public static string Welcome(string? firstName)
=> $"{GetUserName(firstName)} عزیز، به کارابازار خوش آمدید!";
}
3. 📲 ارسال SMS هنگام تأیید وام دایا ✅
فایل: CMSMicroservice.Application/FinancialCQ/Commands/ProcessDayaLoanApproval/ProcessDayaLoanApprovalCommandHandler.cs
تغییرات:
public class ProcessDayaLoanApprovalCommandHandler : IRequestHandler<ProcessDayaLoanApprovalCommand, Unit>
{
private readonly IKavenegarService _smsService; // جدید
private readonly ILogger<ProcessDayaLoanApprovalCommandHandler> _logger; // جدید
// بعد از واریز موفق به کیف پول
private async Task SendDayaLoanSmsAsync(User user)
{
try
{
var message = SmsTemplates.DayaLoanReceived(
user.FirstName,
SystemConstants.DayaLoanAmount);
await _smsService.SendAsync(user.PhoneNumber, message);
_logger.LogInformation("Daya loan SMS sent to user {UserId}", user.Id);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to send Daya loan SMS to user {UserId}", user.Id);
// خطای SMS مانع عملیات اصلی نمیشود
}
}
}
4. 🖥️ BackOffice - صفحه مدیریت نسخه اپلیکیشن ✅
4.1 اضافه شدن به منو
فایل: BackOffice/Shared/NavMenu.razor
@if (CanViewSettings)
{
<MudNavLink Match="NavLinkMatch.Prefix"
Href="/settings/app-versions"
Icon="@Icons.Material.Filled.PhoneAndroid">
نسخه اپلیکیشنها
</MudNavLink>
}
Permission: settings.view
4.2 دکمه افزودن نسخه جدید
فایل: BackOffice/Pages/Settings/AppVersions.razor
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Add"
OnClick="@OpenCreateDialog">
افزودن نسخه جدید
</MudButton>
4.3 Dialog با حالت جدید/ویرایش
فایل: BackOffice/Pages/Settings/Components/AppVersionEditDialog.razor
[Parameter]
public bool IsNew { get; set; } = false;
@if (IsNew)
{
<MudSelect @bind-Value="Model.AppName"
Label="نام اپلیکیشن"
Required="true">
<MudSelectItem Value="@("KaraBazarApp")">کارابازار</MudSelectItem>
<MudSelectItem Value="@("KaraBazarAdminApp")">ادمین کارابازار</MudSelectItem>
</MudSelect>
}
else
{
<MudTextField @bind-Value="Model.AppName"
ReadOnly="true" Disabled="true" />
}
4.4 آیکون و رنگ اپلیکیشنها
private string GetAppIcon(string appName) => appName switch
{
"KaraBazarApp" => Icons.Material.Filled.ShoppingCart,
"KaraBazarAdminApp" => Icons.Material.Filled.AdminPanelSettings,
_ => Icons.Material.Filled.PhoneAndroid
};
private Color GetAppColor(string appName) => appName switch
{
"KaraBazarApp" => Color.Primary,
"KaraBazarAdminApp" => Color.Secondary,
_ => Color.Default
};
5. 🔧 Mapping Fixes ✅
5.1 CMS - AppVersionProfile
فایل جدید: CMSMicroservice.WebApi/Common/Mappings/AppVersionProfile.cs
public class AppVersionProfile : IRegister
{
public void Register(TypeAdapterConfig config)
{
// Map List<AppVersionItemDto> to GetAllAppVersionsResponse
config.NewConfig<List<AppVersionItemDto>, GetAllAppVersionsResponse>()
.MapWith(src => CreateResponse(src));
// Map AppVersionItemDto to AppVersionItem (proto message)
config.NewConfig<AppVersionItemDto, AppVersionItem>()
.Map(dest => dest.Id, src => src.Id)
.Map(dest => dest.AppName, src => src.AppName)
// ... other mappings
}
private static GetAllAppVersionsResponse CreateResponse(List<AppVersionItemDto> items)
{
var response = new GetAllAppVersionsResponse();
foreach (var item in items)
{
response.Items.Add(item.Adapt<AppVersionItem>());
}
return response;
}
}
5.2 BackOffice.BFF - CommissionProfile
فایل: BackOffice.BFF.Application/Common/Mappings/CommissionProfile.cs
// CMS GetAllWeeklyPoolsResponse -> GetAllWeeklyPoolsResponseDto
config.NewConfig<GetAllWeeklyPoolsResponse, GetAllWeeklyPoolsResponseDto>()
.MapWith(src => new GetAllWeeklyPoolsResponseDto
{
MetaData = new MetaDataDto
{
TotalCount = (int)src.MetaData.TotalCount,
PageSize = (int)src.MetaData.PageSize,
CurrentPage = (int)src.MetaData.CurrentPage,
TotalPages = (int)src.MetaData.TotalPage
},
Models = src.Models.Select(m => new WeeklyCommissionPoolDto
{
Id = m.Id,
WeekDefinitionId = m.WeekDefinitionId,
// ... other mappings
}).ToList()
});
5.3 BackOffice.BFF - GeneralMapping (Unit to Empty)
فایل: BackOffice.BFF.WebApi/Common/Mappings/GeneralMapping.cs
// MediatR Unit to Google.Protobuf.Empty
config.NewConfig<MediatR.Unit, Google.Protobuf.WellKnownTypes.Empty>()
.MapWith(_ => new Google.Protobuf.WellKnownTypes.Empty());
6. 🔄 Commission Status Refactoring ✅
مشکل: تبدیل enum عددی CommissionPayoutStatus به متن فارسی در BFF gateway انجام میشد.
راهحل: انتقال منطق به FrontOffice client برای معماری بهتر.
6.1 FrontOffice.BFF - Simplify Response
فایل: FrontOffice.BFF.Application/.../GetMyWeeklyBalancesQueryHandler.cs
قبل:
Status = MapStatusToString(x.Status)
بعد:
Status = x.Status // Return int directly
6.2 FrontOffice - CommissionService
فایل: FrontOffice.Main/Utilities/CommissionService.cs
public static string MapStatus(int status) => status switch
{
0 => "در انتظار", // Pending
1 => "پرداخت شده", // Paid
2 => "درخواست برداشت", // WithdrawRequested
3 => "برداشت شده", // Withdrawn
4 => "خطای پرداخت", // PaymentFailed
5 => "لغو شده", // Cancelled
_ => "نامشخص"
};
public static string GetStatusColor(int status) => status switch
{
0 => "warning", // Pending - زرد
1 => "success", // Paid - سبز
2 => "info", // WithdrawRequested - آبی
3 => "success", // Withdrawn - سبز
4 => "error", // PaymentFailed - قرمز
5 => "default", // Cancelled - خاکستری
_ => "default"
};
Enum مرجع (CommissionPayoutStatus):
public enum CommissionPayoutStatus
{
Pending = 0,
Paid = 1,
WithdrawRequested = 2,
Withdrawn = 3,
PaymentFailed = 4,
Cancelled = 5
}
7. 🛠️ ProcessWithdrawal Fix ✅
مشکل: خطای "PayoutId invalid" هنگام تأیید/رد برداشت در BackOffice
علت: PayoutId در mapping از CMS request به BackOffice.BFF command map نمیشد.
فایل: BackOffice.BFF.Application/Common/Mappings/CommissionProfile.cs
قبل:
config.NewConfig<ProcessWithdrawalRequest, ProcessWithdrawalCommand>();
// PayoutId ignored!
بعد:
config.NewConfig<ProcessWithdrawalRequest, ProcessWithdrawalCommand>()
.Map(dest => dest.PayoutId, src => src.PayoutId)
.Map(dest => dest.Approve, src => src.Approve)
.Map(dest => dest.RejectionReason, src => src.RejectionReason);
8. 📅 WeekDisplayName Fix ✅
مشکل: نمایش "1404-W40" به جای "هفته چهلم" در dropdown انتخاب هفته
علت: استفاده از PersianWeekNumber به جای DisplayName
فایل: CMS.Application/.../GetAllWeeklyPoolsQueryHandler.cs
قبل:
WeekDisplayName = x.WeekDefinition.PersianWeekNumber // "1404-W40"
بعد:
WeekDisplayName = x.WeekDefinition.DisplayName // "هفته چهلم"
9. 📋 Withdrawals Page Fix ✅
مشکل: صفحه تأیید برداشتها در BackOffice لود نمیشد
علت: mismatch بین نام propertyها در CMS proto و BackOffice.BFF DTO
فایل: BackOffice.BFF.Application/.../GetWithdrawalRequestsResponseDto.cs
قبل:
public int TotalPages { get; set; }
public int TotalCount { get; set; }
بعد:
public int TotalPage { get; set; } // Match CMS proto
public int TotalCount { get; set; }
فایل: BackOffice.BFF.Application/.../GetWithdrawalRequestsQueryHandler.cs
قبل:
return response.Adapt<GetWithdrawalRequestsResponseDto>();
بعد:
return new GetWithdrawalRequestsResponseDto
{
TotalCount = (int)response.MetaData.TotalCount,
TotalPage = (int)response.MetaData.TotalPage,
// ... explicit mapping
};
10. 👤 Network Balances Enhancement ✅
نیاز: نمایش نام کامل کاربر و جزئیات breakdown پای چپ/راست در صفحه balanceهای شبکه
10.1 CMS Proto Update
فایل: CMS/Protobufs/Protos/commission.proto
message UserWeeklyBalanceModel {
// ... existing fields
string user_full_name = 13;
int64 left_leg_new_members = 14;
int64 left_leg_carryover = 15;
int64 left_leg_total = 16;
int64 right_leg_new_members = 17;
int64 right_leg_carryover = 18;
int64 right_leg_total = 19;
}
10.2 CMS Handler Update
فایل: CMS.Application/.../GetUserWeeklyBalancesQueryHandler.cs
var query = _dbContext.NetworkWeeklyBalances
.Include(x => x.User) // NEW: Include User
.Include(x => x.WeekDefinition)
.Where(x => x.WeekDefinitionId == request.WeekDefinitionId);
// In projection:
UserFullName = $"{x.User.FirstName} {x.User.LastName}".Trim(),
LeftLegNewMembers = x.LeftLegNewMembers,
LeftLegCarryover = x.LeftLegCarryover,
LeftLegTotal = x.LeftLegTotal,
RightLegNewMembers = x.RightLegNewMembers,
RightLegCarryover = x.RightLegCarryover,
RightLegTotal = x.RightLegTotal,
10.3 BackOffice UI Update
فایل: BackOffice/Pages/Network/BalancesReport.razor
@* ستون نام کاربر *@
<PropertyColumn Property="x => x.UserFullName" Title="نام کاربر" />
@* ستون پای چپ با Tooltip *@
<TemplateColumn Title="پای چپ">
<CellTemplate>
<MudTooltip Text="@($"جدید: {FormatNumber(context.Item.LeftLegNewMembers)} | انتقالی: {FormatNumber(context.Item.LeftLegCarryover)}")">
<MudText>@FormatNumber(context.Item.LeftLegTotal)</MudText>
</MudTooltip>
</CellTemplate>
</TemplateColumn>
@* ستون پای راست با Tooltip *@
<TemplateColumn Title="پای راست">
<CellTemplate>
<MudTooltip Text="@($"جدید: {FormatNumber(context.Item.RightLegNewMembers)} | انتقالی: {FormatNumber(context.Item.RightLegCarryover)}")">
<MudText>@FormatNumber(context.Item.RightLegTotal)</MudText>
</MudTooltip>
</CellTemplate>
</TemplateColumn>
10.4 Proto Package Update
# Publish new proto package
cd CMS/Protobufs
# Update version in .csproj to 0.0.14
dotnet pack
dotnet nuget push ...
# Update BackOffice
cd BackOffice/src/BackOffice
# Update package reference in .csproj
<PackageReference Include="Foursat.BackOffice.BFF.Commission.Protobuf" Version="0.0.14" />
11. 🔢 WeekDefinitionId Mapping Fix ✅
مشکل: WeekDefinitionId همیشه 0 به BFF ارسال میشد، حتی اگر در client مقدار صحیح ست شده بود.
علت: در protobuf، فیلد week_definition_id از نوع google.protobuf.Int64Value است که یک wrapper type هست. در mapping مستقیم assign میشد بدون extract کردن .Value.
فایل: FrontOffice.BFF/src/FrontOffice.BFF.WebApi/Common/Mappings/CommissionProfile.cs
Proto Definition:
message GetMyWeeklyBalancesRequest {
google.protobuf.Int64Value week_definition_id = 3;
}
قبل:
config.NewConfig<GetMyWeeklyBalancesRequest, GetMyWeeklyBalancesQuery>()
.Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId); // BUG: assigns Int64Value object, not the value
بعد:
config.NewConfig<GetMyWeeklyBalancesRequest, GetMyWeeklyBalancesQuery>()
.Map(dest => dest.WeekDefinitionId,
src => src.WeekDefinitionId != null ? src.WeekDefinitionId.Value : null);
توضیح:
Int64Valueیک wrapper class در protobuf هست برای nullable long- وقتی مستقیم assign کنید، implicit conversion اتفاق نمیفته
- باید explicit از
.Valueاستفاده کنید
📦 فایلهای تغییر یافته
CMS
| فایل | نوع تغییر |
|---|---|
Domain/Common/SystemConstants.cs |
Modified - اضافه شدن GoldenPackageAmount, DayaLoanAmount |
Domain/Common/SmsTemplates.cs |
New - قالبهای پیامک |
Application/.../ProcessDayaLoanApprovalCommandHandler.cs |
Modified - اضافه شدن SMS |
WebApi/Common/Mappings/AppVersionProfile.cs |
New - Mapster profile |
Application/.../GetAllWeeklyPoolsQueryHandler.cs |
Modified - تغییر WeekDisplayName از PersianWeekNumber به DisplayName |
Application/.../GetUserWeeklyBalancesQueryHandler.cs |
Modified - اضافه شدن User include و فیلدهای جدید |
Application/.../GetUserWeeklyBalancesResponseDto.cs |
Modified - اضافه شدن UserFullName و breakdown fields |
WebApi/Common/Mappings/CommissionProfile.cs |
Modified - mapping جدید برای UserWeeklyBalanceModel |
Protobufs/Protos/commission.proto |
Modified - اضافه شدن فیلدهای جدید به UserWeeklyBalanceModel |
BackOffice.BFF
| فایل | نوع تغییر |
|---|---|
Application/Common/Mappings/CommissionProfile.cs |
Modified - اضافه شدن GetAllWeeklyPools mapping + ProcessWithdrawal mapping |
WebApi/Common/Mappings/GeneralMapping.cs |
Modified - اضافه شدن Unit to Empty |
Application/.../GetWithdrawalRequestsQueryHandler.cs |
Modified - explicit mapping به جای Adapt<> |
Application/.../GetWithdrawalRequestsResponseDto.cs |
Modified - تطابق با CMS proto |
Protobufs/Protos/commission.proto |
Modified - اضافه شدن فیلدهای جدید |
BackOffice
| فایل | نوع تغییر |
|---|---|
Shared/NavMenu.razor |
Modified - اضافه شدن لینک app-versions |
Pages/Settings/AppVersions.razor |
Modified - دکمه افزودن + OpenCreateDialog |
Pages/Settings/Components/AppVersionEditDialog.razor |
Modified - پارامتر IsNew + Select |
Pages/Network/BalancesReport.razor |
Modified - ستونهای جدید با MudTooltip |
BackOffice.csproj |
Modified - آپدیت proto package به v0.0.14 |
FrontOffice.BFF
| فایل | نوع تغییر |
|---|---|
WebApi/Common/Mappings/CommissionProfile.cs |
Modified - رفع WeekDefinitionId mapping (Int64Value.Value) |
Application/.../GetMyWeeklyBalancesQueryHandler.cs |
Modified - simplify status handling |
FrontOffice
| فایل | نوع تغییر |
|---|---|
Utilities/CommissionService.cs |
Modified - اضافه شدن GetStatusColor و MapStatus (انتقال از BFF) |
Pages/Commission/WeeklyBalancePage.razor.cs |
Modified - استفاده از متدهای جدید CommissionService |
✅ Build Status
# CMS
dotnet build CMSMicroservice.WebApi/CMSMicroservice.WebApi.csproj
# Build succeeded. 0 Error(s)
# BackOffice.BFF
dotnet build BackOffice.BFF.WebApi/BackOffice.BFF.WebApi.csproj
# Build succeeded. 0 Error(s)
# BackOffice
dotnet build BackOffice/BackOffice.csproj
# Build succeeded. 0 Error(s)
# FrontOffice.BFF
dotnet build FrontOffice.BFF.WebApi/FrontOffice.BFF.WebApi.csproj
# Build succeeded. 0 Error(s)
# FrontOffice
dotnet build FrontOffice.Main/FrontOffice.Main.csproj
# Build succeeded. 0 Error(s)
📊 آمار Session
| متریک | مقدار |
|---|---|
| فایلهای جدید | 2 |
| فایلهای تغییر یافته | 18 |
| خطوط کد اضافه شده | ~500 |
| باگهای Mapping رفع شده | 5 |
| پروژههای تأثیرگذار | 5 (CMS, BackOffice, BackOffice.BFF, FrontOffice, FrontOffice.BFF) |
🔗 Related Changelogs
- CHANGELOG-2025-12-26.md - App Version Management + ReferralCode in Tree
- CHANGELOG-2025-12-25.md - درخت شبکه BackOffice