feat: implement Kavenegar SMS service and refactor system configurations to use static constants
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 1m38s
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 1m38s
This commit is contained in:
+8
-31
@@ -1,5 +1,6 @@
|
||||
using CMSMicroservice.Application.Common.Exceptions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using CMSMicroservice.Domain.Entities.Club;
|
||||
using CMSMicroservice.Domain.Entities.Commission;
|
||||
@@ -126,38 +127,14 @@ public class AcceptClubMembershipContractCommandHandler
|
||||
};
|
||||
await _context.UserContracts.AddAsync(userContract, cancellationToken);
|
||||
|
||||
// 6. دریافت مقادیر از تنظیمات سیستم
|
||||
var giftValueConfig = await _context.SystemConfigurations
|
||||
.FirstOrDefaultAsync(
|
||||
c => c.Key == "Club.MembershipGiftValue" && c.IsActive,
|
||||
cancellationToken
|
||||
);
|
||||
// 6. دریافت مقادیر از SystemConstants (استاتیک)
|
||||
long giftValue = SystemConstants.ClubMembershipGiftValue;
|
||||
long activationFeeValue = SystemConstants.ClubActivationFee;
|
||||
|
||||
var activationFeeConfig = await _context.SystemConfigurations
|
||||
.FirstOrDefaultAsync(
|
||||
c => c.Key == "Club.ActivationFee" && c.IsActive,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
long giftValue = 28_000_000; // مقدار پیشفرض
|
||||
if (giftValueConfig != null && long.TryParse(giftValueConfig.Value, out var configValue))
|
||||
{
|
||||
giftValue = configValue;
|
||||
_logger.LogInformation(
|
||||
"Using Club.MembershipGiftValue from configuration: {GiftValue}",
|
||||
giftValue
|
||||
);
|
||||
}
|
||||
|
||||
long activationFeeValue = 25_200_000; // مقدار پیشفرض
|
||||
if (activationFeeConfig != null && long.TryParse(activationFeeConfig.Value, out var activationFeeConfigValue))
|
||||
{
|
||||
activationFeeValue = activationFeeConfigValue;
|
||||
_logger.LogInformation(
|
||||
"Using Club.ActivationFee from configuration: {activationFeeValue}",
|
||||
activationFeeValue
|
||||
);
|
||||
}
|
||||
_logger.LogInformation(
|
||||
"Using Club.MembershipGiftValue: {GiftValue}, Club.ActivationFee: {ActivationFee}",
|
||||
giftValue, activationFeeValue
|
||||
);
|
||||
|
||||
// 7. فعالسازی باشگاه مشتریان
|
||||
ClubMembership clubMembership;
|
||||
|
||||
+10
-46
@@ -1,6 +1,7 @@
|
||||
using CMSMicroservice.Application.Common.Exceptions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using CMSMicroservice.Domain.Entities.Club;
|
||||
using CMSMicroservice.Domain.Entities.Commission;
|
||||
@@ -75,7 +76,7 @@ public class ActivateClubMembershipCommandHandler : IRequestHandler<ActivateClub
|
||||
throw new NotFoundException("کیف پول کاربر یافت نشد");
|
||||
}
|
||||
|
||||
if (wallet.Balance < 56_000_000)
|
||||
if (wallet.Balance < SystemConstants.BasePackageAmount)
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"User {UserId} has insufficient balance: {Balance}",
|
||||
@@ -83,7 +84,7 @@ public class ActivateClubMembershipCommandHandler : IRequestHandler<ActivateClub
|
||||
wallet.Balance
|
||||
);
|
||||
throw new BadRequestException(
|
||||
"برای فعالسازی باشگاه مشتریان باید حداقل 56 میلیون تومان موجودی اصلی داشته باشید"
|
||||
$"برای فعالسازی باشگاه مشتریان باید حداقل {SystemConstants.BasePackageAmount:N0} ریال موجودی اصلی داشته باشید"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -135,51 +136,14 @@ public class ActivateClubMembershipCommandHandler : IRequestHandler<ActivateClub
|
||||
var existingMembership = await _context.ClubMemberships
|
||||
.FirstOrDefaultAsync(c => c.UserId == user.Id, cancellationToken);
|
||||
|
||||
// 6.1. دریافت مبلغ هدیه از تنظیمات
|
||||
var giftValueConfig = await _context.SystemConfigurations
|
||||
.FirstOrDefaultAsync(
|
||||
c => c.Key == "Club.MembershipGiftValue" && c.IsActive,
|
||||
cancellationToken
|
||||
);
|
||||
// 6.1. دریافت مبلغ هدیه و هزینه فعالسازی از SystemConstants
|
||||
long giftValue = SystemConstants.ClubMembershipGiftValue;
|
||||
long activationFeeValue = SystemConstants.ClubActivationFee;
|
||||
|
||||
var activationFeeConfig = await _context.SystemConfigurations
|
||||
.FirstOrDefaultAsync(
|
||||
c => c.Key == "Club.ActivationFee" && c.IsActive,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
long giftValue = 28_000_000; // مقدار پیشفرض
|
||||
if (giftValueConfig != null && long.TryParse(giftValueConfig.Value, out var configValue))
|
||||
{
|
||||
giftValue = configValue;
|
||||
_logger.LogInformation(
|
||||
"Using Club.MembershipGiftValue from configuration: {GiftValue}",
|
||||
giftValue
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Club.MembershipGiftValue not found in configuration, using default: {GiftValue}",
|
||||
giftValue
|
||||
);
|
||||
}
|
||||
long activationFeeValue = 25_200_000; // مقدار پیشفرض
|
||||
if (activationFeeConfig != null && long.TryParse(activationFeeConfig.Value, out var activationFeeConfigValue))
|
||||
{
|
||||
activationFeeValue = activationFeeConfigValue;
|
||||
_logger.LogInformation(
|
||||
"Using Club.ActivationFee from configuration: {activationFeeValue}",
|
||||
activationFeeValue
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Club.ActivationFee not found in configuration, using default: {activationFeeValue}",
|
||||
activationFeeValue
|
||||
);
|
||||
}
|
||||
_logger.LogInformation(
|
||||
"Using Club.MembershipGiftValue: {GiftValue}, Club.ActivationFee: {ActivationFee}",
|
||||
giftValue, activationFeeValue
|
||||
);
|
||||
|
||||
ClubMembership entity;
|
||||
bool isNewMembership = existingMembership == null;
|
||||
|
||||
+5
-13
@@ -1,3 +1,5 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
namespace CMSMicroservice.Application.CommissionCQ.Commands.CalculateWeeklyBalances;
|
||||
|
||||
public class CalculateWeeklyBalancesCommandHandler : IRequestHandler<CalculateWeeklyBalancesCommand, int>
|
||||
@@ -74,21 +76,11 @@ public class CalculateWeeklyBalancesCommandHandler : IRequestHandler<CalculateWe
|
||||
var balancesList = new List<NetworkWeeklyBalance>();
|
||||
var calculatedAt = DateTime.Now;
|
||||
|
||||
// خواندن یکباره Configuration ها (بهینهسازی - به جای N query)
|
||||
var configs = await _context.SystemConfigurations
|
||||
.Where(x => x.IsActive && (
|
||||
x.Key == "Club.ActivationFee" ||
|
||||
x.Key == "Commission.WeeklyPoolContributionPercent" ||
|
||||
x.Key == "Commission.MaxWeeklyBalancesPerLeg" ||
|
||||
x.Key == "Commission.MaxNetworkLevel"))
|
||||
.ToDictionaryAsync(x => x.Key, x => x.Value, cancellationToken);
|
||||
|
||||
// var activationFee = long.Parse(configs.GetValueOrDefault("Club.ActivationFee", "25000000"));
|
||||
// var poolPercent = decimal.Parse(configs.GetValueOrDefault("Commission.WeeklyPoolContributionPercent", "20")) / 100m;
|
||||
// استفاده از SystemConstants (استاتیک - بدون کوئری به دیتابیس)
|
||||
// سقف تعادل هفتگی برای هر دست (نه کل) - 300 برای چپ + 300 برای راست = حداکثر 600 تعادل
|
||||
var maxBalancesPerLeg = int.Parse(configs.GetValueOrDefault("Commission.MaxWeeklyBalancesPerLeg", "300"));
|
||||
var maxBalancesPerLeg = SystemConstants.CommissionMaxWeeklyBalancesPerLeg;
|
||||
// حداکثر عمق شبکه برای شمارش اعضا (15 لول)
|
||||
var maxNetworkLevel = int.Parse(configs.GetValueOrDefault("Commission.MaxNetworkLevel", "15"));
|
||||
var maxNetworkLevel = SystemConstants.CommissionMaxNetworkLevel;
|
||||
|
||||
foreach (var user in usersInNetwork.OrderBy(o=>o.Id))
|
||||
{
|
||||
|
||||
+4
-6
@@ -1,3 +1,5 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
namespace CMSMicroservice.Application.CommissionCQ.Commands.ProcessUserPayouts;
|
||||
|
||||
public class ProcessUserPayoutsCommandHandler : IRequestHandler<ProcessUserPayoutsCommand, int>
|
||||
@@ -47,12 +49,8 @@ public class ProcessUserPayoutsCommandHandler : IRequestHandler<ProcessUserPayou
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
// ⭐ خواندن MaxNetworkLevel از Config
|
||||
var maxNetworkLevelConfig = await _context.SystemConfigurations
|
||||
.Where(x => x.Key == "Commission.MaxNetworkLevel" && x.IsActive)
|
||||
.Select(x => x.Value)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
var maxNetworkLevel = int.Parse(maxNetworkLevelConfig ?? "15");
|
||||
// ⭐ خواندن MaxNetworkLevel از SystemConstants (استاتیک)
|
||||
var maxNetworkLevel = SystemConstants.CommissionMaxNetworkLevel;
|
||||
|
||||
// دریافت همه تعادلهای هفتگی (شامل صفرها هم برای محاسبه زیرمجموعه)
|
||||
var allWeeklyBalances = await _context.NetworkWeeklyBalances
|
||||
|
||||
@@ -31,8 +31,6 @@ public interface IApplicationDbContext
|
||||
DbSet<UserPackagePurchase> UserPackagePurchases { get; }
|
||||
DbSet<UserWallet> UserWallets { get; }
|
||||
DbSet<UserWalletChangeLog> UserWalletChangeLogs { get; }
|
||||
DbSet<SystemConfiguration> SystemConfigurations { get; }
|
||||
DbSet<SystemConfigurationHistory> SystemConfigurationHistories { get; }
|
||||
DbSet<ManualPayment> ManualPayments { get; }
|
||||
DbSet<PublicMessage> PublicMessages { get; }
|
||||
DbSet<ClubMembership> ClubMemberships { get; }
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace CMSMicroservice.Application.Common.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// سرویس ارسال SMS با کاوهنگار
|
||||
/// </summary>
|
||||
public interface IKavenegarService
|
||||
{
|
||||
/// <summary>
|
||||
/// ارسال پیامک ساده
|
||||
/// </summary>
|
||||
Task SendAsync(string mobile, string message);
|
||||
|
||||
/// <summary>
|
||||
/// ارسال پیامک با قالب (VerifyLookup)
|
||||
/// </summary>
|
||||
Task VerifyLookupAsync(string mobile, string token, string template = "Afrino");
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Commands.DeactivateConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// Command برای غیرفعال کردن یک Configuration
|
||||
/// </summary>
|
||||
public record DeactivateConfigurationCommand : IRequest<Unit>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه Configuration
|
||||
/// </summary>
|
||||
public long ConfigurationId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// دلیل غیرفعالسازی
|
||||
/// </summary>
|
||||
public string? Reason { get; init; }
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Commands.DeactivateConfiguration;
|
||||
|
||||
public class DeactivateConfigurationCommandHandler : IRequestHandler<DeactivateConfigurationCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public DeactivateConfigurationCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(DeactivateConfigurationCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var entity = await _context.SystemConfigurations
|
||||
.FirstOrDefaultAsync(x => x.Id == request.ConfigurationId, cancellationToken)
|
||||
?? throw new NotFoundException(nameof(SystemConfiguration), request.ConfigurationId);
|
||||
|
||||
// اگر از قبل غیرفعال است، خطا ندهیم
|
||||
if (!entity.IsActive)
|
||||
{
|
||||
return Unit.Value;
|
||||
}
|
||||
|
||||
var oldValue = entity.Value;
|
||||
entity.IsActive = false;
|
||||
|
||||
_context.SystemConfigurations.Update(entity);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// ثبت تاریخچه
|
||||
var history = new SystemConfigurationHistory
|
||||
{
|
||||
ConfigurationId = entity.Id,
|
||||
Scope = entity.Scope,
|
||||
Key = entity.Key,
|
||||
OldValue = oldValue,
|
||||
NewValue = entity.Value,
|
||||
Reason = request.Reason ?? "Configuration deactivated",
|
||||
PerformedBy = _currentUser.GetPerformedBy()
|
||||
};
|
||||
|
||||
await _context.SystemConfigurationHistories.AddAsync(history, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Commands.DeactivateConfiguration;
|
||||
|
||||
public class DeactivateConfigurationCommandValidator : AbstractValidator<DeactivateConfigurationCommand>
|
||||
{
|
||||
public DeactivateConfigurationCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.ConfigurationId)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("شناسه Configuration معتبر نیست");
|
||||
|
||||
RuleFor(x => x.Reason)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("دلیل غیرفعالسازی نمیتواند بیشتر از 500 کاراکتر باشد")
|
||||
.When(x => !string.IsNullOrEmpty(x.Reason));
|
||||
}
|
||||
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(
|
||||
ValidationContext<DeactivateConfigurationCommand>.CreateWithOptions(
|
||||
(DeactivateConfigurationCommand)model,
|
||||
x => x.IncludeProperties(propertyName)));
|
||||
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Commands.SeedVATConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// Seed initial VAT configuration
|
||||
/// نرخ مالیات پیشفرض ۹٪
|
||||
/// </summary>
|
||||
public class SeedVATConfigurationCommand : IRequest<Unit>
|
||||
{
|
||||
}
|
||||
|
||||
public class SeedVATConfigurationCommandHandler : IRequestHandler<SeedVATConfigurationCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ILogger<SeedVATConfigurationCommandHandler> _logger;
|
||||
|
||||
public SeedVATConfigurationCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ILogger<SeedVATConfigurationCommandHandler> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(SeedVATConfigurationCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var configs = new[]
|
||||
{
|
||||
new
|
||||
{
|
||||
Scope = ConfigurationScope.VAT,
|
||||
Key = "Rate",
|
||||
Value = "0.09",
|
||||
Description = "نرخ مالیات بر ارزش افزوده (۹٪)"
|
||||
},
|
||||
new
|
||||
{
|
||||
Scope = ConfigurationScope.VAT,
|
||||
Key = "IsEnabled",
|
||||
Value = "true",
|
||||
Description = "فعال/غیرفعال بودن محاسبه مالیات"
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var config in configs)
|
||||
{
|
||||
var exists = _context.SystemConfigurations
|
||||
.Any(x => x.Scope == config.Scope && x.Key == config.Key);
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
_context.SystemConfigurations.Add(new Domain.Entities.Configuration.SystemConfiguration
|
||||
{
|
||||
Scope = config.Scope,
|
||||
Key = config.Key,
|
||||
Value = config.Value,
|
||||
Description = config.Description
|
||||
});
|
||||
|
||||
_logger.LogInformation(
|
||||
"VAT configuration seeded: {Scope}.{Key} = {Value}",
|
||||
config.Scope,
|
||||
config.Key,
|
||||
config.Value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Commands.SetConfigurationValue;
|
||||
|
||||
/// <summary>
|
||||
/// Command برای تنظیم یا بهروزرسانی یک Configuration
|
||||
/// </summary>
|
||||
public record SetConfigurationValueCommand : IRequest<long>
|
||||
{
|
||||
/// <summary>
|
||||
/// محدوده تنظیمات (System, Network, Club, Commission)
|
||||
/// </summary>
|
||||
public ConfigurationScope Scope { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// کلید یکتا برای تنظیمات
|
||||
/// </summary>
|
||||
public string Key { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// مقدار تنظیمات (JSON format)
|
||||
/// </summary>
|
||||
public string Value { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// توضیحات تنظیمات
|
||||
/// </summary>
|
||||
public string? Description { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// دلیل تغییر (برای History)
|
||||
/// </summary>
|
||||
public string? ChangeReason { get; init; }
|
||||
}
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Commands.SetConfigurationValue;
|
||||
|
||||
public class SetConfigurationValueCommandHandler : IRequestHandler<SetConfigurationValueCommand, long>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public SetConfigurationValueCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<long> Handle(SetConfigurationValueCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// بررسی وجود Configuration با همین Scope و Key
|
||||
var existingConfig = await _context.SystemConfigurations
|
||||
.FirstOrDefaultAsync(x =>
|
||||
x.Scope == request.Scope &&
|
||||
x.Key == request.Key,
|
||||
cancellationToken);
|
||||
|
||||
SystemConfiguration entity;
|
||||
bool isNewRecord = existingConfig == null;
|
||||
string oldValue = null;
|
||||
|
||||
if (isNewRecord)
|
||||
{
|
||||
// ایجاد Configuration جدید
|
||||
entity = new SystemConfiguration
|
||||
{
|
||||
Scope = request.Scope,
|
||||
Key = request.Key,
|
||||
Value = request.Value,
|
||||
Description = request.Description,
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
await _context.SystemConfigurations.AddAsync(entity, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
// بهروزرسانی Configuration موجود
|
||||
entity = existingConfig;
|
||||
oldValue = entity.Value;
|
||||
|
||||
entity.Value = request.Value;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Description))
|
||||
{
|
||||
entity.Description = request.Description;
|
||||
}
|
||||
|
||||
_context.SystemConfigurations.Update(entity);
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// ثبت تاریخچه
|
||||
var history = new SystemConfigurationHistory
|
||||
{
|
||||
ConfigurationId = entity.Id,
|
||||
Scope = entity.Scope,
|
||||
Key = entity.Key,
|
||||
OldValue = oldValue,
|
||||
NewValue = entity.Value,
|
||||
Reason = request.ChangeReason ?? (isNewRecord ? "Initial creation" : "Value updated"),
|
||||
PerformedBy = "System" // TODO: باید از Current User گرفته شود
|
||||
};
|
||||
|
||||
await _context.SystemConfigurationHistories.AddAsync(history, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return entity.Id;
|
||||
}
|
||||
}
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Commands.SetConfigurationValue;
|
||||
|
||||
public class SetConfigurationValueCommandValidator : AbstractValidator<SetConfigurationValueCommand>
|
||||
{
|
||||
public SetConfigurationValueCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.Scope)
|
||||
.IsInEnum()
|
||||
.WithMessage("محدوده تنظیمات معتبر نیست");
|
||||
|
||||
RuleFor(x => x.Key)
|
||||
.NotEmpty()
|
||||
.WithMessage("کلید تنظیمات الزامی است")
|
||||
.MaximumLength(100)
|
||||
.WithMessage("کلید تنظیمات نمیتواند بیشتر از 100 کاراکتر باشد")
|
||||
.Matches(@"^[a-zA-Z0-9_\.]+$")
|
||||
.WithMessage("کلید تنظیمات فقط میتواند شامل حروف انگلیسی، اعداد، نقطه و آندرلاین باشد");
|
||||
|
||||
RuleFor(x => x.Value)
|
||||
.NotEmpty()
|
||||
.WithMessage("مقدار تنظیمات الزامی است")
|
||||
.MaximumLength(2000)
|
||||
.WithMessage("مقدار تنظیمات نمیتواند بیشتر از 2000 کاراکتر باشد");
|
||||
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("توضیحات نمیتواند بیشتر از 500 کاراکتر باشد")
|
||||
.When(x => !string.IsNullOrEmpty(x.Description));
|
||||
|
||||
RuleFor(x => x.ChangeReason)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("دلیل تغییر نمیتواند بیشتر از 500 کاراکتر باشد")
|
||||
.When(x => !string.IsNullOrEmpty(x.ChangeReason));
|
||||
}
|
||||
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(
|
||||
ValidationContext<SetConfigurationValueCommand>.CreateWithOptions(
|
||||
(SetConfigurationValueCommand)model,
|
||||
x => x.IncludeProperties(propertyName)));
|
||||
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetAllConfigurations;
|
||||
|
||||
/// <summary>
|
||||
/// Query برای دریافت لیست تمام Configuration ها با فیلتر
|
||||
/// </summary>
|
||||
public record GetAllConfigurationsQuery : IRequest<GetAllConfigurationsResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// موقعیت صفحهبندی
|
||||
/// </summary>
|
||||
public PaginationState? PaginationState { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// مرتبسازی بر اساس
|
||||
/// </summary>
|
||||
public string? SortBy { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// فیلتر
|
||||
/// </summary>
|
||||
public GetAllConfigurationsFilter? Filter { get; init; }
|
||||
}
|
||||
|
||||
public class GetAllConfigurationsFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// فیلتر بر اساس محدوده
|
||||
/// </summary>
|
||||
public ConfigurationScope? Scope { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// جستجو در کلید
|
||||
/// </summary>
|
||||
public string? KeyContains { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// فقط Configuration های فعال
|
||||
/// </summary>
|
||||
public bool? IsActive { get; set; }
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetAllConfigurations;
|
||||
|
||||
public class GetAllConfigurationsQueryHandler : IRequestHandler<GetAllConfigurationsQuery, GetAllConfigurationsResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
|
||||
public GetAllConfigurationsQueryHandler(IApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetAllConfigurationsResponseDto> Handle(GetAllConfigurationsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _context.SystemConfigurations
|
||||
.ApplyOrder(sortBy: request.SortBy)
|
||||
.AsNoTracking()
|
||||
.AsQueryable();
|
||||
|
||||
if (request.Filter is not null)
|
||||
{
|
||||
query = query
|
||||
.Where(x => request.Filter.Scope == null || x.Scope == request.Filter.Scope)
|
||||
.Where(x => request.Filter.KeyContains == null || x.Key.Contains(request.Filter.KeyContains))
|
||||
.Where(x => request.Filter.IsActive == null || x.IsActive == request.Filter.IsActive);
|
||||
}
|
||||
|
||||
var meta = await query.GetMetaData(request.PaginationState, cancellationToken);
|
||||
|
||||
var models = await query
|
||||
.PaginatedListAsync(paginationState: request.PaginationState)
|
||||
.Select(x => new GetAllConfigurationsResponseModel
|
||||
{
|
||||
Id = x.Id,
|
||||
Scope = x.Scope,
|
||||
Key = x.Key,
|
||||
Value = x.Value,
|
||||
Description = x.Description,
|
||||
IsActive = x.IsActive,
|
||||
Created = x.Created,
|
||||
LastModified = x.LastModified
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return new GetAllConfigurationsResponseDto
|
||||
{
|
||||
MetaData = meta,
|
||||
Models = models
|
||||
};
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetAllConfigurations;
|
||||
|
||||
public class GetAllConfigurationsQueryValidator : AbstractValidator<GetAllConfigurationsQuery>
|
||||
{
|
||||
public GetAllConfigurationsQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.Filter.Scope)
|
||||
.IsInEnum()
|
||||
.WithMessage("محدوده تنظیمات معتبر نیست")
|
||||
.When(x => x.Filter?.Scope != null);
|
||||
}
|
||||
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(
|
||||
ValidationContext<GetAllConfigurationsQuery>.CreateWithOptions(
|
||||
(GetAllConfigurationsQuery)model,
|
||||
x => x.IncludeProperties(propertyName)));
|
||||
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetAllConfigurations;
|
||||
|
||||
public class GetAllConfigurationsResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public List<GetAllConfigurationsResponseModel> Models { get; set; }
|
||||
}
|
||||
|
||||
public class GetAllConfigurationsResponseModel
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public ConfigurationScope Scope { get; set; }
|
||||
public string Key { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public DateTimeOffset Created { get; set; }
|
||||
public DateTimeOffset? LastModified { get; set; }
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetConfigurationByKey;
|
||||
|
||||
/// <summary>
|
||||
/// DTO برای نمایش اطلاعات Configuration
|
||||
/// </summary>
|
||||
public class ConfigurationDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public ConfigurationScope Scope { get; set; }
|
||||
public string Key { get; set; }
|
||||
public string Value { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public DateTimeOffset Created { get; set; }
|
||||
public DateTimeOffset? LastModified { get; set; }
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetConfigurationByKey;
|
||||
|
||||
/// <summary>
|
||||
/// Query برای دریافت یک Configuration بر اساس Scope و Key
|
||||
/// </summary>
|
||||
public record GetConfigurationByKeyQuery : IRequest<ConfigurationDto?>
|
||||
{
|
||||
/// <summary>
|
||||
/// محدوده تنظیمات
|
||||
/// </summary>
|
||||
public ConfigurationScope Scope { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// کلید تنظیمات
|
||||
/// </summary>
|
||||
public string Key { get; init; }
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetConfigurationByKey;
|
||||
|
||||
public class GetConfigurationByKeyQueryHandler : IRequestHandler<GetConfigurationByKeyQuery, ConfigurationDto?>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
|
||||
public GetConfigurationByKeyQueryHandler(IApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<ConfigurationDto?> Handle(GetConfigurationByKeyQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var config = await _context.SystemConfigurations
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Scope == request.Scope && x.Key == request.Key)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (config == null)
|
||||
return null;
|
||||
|
||||
return new ConfigurationDto
|
||||
{
|
||||
Id = config.Id,
|
||||
Scope = config.Scope,
|
||||
Key = config.Key,
|
||||
Value = config.Value,
|
||||
Description = config.Description,
|
||||
IsActive = config.IsActive,
|
||||
Created = config.Created,
|
||||
LastModified = config.LastModified
|
||||
};
|
||||
}
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetConfigurationByKey;
|
||||
|
||||
public class GetConfigurationByKeyQueryValidator : AbstractValidator<GetConfigurationByKeyQuery>
|
||||
{
|
||||
public GetConfigurationByKeyQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.Scope)
|
||||
.IsInEnum()
|
||||
.WithMessage("محدوده تنظیمات معتبر نیست");
|
||||
|
||||
RuleFor(x => x.Key)
|
||||
.NotEmpty()
|
||||
.WithMessage("کلید تنظیمات الزامی است");
|
||||
}
|
||||
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(
|
||||
ValidationContext<GetConfigurationByKeyQuery>.CreateWithOptions(
|
||||
(GetConfigurationByKeyQuery)model,
|
||||
x => x.IncludeProperties(propertyName)));
|
||||
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetConfigurationHistory;
|
||||
|
||||
/// <summary>
|
||||
/// Query برای دریافت تاریخچه تغییرات یک Configuration
|
||||
/// </summary>
|
||||
public record GetConfigurationHistoryQuery : IRequest<GetConfigurationHistoryResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه Configuration
|
||||
/// </summary>
|
||||
public long ConfigurationId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// موقعیت صفحهبندی
|
||||
/// </summary>
|
||||
public PaginationState? PaginationState { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// مرتبسازی بر اساس
|
||||
/// </summary>
|
||||
public string? SortBy { get; init; }
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetConfigurationHistory;
|
||||
|
||||
public class GetConfigurationHistoryQueryHandler : IRequestHandler<GetConfigurationHistoryQuery, GetConfigurationHistoryResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
|
||||
public GetConfigurationHistoryQueryHandler(IApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetConfigurationHistoryResponseDto> Handle(GetConfigurationHistoryQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
// بررسی وجود Configuration
|
||||
var configExists = await _context.SystemConfigurations
|
||||
.AnyAsync(x => x.Id == request.ConfigurationId, cancellationToken);
|
||||
|
||||
if (!configExists)
|
||||
{
|
||||
throw new NotFoundException(nameof(SystemConfiguration), request.ConfigurationId);
|
||||
}
|
||||
|
||||
var query = _context.SystemConfigurationHistories
|
||||
.Where(x => x.ConfigurationId == request.ConfigurationId)
|
||||
.ApplyOrder(sortBy: request.SortBy ?? "Created") // پیشفرض: جدیدترین اول
|
||||
.AsNoTracking()
|
||||
.AsQueryable();
|
||||
|
||||
var meta = await query.GetMetaData(request.PaginationState, cancellationToken);
|
||||
|
||||
var models = await query
|
||||
.PaginatedListAsync(paginationState: request.PaginationState)
|
||||
.Select(x => new GetConfigurationHistoryResponseModel
|
||||
{
|
||||
Id = x.Id,
|
||||
ConfigurationId = x.ConfigurationId,
|
||||
Scope = x.Scope,
|
||||
Key = x.Key,
|
||||
OldValue = x.OldValue,
|
||||
NewValue = x.NewValue,
|
||||
ChangeReason = x.Reason,
|
||||
ChangedBy = x.PerformedBy,
|
||||
Created = x.Created
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return new GetConfigurationHistoryResponseDto
|
||||
{
|
||||
MetaData = meta,
|
||||
Models = models
|
||||
};
|
||||
}
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetConfigurationHistory;
|
||||
|
||||
public class GetConfigurationHistoryQueryValidator : AbstractValidator<GetConfigurationHistoryQuery>
|
||||
{
|
||||
public GetConfigurationHistoryQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.ConfigurationId)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("شناسه Configuration معتبر نیست");
|
||||
}
|
||||
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(
|
||||
ValidationContext<GetConfigurationHistoryQuery>.CreateWithOptions(
|
||||
(GetConfigurationHistoryQuery)model,
|
||||
x => x.IncludeProperties(propertyName)));
|
||||
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
namespace CMSMicroservice.Application.ConfigurationCQ.Queries.GetConfigurationHistory;
|
||||
|
||||
public class GetConfigurationHistoryResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public List<GetConfigurationHistoryResponseModel> Models { get; set; }
|
||||
}
|
||||
|
||||
public class GetConfigurationHistoryResponseModel
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long ConfigurationId { get; set; }
|
||||
public ConfigurationScope Scope { get; set; }
|
||||
public string Key { get; set; }
|
||||
public string? OldValue { get; set; }
|
||||
public string NewValue { get; set; }
|
||||
public string ChangeReason { get; set; }
|
||||
public string ChangedBy { get; set; }
|
||||
public DateTimeOffset Created { get; set; }
|
||||
}
|
||||
+8
-12
@@ -1,5 +1,6 @@
|
||||
using CMSMicroservice.Domain.Events;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using CMSMicroservice.Application.DayaLoanCQ.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -10,11 +11,6 @@ public class CheckDayaLoanStatusCommandHandler : IRequestHandler<CheckDayaLoanSt
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly IDayaLoanApiService _dayaApiService;
|
||||
private readonly ILogger<CheckDayaLoanStatusCommandHandler> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ وام دایا - 56 میلیون ریال
|
||||
/// </summary>
|
||||
private const long DAYA_LOAN_AMOUNT = 56_000_000;
|
||||
|
||||
public CheckDayaLoanStatusCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
@@ -69,7 +65,7 @@ public class CheckDayaLoanStatusCommandHandler : IRequestHandler<CheckDayaLoanSt
|
||||
|
||||
_logger.LogInformation(
|
||||
"Daya loan processed for User {UserId}, ContractNumber: {ContractNumber}, Amount: {Amount}",
|
||||
existingContract.UserId, dayaResult.ContractNumber, DAYA_LOAN_AMOUNT);
|
||||
existingContract.UserId, dayaResult.ContractNumber, SystemConstants.DayaLoanAmount);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -90,7 +86,7 @@ public class CheckDayaLoanStatusCommandHandler : IRequestHandler<CheckDayaLoanSt
|
||||
|
||||
_logger.LogInformation(
|
||||
"Daya loan processed for new contract - User {UserId}, ContractNumber: {ContractNumber}, Amount: {Amount}",
|
||||
user.Id, dayaResult.ContractNumber, DAYA_LOAN_AMOUNT);
|
||||
user.Id, dayaResult.ContractNumber, SystemConstants.DayaLoanAmount);
|
||||
}
|
||||
|
||||
var newContract = new DayaLoanContract
|
||||
@@ -187,13 +183,13 @@ public class CheckDayaLoanStatusCommandHandler : IRequestHandler<CheckDayaLoanSt
|
||||
var previousBalance = wallet.Balance;
|
||||
var previousDiscountBalance = wallet.DiscountBalance;
|
||||
|
||||
wallet.Balance += DAYA_LOAN_AMOUNT;
|
||||
wallet.DiscountBalance += DAYA_LOAN_AMOUNT;
|
||||
wallet.Balance += SystemConstants.DayaLoanAmount;
|
||||
wallet.DiscountBalance += SystemConstants.DayaLoanAmount;
|
||||
|
||||
// 2. ثبت تراکنش - RefId = شماره قرارداد، Status = 0 (Success)، Type = 2 (DepositExternal1)
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Amount = DAYA_LOAN_AMOUNT,
|
||||
Amount = SystemConstants.DayaLoanAmount,
|
||||
Description = $"شارژ کیف پول از وام دایا - قرارداد {contractNumber}",
|
||||
PaymentStatus = PaymentStatus.Success, // 0
|
||||
PaymentDate = DateTime.Now,
|
||||
@@ -209,11 +205,11 @@ public class CheckDayaLoanStatusCommandHandler : IRequestHandler<CheckDayaLoanSt
|
||||
{
|
||||
WalletId = wallet.Id,
|
||||
CurrentBalance = wallet.Balance,
|
||||
ChangeValue = DAYA_LOAN_AMOUNT,
|
||||
ChangeValue = SystemConstants.DayaLoanAmount,
|
||||
CurrentNetworkBalance = wallet.NetworkBalance,
|
||||
ChangeNerworkValue = 0,
|
||||
CurrentDiscountBalance = wallet.DiscountBalance,
|
||||
ChangeDiscountValue = DAYA_LOAN_AMOUNT,
|
||||
ChangeDiscountValue = SystemConstants.DayaLoanAmount,
|
||||
IsIncrease = true,
|
||||
RefrenceId = transaction.Id
|
||||
};
|
||||
|
||||
+7
-6
@@ -1,4 +1,5 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
|
||||
namespace CMSMicroservice.Application.DayaLoanCQ.Commands.ProcessDayaLoanApproval;
|
||||
|
||||
@@ -18,17 +19,17 @@ public record ProcessDayaLoanApprovalCommand : IRequest<ProcessDayaLoanApprovalR
|
||||
public string ContractNumber { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کیف پول عادی (56 میلیون)
|
||||
/// مبلغ کیف پول عادی
|
||||
/// </summary>
|
||||
public long WalletAmount { get; init; } = 56_000_000;
|
||||
public long WalletAmount { get; init; } = SystemConstants.DayaLoanAmount;
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کیف پول قفل شده (56 میلیون)
|
||||
/// مبلغ کیف پول قفل شده
|
||||
/// </summary>
|
||||
public long LockedWalletAmount { get; init; } = 56_000_000;
|
||||
public long LockedWalletAmount { get; init; } = SystemConstants.DayaLoanAmount;
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کیف پول تخفیف (56 میلیون)
|
||||
/// مبلغ کیف پول تخفیف (دو برابر)
|
||||
/// </summary>
|
||||
public long DiscountWalletAmount { get; init; } = 56_000_000;
|
||||
public long DiscountWalletAmount { get; init; } = SystemConstants.DayaLoanAmount * 2;
|
||||
}
|
||||
|
||||
+3
-18
@@ -76,22 +76,7 @@ public class ProcessDayaLoanApprovalCommandHandler : IRequestHandler<ProcessDaya
|
||||
};
|
||||
await _context.UserWalletChangeLogs.AddAsync(mainLog, cancellationToken);
|
||||
|
||||
// شارژ کیف پول شبکه/کارمزد (56 میلیون) - نامگذاری قدیم: کیف پول قفل شده
|
||||
var balanceBeforeLocked = wallet.NetworkBalance;
|
||||
wallet.NetworkBalance += request.LockedWalletAmount;
|
||||
|
||||
// لاگ کیف پول شبکه
|
||||
var networkLog = new UserWalletChangeLog
|
||||
{
|
||||
WalletId = wallet.Id,
|
||||
CurrentBalance = wallet.Balance,
|
||||
ChangeValue = 0,
|
||||
CurrentNetworkBalance = wallet.NetworkBalance,
|
||||
ChangeNerworkValue = request.LockedWalletAmount,
|
||||
IsIncrease = true,
|
||||
RefrenceId = transaction.Id
|
||||
};
|
||||
await _context.UserWalletChangeLogs.AddAsync(networkLog, cancellationToken);
|
||||
|
||||
|
||||
// شارژ کیف پول تخفیف (56 میلیون)
|
||||
var balanceBeforeDiscount = wallet.DiscountBalance;
|
||||
@@ -119,9 +104,9 @@ public class ProcessDayaLoanApprovalCommandHandler : IRequestHandler<ProcessDaya
|
||||
// تنظیم نحوه خرید پکیج به DayaLoan
|
||||
user.PackagePurchaseMethod = PackagePurchaseMethod.DayaLoan;
|
||||
|
||||
// ثبت سفارش پکیج (فعلاً پکیج طلایی)
|
||||
// ثبت سفارش پکیج (فعلاً پکیج پایه)
|
||||
var goldenPackage = await _context.Packages
|
||||
.FirstOrDefaultAsync(p => p.Title.Contains("طلایی") || p.Title.Contains("Golden"), cancellationToken);
|
||||
.FirstOrDefaultAsync(p => p.Id==4, cancellationToken);
|
||||
|
||||
if (goldenPackage != null)
|
||||
{
|
||||
|
||||
+5
-9
@@ -2,6 +2,7 @@ using CMSMicroservice.Application.Common.Exceptions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -19,11 +20,6 @@ public class InitiateBasePackagePaymentCommandHandler : IRequestHandler<Initiate
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ILogger<InitiateBasePackagePaymentCommandHandler> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ پکیج پایه (56 میلیون تومان)
|
||||
/// </summary>
|
||||
private const long BasePackageAmount = 56_000_000;
|
||||
|
||||
/// <summary>
|
||||
/// شناسه پکیج پایه در دیتابیس
|
||||
/// </summary>
|
||||
@@ -97,7 +93,7 @@ public class InitiateBasePackagePaymentCommandHandler : IRequestHandler<Initiate
|
||||
Message = "سفارش قبلی در انتظار پرداخت یافت شد.",
|
||||
OrderId = pendingOrder.Id,
|
||||
TransactionId = existingTransaction?.Id ?? 0,
|
||||
Amount = BasePackageAmount
|
||||
Amount = SystemConstants.BasePackageAmount
|
||||
};
|
||||
}
|
||||
|
||||
@@ -116,7 +112,7 @@ public class InitiateBasePackagePaymentCommandHandler : IRequestHandler<Initiate
|
||||
// 5. ایجاد Transaction با وضعیت Pending
|
||||
var transaction = new Transaction
|
||||
{
|
||||
Amount = BasePackageAmount,
|
||||
Amount = SystemConstants.BasePackageAmount,
|
||||
Description = $"خرید پکیج پایه ۵۶ میلیونی - کاربر #{user.Id}",
|
||||
PaymentStatus = PaymentStatus.Pending,
|
||||
Type = TransactionType.DepositIpg
|
||||
@@ -135,7 +131,7 @@ public class InitiateBasePackagePaymentCommandHandler : IRequestHandler<Initiate
|
||||
{
|
||||
UserId = user.Id,
|
||||
PackageId = BasePackageId,
|
||||
Amount = BasePackageAmount,
|
||||
Amount = SystemConstants.BasePackageAmount,
|
||||
PaymentStatus = PaymentStatus.Pending,
|
||||
DeliveryStatus = DeliveryStatus.None,
|
||||
UserAddressId = defaultAddress.Id,
|
||||
@@ -158,7 +154,7 @@ public class InitiateBasePackagePaymentCommandHandler : IRequestHandler<Initiate
|
||||
Message = "تراکنش و سفارش با موفقیت ثبت شد.",
|
||||
OrderId = order.Id,
|
||||
TransactionId = transaction.Id,
|
||||
Amount = BasePackageAmount
|
||||
Amount = SystemConstants.BasePackageAmount
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
+5
-9
@@ -2,6 +2,7 @@ using CMSMicroservice.Application.Common.Exceptions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -24,11 +25,6 @@ public class VerifyBasePackagePaymentCommandHandler : IRequestHandler<VerifyBase
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ILogger<VerifyBasePackagePaymentCommandHandler> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ پکیج پایه (56 میلیون تومان)
|
||||
/// </summary>
|
||||
private const long BasePackageAmount = 56_000_000;
|
||||
|
||||
public VerifyBasePackagePaymentCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
@@ -136,8 +132,8 @@ public class VerifyBasePackagePaymentCommandHandler : IRequestHandler<VerifyBase
|
||||
var oldBalance = userWallet.Balance;
|
||||
var oldDiscountBalance = userWallet.DiscountBalance;
|
||||
|
||||
userWallet.Balance += BasePackageAmount;
|
||||
userWallet.DiscountBalance += BasePackageAmount;
|
||||
userWallet.Balance += SystemConstants.BasePackageAmount;
|
||||
userWallet.DiscountBalance += SystemConstants.BasePackageAmount;
|
||||
|
||||
_logger.LogInformation(
|
||||
"Charging wallet for user {UserId}. Balance: {OldBalance} -> {NewBalance}, DiscountBalance: {OldDiscount} -> {NewDiscount}",
|
||||
@@ -157,11 +153,11 @@ public class VerifyBasePackagePaymentCommandHandler : IRequestHandler<VerifyBase
|
||||
{
|
||||
WalletId = userWallet.Id,
|
||||
CurrentBalance = userWallet.Balance,
|
||||
ChangeValue = BasePackageAmount,
|
||||
ChangeValue = SystemConstants.BasePackageAmount,
|
||||
CurrentNetworkBalance = userWallet.NetworkBalance,
|
||||
ChangeNerworkValue = 0,
|
||||
CurrentDiscountBalance = userWallet.DiscountBalance,
|
||||
ChangeDiscountValue = BasePackageAmount,
|
||||
ChangeDiscountValue = SystemConstants.BasePackageAmount,
|
||||
IsIncrease = true,
|
||||
RefrenceId = transaction.Id
|
||||
};
|
||||
|
||||
+10
-24
@@ -1,3 +1,4 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using CMSMicroservice.Domain.Events;
|
||||
using CMSMicroservice.Domain.Entities.Order;
|
||||
@@ -63,16 +64,11 @@ public class
|
||||
}
|
||||
|
||||
long finalAmount = 0;
|
||||
var vatIsEnable =
|
||||
_context.SystemConfigurations
|
||||
.FirstOrDefault(f => f.Scope == ConfigurationScope.VAT && f.Key == "IsEnabled")?.Value ??
|
||||
"0";
|
||||
if (vatIsEnable=="1")
|
||||
|
||||
// استفاده از SystemConstants برای VAT
|
||||
if (SystemConstants.ShopVATEnabled)
|
||||
{
|
||||
_vatRate = float.Parse(
|
||||
_context.SystemConfigurations
|
||||
.FirstOrDefault(f => f.Scope == ConfigurationScope.VAT && f.Key == "Shop.VAT")?.Value ??
|
||||
throw new InvalidOperationException());
|
||||
_vatRate = (float)SystemConstants.ShopVAT;
|
||||
finalAmount = AddVAT(user.UserCarts.Sum(s => s.Count * s.Product.Price));
|
||||
_logger.LogInformation(
|
||||
"Calculating final amount with VAT. Base Amount: {BaseAmount}, VAT Rate: {VATRate}, Final Amount: {FinalAmount}",
|
||||
@@ -147,7 +143,7 @@ public class
|
||||
{
|
||||
ProductId = s.ProductId,
|
||||
Count = s.Count,
|
||||
UnitPrice =vatIsEnable=="1" ?AddVAT(s.Product.Price): s.Product.Price,
|
||||
UnitPrice = SystemConstants.ShopVATEnabled ? AddVAT(s.Product.Price) : s.Product.Price,
|
||||
OrderId = newOrder.Id
|
||||
});
|
||||
await _context.FactorDetails.AddRangeAsync(factorDetailsList, cancellationToken);
|
||||
@@ -183,25 +179,15 @@ public class
|
||||
{
|
||||
try
|
||||
{
|
||||
// بررسی فعال بودن VAT
|
||||
var vatEnabledConfig = await _context.SystemConfigurations
|
||||
.FirstOrDefaultAsync(x => x.Scope == ConfigurationScope.VAT && x.Key == "IsEnabled", cancellationToken);
|
||||
|
||||
if (vatEnabledConfig == null || !bool.TryParse(vatEnabledConfig.Value, out var isEnabled) || !isEnabled)
|
||||
// بررسی فعال بودن VAT از SystemConstants
|
||||
if (!SystemConstants.ShopVATEnabled)
|
||||
{
|
||||
_logger.LogInformation("VAT is disabled. Skipping VAT calculation for order {OrderId}", orderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// دریافت نرخ VAT
|
||||
var vatRateConfig = await _context.SystemConfigurations
|
||||
.FirstOrDefaultAsync(x => x.Scope == ConfigurationScope.VAT && x.Key == "Shop.VAT", cancellationToken);
|
||||
|
||||
if (vatRateConfig == null || !decimal.TryParse(vatRateConfig.Value, out var vatRate))
|
||||
{
|
||||
_logger.LogWarning("VAT Rate configuration not found or invalid. Using default 0.09");
|
||||
vatRate = 0.09m;
|
||||
}
|
||||
// دریافت نرخ VAT از SystemConstants
|
||||
var vatRate = SystemConstants.ShopVAT;
|
||||
|
||||
// محاسبه مالیات
|
||||
var vatAmount = (long)(orderAmount * vatRate);
|
||||
|
||||
Reference in New Issue
Block a user