Phase 4: Complete Package CRUD DTOs + Legacy Fixes

- CreateNewPackageCommand: Add 12 new Package fields (SortOrder, IsActive, IsBasePackage,
  SupportsDayaPurchase, SupportsDirectPurchase, ActivationFee, DiscountMultiplier,
  MagicWalletMultiplier, MaxBalancesPerLeg, MaxNetworkLevel, MagicWalletMaxDeposit,
  MagicWalletMaxCredit) with sensible defaults
- GetPackageResponseDto: Add 12 new fields (Mapster auto-maps via ProjectToType)
- GetAllPackageByFilterResponseModel: Add 12 new fields (Mapster auto-maps)
- PurchaseGoldenPackage: Replace fragile Title string match ('طلایی'/'golden')
  with proper IsDeleted/IsActive/SupportsDirectPurchase validation
- VerifyPackagePurchase: Replace hardcoded order.Amount*2 with
  package.DiscountMultiplier from DB (fallback 2.0 for null Package)
This commit is contained in:
masoodafar-web
2026-02-26 00:24:35 +03:30
parent ccb938e9ba
commit 0002a5a6f2
5 changed files with 56 additions and 12 deletions
@@ -9,5 +9,17 @@ public record CreateNewPackageCommand : IRequest<CreateNewPackageResponseDto>
public string ImagePath { get; init; }
//قیمت
public long Price { get; init; }
// فیلدهای جدید پکیج
public int SortOrder { get; init; }
public bool IsActive { get; init; } = true;
public bool IsBasePackage { get; init; }
public bool SupportsDayaPurchase { get; init; } = true;
public bool SupportsDirectPurchase { get; init; } = true;
public long ActivationFee { get; init; }
public double DiscountMultiplier { get; init; } = 2.0;
public double MagicWalletMultiplier { get; init; } = 2.5;
public int MaxBalancesPerLeg { get; init; } = 300;
public int MaxNetworkLevel { get; init; } = 15;
public long MagicWalletMaxDeposit { get; init; } = 1_000_000_000;
public long MagicWalletMaxCredit { get; init; } = 2_500_000_000;
}
@@ -65,16 +65,21 @@ public class PurchaseGoldenPackageCommandHandler : IRequestHandler<PurchaseGolde
throw new NotFoundException(nameof(Package), request.PackageId);
}
// اطمینان از اینکه این همان پکیج طلایی است
if (!package.Title.Contains("طلایی", StringComparison.OrdinalIgnoreCase) &&
!package.Title.Contains("golden", StringComparison.OrdinalIgnoreCase))
// اطمینان از فعال بودن و قابل خرید بودن پکیج
if (package.IsDeleted || !package.IsActive)
{
_logger.LogWarning(
"PackageId {PackageId} is not a golden package. Title: {Title}",
"PackageId {PackageId} is not available. IsDeleted: {IsDeleted}, IsActive: {IsActive}",
request.PackageId,
package.Title);
package.IsDeleted,
package.IsActive);
throw new ValidationException("فقط پکیج طلایی قابل خرید است.");
throw new ValidationException("این پکیج در حال حاضر قابل خرید نیست.");
}
if (!package.SupportsDirectPurchase)
{
throw new ValidationException("این پکیج فقط از طریق وام دایا قابل خرید است.");
}
// 4. پیدا کردن آدرس پیش‌فرض کاربر (الزامی برای UserOrder)
@@ -99,9 +99,11 @@ public class VerifyPackagePurchaseCommandHandler
wallet.Balance
);
// شارژ DiscountBalance (موجودی تخفیف) — دو برابر مبلغ سفارش
// شارژ DiscountBalance (موجودی تخفیف) — ضریب تخفیف از پکیج
var oldDiscountBalance = wallet.DiscountBalance;
wallet.DiscountBalance += order.Amount * 2;
var discountMultiplier = order.Package?.DiscountMultiplier ?? 2.0m;
var discountAmount = (long)(order.Amount * discountMultiplier);
wallet.DiscountBalance += discountAmount;
_logger.LogInformation(
"Charging DiscountBalance for UserId {UserId}: {OldBalance} -> {NewBalance}",
@@ -132,7 +134,7 @@ public class VerifyPackagePurchaseCommandHandler
ChangeValue = order.Amount,
CurrentNetworkBalance = wallet.NetworkBalance,
ChangeNerworkValue = 0,
CurrentDiscountBalance = wallet.DiscountBalance - (order.Amount * 2), // قبل از شارژ DiscountBalance
CurrentDiscountBalance = wallet.DiscountBalance - discountAmount, // قبل از شارژ DiscountBalance
ChangeDiscountValue = 0,
IsIncrease = true,
RefrenceId = transaction.Id
@@ -148,7 +150,7 @@ public class VerifyPackagePurchaseCommandHandler
CurrentNetworkBalance = wallet.NetworkBalance,
ChangeNerworkValue = 0,
CurrentDiscountBalance = wallet.DiscountBalance,
ChangeDiscountValue = order.Amount * 2,
ChangeDiscountValue = discountAmount,
IsIncrease = true,
RefrenceId = transaction.Id
};
@@ -18,4 +18,17 @@ public class GetAllPackageByFilterResponseDto
public string ImagePath { get; set; }
//قیمت
public long Price { get; set; }
// فیلدهای جدید پکیج
public int SortOrder { get; set; }
public bool IsActive { get; set; }
public bool IsBasePackage { get; set; }
public bool SupportsDayaPurchase { get; set; }
public bool SupportsDirectPurchase { get; set; }
public long ActivationFee { get; set; }
public decimal DiscountMultiplier { get; set; }
public decimal MagicWalletMultiplier { get; set; }
public int MaxBalancesPerLeg { get; set; }
public int MaxNetworkLevel { get; set; }
public long MagicWalletMaxDeposit { get; set; }
public long MagicWalletMaxCredit { get; set; }
}
@@ -11,5 +11,17 @@ public class GetPackageResponseDto
public string ImagePath { get; set; }
//قیمت
public long Price { get; set; }
// فیلدهای جدید پکیج
public int SortOrder { get; set; }
public bool IsActive { get; set; }
public bool IsBasePackage { get; set; }
public bool SupportsDayaPurchase { get; set; }
public bool SupportsDirectPurchase { get; set; }
public long ActivationFee { get; set; }
public decimal DiscountMultiplier { get; set; }
public decimal MagicWalletMultiplier { get; set; }
public int MaxBalancesPerLeg { get; set; }
public int MaxNetworkLevel { get; set; }
public long MagicWalletMaxDeposit { get; set; }
public long MagicWalletMaxCredit { get; set; }
}