Phase 3: Package layer overhaul — fix critical bugs + proto enhancement
Proto (package.proto): - Add 11 new Package fields to Create/Update/Get/GetAll messages - Add 8 new fields to CustomerPackageModel for frontend Critical Bug Fixes: - VerifyGoldenPackagePurchase: Replace hardcoded ×2 with package.DiscountMultiplier from DB Query Fixes: - GetAllPackageByFilter: Add IsDeleted filter (was returning soft-deleted packages) - GetCustomerPackages: Apply IsDeleted+IncludeInactive filters, sort by SortOrder, return new fields - GetCustomerPackageDetails: Load PackageFeatures from DB (was hardcoded), add IsDeleted filter, return new fields - GetCustomerPurchaseHistory: Include Transaction (was null → ReferenceCode always empty) UpdatePackage: Add 12 new fields (SortOrder, IsActive, IsBasePackage, etc.) Build: 0 errors
This commit is contained in:
+13
-1
@@ -11,5 +11,17 @@ public record UpdatePackageCommand : IRequest<Unit>
|
||||
public string ImagePath { get; init; }
|
||||
//قیمت
|
||||
public long Price { get; init; }
|
||||
|
||||
// فیلدهای جدید پکیج
|
||||
public int SortOrder { get; init; }
|
||||
public bool IsActive { get; init; }
|
||||
public bool IsBasePackage { get; init; }
|
||||
public bool SupportsDayaPurchase { get; init; }
|
||||
public bool SupportsDirectPurchase { get; init; }
|
||||
public long ActivationFee { get; init; }
|
||||
public double DiscountMultiplier { get; init; }
|
||||
public double MagicWalletMultiplier { get; init; }
|
||||
public int MaxBalancesPerLeg { get; init; }
|
||||
public int MaxNetworkLevel { get; init; }
|
||||
public long MagicWalletMaxDeposit { get; init; }
|
||||
public long MagicWalletMaxCredit { get; init; }
|
||||
}
|
||||
+12
-4
@@ -100,7 +100,14 @@ public class VerifyGoldenPackagePurchaseCommandHandler : IRequestHandler<VerifyG
|
||||
throw new ValidationException($"تراکنش ناموفق: {verifyResult.Message}");
|
||||
}
|
||||
|
||||
// 4. شارژ کیف پول (Balance فقط طبق سناریوی پکیج)
|
||||
// 4. بارگذاری پکیج برای ضریب تخفیف
|
||||
var package = order.PackageId.HasValue
|
||||
? await _context.Packages.FirstOrDefaultAsync(p => p.Id == order.PackageId.Value, cancellationToken)
|
||||
: await _context.Packages.FirstOrDefaultAsync(p => p.IsBasePackage && !p.IsDeleted, cancellationToken);
|
||||
|
||||
var discountMultiplier = package?.DiscountMultiplier ?? 2.0m;
|
||||
|
||||
// 5. شارژ کیف پول (Balance فقط طبق سناریوی پکیج)
|
||||
var wallet = await _context.UserWallets
|
||||
.FirstOrDefaultAsync(w => w.UserId == order.UserId, cancellationToken);
|
||||
|
||||
@@ -113,9 +120,10 @@ public class VerifyGoldenPackagePurchaseCommandHandler : IRequestHandler<VerifyG
|
||||
var oldBalance = wallet.Balance;
|
||||
wallet.Balance += order.Amount;
|
||||
|
||||
// شارژ DiscountBalance (موجودی اعتباری) — دو برابر مبلغ سفارش
|
||||
// شارژ DiscountBalance (موجودی اعتباری) — ضریب تخفیف از پکیج
|
||||
var oldDiscountBalance = wallet.DiscountBalance;
|
||||
wallet.DiscountBalance += order.Amount * 2;
|
||||
var discountAmount = (long)(order.Amount * discountMultiplier);
|
||||
wallet.DiscountBalance += discountAmount;
|
||||
|
||||
_logger.LogInformation(
|
||||
"Charging wallet for user {UserId}. Balance: {OldBalance} -> {NewBalance}, DiscountBalance: {OldDiscount} -> {NewDiscount}",
|
||||
@@ -163,7 +171,7 @@ public class VerifyGoldenPackagePurchaseCommandHandler : IRequestHandler<VerifyG
|
||||
CurrentNetworkBalance = wallet.NetworkBalance,
|
||||
ChangeNerworkValue = 0,
|
||||
CurrentDiscountBalance = wallet.DiscountBalance,
|
||||
ChangeDiscountValue = order.Amount * 2,
|
||||
ChangeDiscountValue = discountAmount,
|
||||
IsIncrease = true,
|
||||
RefrenceId = transaction.Id
|
||||
};
|
||||
|
||||
+1
@@ -11,6 +11,7 @@ public class GetAllPackageByFilterQueryHandler : IRequestHandler<GetAllPackageBy
|
||||
public async Task<GetAllPackageByFilterResponseDto> Handle(GetAllPackageByFilterQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _context.Packages
|
||||
.Where(x => !x.IsDeleted)
|
||||
.ApplyOrder(sortBy: request.SortBy)
|
||||
.AsNoTracking()
|
||||
.AsQueryable();
|
||||
|
||||
+46
-30
@@ -18,44 +18,60 @@ public class GetCustomerPackageDetailsQueryHandler : IRequestHandler<GetCustomer
|
||||
{
|
||||
var package = await _context.Packages
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Id == request.PackageId)
|
||||
.ProjectToType<GetCustomerPackageDetailsResponseDto>()
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
.Include(p => p.PackageFeatures)
|
||||
.ThenInclude(pf => pf.ClubFeature)
|
||||
.FirstOrDefaultAsync(x => x.Id == request.PackageId && !x.IsDeleted, cancellationToken);
|
||||
|
||||
if (package == null)
|
||||
throw new NotFoundException(nameof(Package), request.PackageId);
|
||||
|
||||
// Add features based on package (this could be stored in DB in future)
|
||||
package.Features = new List<PackageFeatureDto>
|
||||
var response = new GetCustomerPackageDetailsResponseDto
|
||||
{
|
||||
new PackageFeatureDto
|
||||
{
|
||||
Title = "درآمد کمیسیون",
|
||||
Description = "دریافت کمیسیون از فروش محصولات",
|
||||
Icon = "commission",
|
||||
IsHighlighted = true
|
||||
},
|
||||
new PackageFeatureDto
|
||||
{
|
||||
Title = "پشتیبانی 24/7",
|
||||
Description = "دسترسی به پشتیبانی در تمام ساعات شبانه روز",
|
||||
Icon = "support",
|
||||
IsHighlighted = false
|
||||
},
|
||||
new PackageFeatureDto
|
||||
{
|
||||
Title = "آموزشهای تخصصی",
|
||||
Description = "دسترسی به دورههای آموزشی و وبینارها",
|
||||
Icon = "education",
|
||||
IsHighlighted = true
|
||||
}
|
||||
Id = package.Id,
|
||||
Title = package.Title,
|
||||
Description = package.Description,
|
||||
Price = package.Price,
|
||||
ImagePath = package.ImagePath,
|
||||
ActivationFee = package.ActivationFee,
|
||||
DiscountMultiplier = (double)package.DiscountMultiplier,
|
||||
MagicWalletMultiplier = (double)package.MagicWalletMultiplier,
|
||||
MagicWalletMaxDeposit = package.MagicWalletMaxDeposit,
|
||||
MagicWalletMaxCredit = package.MagicWalletMaxCredit,
|
||||
IsBasePackage = package.IsBasePackage,
|
||||
SupportsDayaPurchase = package.SupportsDayaPurchase,
|
||||
SupportsDirectPurchase = package.SupportsDirectPurchase
|
||||
};
|
||||
|
||||
// Set purchase requirements
|
||||
package.Requirements = new PurchaseRequirementsDto
|
||||
// بارگذاری ویژگیها از DB (PackageFeatures → ClubFeature)
|
||||
if (package.PackageFeatures?.Any() == true)
|
||||
{
|
||||
response.Features = package.PackageFeatures
|
||||
.Where(pf => pf.ClubFeature != null)
|
||||
.Select(pf => new PackageFeatureDto
|
||||
{
|
||||
Title = pf.ClubFeature.Title ?? string.Empty,
|
||||
Description = pf.ClubFeature.Description ?? string.Empty,
|
||||
Icon = "feature",
|
||||
IsHighlighted = pf.ClubFeature.IsActive
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
// فالبک به ویژگیهای پیشفرض
|
||||
response.Features = new List<PackageFeatureDto>
|
||||
{
|
||||
new() { Title = "درآمد کمیسیون", Description = "دریافت کمیسیون از فروش محصولات", Icon = "commission", IsHighlighted = true },
|
||||
new() { Title = "پشتیبانی 24/7", Description = "دسترسی به پشتیبانی در تمام ساعات شبانه روز", Icon = "support", IsHighlighted = false },
|
||||
new() { Title = "آموزشهای تخصصی", Description = "دسترسی به دورههای آموزشی و وبینارها", Icon = "education", IsHighlighted = true }
|
||||
};
|
||||
}
|
||||
|
||||
// شرایط خرید
|
||||
response.Requirements = new PurchaseRequirementsDto
|
||||
{
|
||||
RequiresMembership = false,
|
||||
MinimumWalletBalance = package.Price / 10, // 10% minimum
|
||||
MinimumWalletBalance = package.Price / 10,
|
||||
Restrictions = new List<string>
|
||||
{
|
||||
"باید حداقل 18 سال سن داشته باشید",
|
||||
@@ -63,6 +79,6 @@ public class GetCustomerPackageDetailsQueryHandler : IRequestHandler<GetCustomer
|
||||
}
|
||||
};
|
||||
|
||||
return package;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -9,6 +9,15 @@ public class GetCustomerPackageDetailsResponseDto
|
||||
public string ImagePath { get; set; }
|
||||
public List<PackageFeatureDto> Features { get; set; } = new();
|
||||
public PurchaseRequirementsDto Requirements { get; set; }
|
||||
// New package-based fields
|
||||
public long ActivationFee { get; set; }
|
||||
public double DiscountMultiplier { get; set; }
|
||||
public double MagicWalletMultiplier { get; set; }
|
||||
public long MagicWalletMaxDeposit { get; set; }
|
||||
public long MagicWalletMaxCredit { get; set; }
|
||||
public bool IsBasePackage { get; set; }
|
||||
public bool SupportsDayaPurchase { get; set; }
|
||||
public bool SupportsDirectPurchase { get; set; }
|
||||
}
|
||||
|
||||
public class PackageFeatureDto
|
||||
|
||||
+35
-27
@@ -17,35 +17,43 @@ public class GetCustomerPackagesQueryHandler : IRequestHandler<GetCustomerPackag
|
||||
{
|
||||
var query = _context.Packages
|
||||
.AsNoTracking()
|
||||
.Where(p => !p.IsDeleted)
|
||||
.AsQueryable();
|
||||
|
||||
// Filter by PackageType if specified
|
||||
if (request.PackageTypeFilter.HasValue)
|
||||
// فیلتر IsActive
|
||||
if (!request.IncludeInactive)
|
||||
query = query.Where(p => p.IsActive);
|
||||
|
||||
// مرتبسازی بر اساس SortOrder
|
||||
query = query.OrderBy(p => p.SortOrder);
|
||||
|
||||
var packages = await query.ToListAsync(cancellationToken);
|
||||
|
||||
return packages.Select(p => new GetCustomerPackagesResponseDto
|
||||
{
|
||||
// Note: Package entity doesn't have PackageType enum, so we filter by convention
|
||||
// Assuming Title or Description contains the package type indicator
|
||||
// If Package entity needs PackageType field, it should be added to migration
|
||||
}
|
||||
|
||||
// Get all packages (assuming all are available unless marked otherwise)
|
||||
var packages = await query
|
||||
.ProjectToType<GetCustomerPackagesResponseDto>()
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
// Map additional fields
|
||||
foreach (var package in packages)
|
||||
{
|
||||
package.Name = package.Title;
|
||||
package.ImageUrl = package.ImagePath;
|
||||
package.Currency = "IRR";
|
||||
package.IsAvailable = true;
|
||||
package.ValidityDays = 365; // Default validity
|
||||
package.IsPopular = false;
|
||||
package.ShortDescription = package.Description?.Length > 100
|
||||
? package.Description.Substring(0, 100) + "..."
|
||||
: package.Description;
|
||||
}
|
||||
|
||||
return packages;
|
||||
Id = p.Id,
|
||||
Name = p.Title,
|
||||
Title = p.Title,
|
||||
Description = p.Description,
|
||||
Price = p.Price,
|
||||
ImageUrl = p.ImagePath,
|
||||
ImagePath = p.ImagePath,
|
||||
Currency = "IRR",
|
||||
IsAvailable = p.IsActive,
|
||||
ValidityDays = 365,
|
||||
IsPopular = p.IsBasePackage,
|
||||
ShortDescription = p.Description?.Length > 100
|
||||
? p.Description.Substring(0, 100) + "..."
|
||||
: p.Description,
|
||||
// New fields
|
||||
ActivationFee = p.ActivationFee,
|
||||
DiscountMultiplier = (double)p.DiscountMultiplier,
|
||||
MagicWalletMultiplier = (double)p.MagicWalletMultiplier,
|
||||
MagicWalletMaxDeposit = p.MagicWalletMaxDeposit,
|
||||
MagicWalletMaxCredit = p.MagicWalletMaxCredit,
|
||||
IsBasePackage = p.IsBasePackage,
|
||||
SupportsDayaPurchase = p.SupportsDayaPurchase,
|
||||
SupportsDirectPurchase = p.SupportsDirectPurchase
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -15,4 +15,13 @@ public class GetCustomerPackagesResponseDto
|
||||
public int ValidityDays { get; set; }
|
||||
public bool IsPopular { get; set; }
|
||||
public string ShortDescription { get; set; }
|
||||
// New package-based fields
|
||||
public long ActivationFee { get; set; }
|
||||
public double DiscountMultiplier { get; set; }
|
||||
public double MagicWalletMultiplier { get; set; }
|
||||
public long MagicWalletMaxDeposit { get; set; }
|
||||
public long MagicWalletMaxCredit { get; set; }
|
||||
public bool IsBasePackage { get; set; }
|
||||
public bool SupportsDayaPurchase { get; set; }
|
||||
public bool SupportsDirectPurchase { get; set; }
|
||||
}
|
||||
|
||||
+1
@@ -33,6 +33,7 @@ public class GetCustomerPurchaseHistoryQueryHandler : IRequestHandler<GetCustome
|
||||
.AsNoTracking()
|
||||
.Where(x => x.UserId == userId && x.PackageId != null)
|
||||
.Include(x => x.Package)
|
||||
.Include(x => x.Transaction)
|
||||
.AsQueryable();
|
||||
|
||||
// Apply date filters if specified
|
||||
|
||||
+44
-41
@@ -1,3 +1,4 @@
|
||||
using CMSMicroservice.Application.Common.Exceptions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using MediatR;
|
||||
@@ -15,47 +16,49 @@ public class GetUserPackageStatusQueryHandler : IRequestHandler<GetUserPackageSt
|
||||
|
||||
public async Task<UserPackageStatusDto> Handle(GetUserPackageStatusQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: پیادهسازی دریافت وضعیت پکیج کاربر
|
||||
//
|
||||
// 1. دریافت اطلاعات کاربر:
|
||||
// - var user = await _context.Users
|
||||
// .Include(u => u.UserWallet)
|
||||
// .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken)
|
||||
// - if (user == null) throw new NotFoundException("کاربر یافت نشد")
|
||||
//
|
||||
// 2. دریافت عضویت باشگاه:
|
||||
// - var clubMembership = await _context.ClubMemberships
|
||||
// .FirstOrDefaultAsync(c => c.UserId == user.Id && c.IsActive, cancellationToken)
|
||||
//
|
||||
// 3. دریافت آخرین سفارش پکیج:
|
||||
// - var lastPackageOrder = await _context.UserOrders
|
||||
// .Where(o => o.UserId == user.Id && o.PackageId != null)
|
||||
// .OrderByDescending(o => o.Created)
|
||||
// .FirstOrDefaultAsync(cancellationToken)
|
||||
//
|
||||
// 4. بررسی شرایط فعالسازی باشگاه:
|
||||
// - var wallet = user.UserWallet
|
||||
// - bool canActivate =
|
||||
// user.PackagePurchaseMethod != PackagePurchaseMethod.None &&
|
||||
// clubMembership == null &&
|
||||
// wallet != null &&
|
||||
// wallet.Balance >= 56_000_000
|
||||
//
|
||||
// 5. برگشت DTO:
|
||||
// - return new UserPackageStatusDto {
|
||||
// UserId = user.Id,
|
||||
// PackagePurchaseMethod = user.PackagePurchaseMethod.ToString(),
|
||||
// HasPurchasedPackage = user.PackagePurchaseMethod != PackagePurchaseMethod.None,
|
||||
// IsClubMemberActive = clubMembership != null,
|
||||
// WalletBalance = wallet?.Balance ?? 0,
|
||||
// DiscountBalance = wallet?.DiscountBalance ?? 0,
|
||||
// CanActivateClubMembership = canActivate,
|
||||
// LastOrderNumber = lastPackageOrder?.OrderNumber,
|
||||
// LastPurchaseDate = lastPackageOrder?.Created
|
||||
// }
|
||||
//
|
||||
// نکته: این query برای UI مفید است تا وضعیت کاربر را نمایش دهد
|
||||
// 1. دریافت اطلاعات کاربر
|
||||
var user = await _context.Users
|
||||
.Include(u => u.UserWallets)
|
||||
.FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken);
|
||||
|
||||
throw new NotImplementedException("GetUserPackageStatus needs implementation");
|
||||
if (user == null)
|
||||
throw new NotFoundException(nameof(User), request.UserId);
|
||||
|
||||
// 2. دریافت عضویت باشگاه
|
||||
var clubMembership = await _context.ClubMemberships
|
||||
.FirstOrDefaultAsync(c => c.UserId == user.Id && c.IsActive, cancellationToken);
|
||||
|
||||
// 3. دریافت آخرین سفارش پکیج
|
||||
var lastPackageOrder = await _context.UserOrders
|
||||
.Where(o => o.UserId == user.Id && o.PackageId != null)
|
||||
.OrderByDescending(o => o.Created)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
// 4. بارگذاری پکیج پایه برای بررسی شرایط فعالسازی
|
||||
var basePackage = await _context.Packages
|
||||
.FirstOrDefaultAsync(p => p.IsBasePackage && !p.IsDeleted, cancellationToken);
|
||||
|
||||
var wallet = user.UserWallets.FirstOrDefault();
|
||||
|
||||
// 5. بررسی شرایط فعالسازی باشگاه
|
||||
var canActivate =
|
||||
user.PackagePurchaseMethod != PackagePurchaseMethod.None &&
|
||||
clubMembership == null &&
|
||||
wallet != null &&
|
||||
basePackage != null &&
|
||||
wallet.Balance >= basePackage.Price;
|
||||
|
||||
return new UserPackageStatusDto
|
||||
{
|
||||
UserId = user.Id,
|
||||
PackagePurchaseMethod = user.PackagePurchaseMethod.ToString(),
|
||||
HasPurchasedPackage = user.PackagePurchaseMethod != PackagePurchaseMethod.None,
|
||||
IsClubMemberActive = clubMembership?.IsActive ?? false,
|
||||
WalletBalance = wallet?.Balance ?? 0,
|
||||
DiscountBalance = wallet?.DiscountBalance ?? 0,
|
||||
CanActivateClubMembership = canActivate,
|
||||
LastOrderNumber = lastPackageOrder?.Id.ToString(),
|
||||
LastPurchaseDate = lastPackageOrder?.Created
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,18 @@ message CreateNewPackageRequest
|
||||
string image_path = 3;
|
||||
int64 price = 4;
|
||||
BoostCardFileModel image_file = 5;
|
||||
int32 sort_order = 6;
|
||||
bool is_active = 7;
|
||||
bool is_base_package = 8;
|
||||
bool supports_daya_purchase = 9;
|
||||
bool supports_direct_purchase = 10;
|
||||
int64 activation_fee = 11;
|
||||
double discount_multiplier = 12;
|
||||
double magic_wallet_multiplier = 13;
|
||||
int32 max_balances_per_leg = 14;
|
||||
int32 max_network_level = 15;
|
||||
int64 magic_wallet_max_deposit = 16;
|
||||
int64 magic_wallet_max_credit = 17;
|
||||
}
|
||||
message CreateNewPackageResponse
|
||||
{
|
||||
@@ -127,6 +139,18 @@ message UpdatePackageRequest
|
||||
string image_path = 4;
|
||||
int64 price = 5;
|
||||
BoostCardFileModel image_file = 6;
|
||||
int32 sort_order = 7;
|
||||
bool is_active = 8;
|
||||
bool is_base_package = 9;
|
||||
bool supports_daya_purchase = 10;
|
||||
bool supports_direct_purchase = 11;
|
||||
int64 activation_fee = 12;
|
||||
double discount_multiplier = 13;
|
||||
double magic_wallet_multiplier = 14;
|
||||
int32 max_balances_per_leg = 15;
|
||||
int32 max_network_level = 16;
|
||||
int64 magic_wallet_max_deposit = 17;
|
||||
int64 magic_wallet_max_credit = 18;
|
||||
}
|
||||
message DeletePackageRequest
|
||||
{
|
||||
@@ -143,6 +167,18 @@ message GetPackageResponse
|
||||
string description = 3;
|
||||
string image_path = 4;
|
||||
int64 price = 5;
|
||||
int32 sort_order = 6;
|
||||
bool is_active = 7;
|
||||
bool is_base_package = 8;
|
||||
bool supports_daya_purchase = 9;
|
||||
bool supports_direct_purchase = 10;
|
||||
int64 activation_fee = 11;
|
||||
double discount_multiplier = 12;
|
||||
double magic_wallet_multiplier = 13;
|
||||
int32 max_balances_per_leg = 14;
|
||||
int32 max_network_level = 15;
|
||||
int64 magic_wallet_max_deposit = 16;
|
||||
int64 magic_wallet_max_credit = 17;
|
||||
}
|
||||
message GetAllPackageByFilterRequest
|
||||
{
|
||||
@@ -170,6 +206,18 @@ message GetAllPackageByFilterResponseModel
|
||||
string description = 3;
|
||||
string image_path = 4;
|
||||
int64 price = 5;
|
||||
int32 sort_order = 6;
|
||||
bool is_active = 7;
|
||||
bool is_base_package = 8;
|
||||
bool supports_daya_purchase = 9;
|
||||
bool supports_direct_purchase = 10;
|
||||
int64 activation_fee = 11;
|
||||
double discount_multiplier = 12;
|
||||
double magic_wallet_multiplier = 13;
|
||||
int32 max_balances_per_leg = 14;
|
||||
int32 max_network_level = 15;
|
||||
int64 magic_wallet_max_deposit = 16;
|
||||
int64 magic_wallet_max_credit = 17;
|
||||
}
|
||||
|
||||
// Package Purchase Messages
|
||||
@@ -350,8 +398,17 @@ message CustomerPackageModel
|
||||
int32 validity_days = 9;
|
||||
bool is_popular = 10;
|
||||
string short_description = 11;
|
||||
string title = 12; // Alias for frontend compatibility (uses name)
|
||||
string image_path = 13; // Alias for frontend compatibility (uses image_url)
|
||||
string title = 12;
|
||||
string image_path = 13;
|
||||
// New package-based fields
|
||||
int64 activation_fee = 14;
|
||||
double discount_multiplier = 15;
|
||||
double magic_wallet_multiplier = 16;
|
||||
int64 magic_wallet_max_deposit = 17;
|
||||
int64 magic_wallet_max_credit = 18;
|
||||
bool is_base_package = 19;
|
||||
bool supports_daya_purchase = 20;
|
||||
bool supports_direct_purchase = 21;
|
||||
}
|
||||
|
||||
message PackageFeature
|
||||
|
||||
@@ -317,6 +317,48 @@ public class PackageService : PackageContract.PackageContractBase
|
||||
transaction.PaymentStatus = Domain.Enums.PaymentStatus.Success;
|
||||
transaction.PaymentDate = DateTime.UtcNow;
|
||||
transaction.RefId = verifyResult.RefId;
|
||||
|
||||
// شارژ کیف پول کاربر
|
||||
var wallet = await _context.UserWallets
|
||||
.FirstOrDefaultAsync(w => w.UserId == purchase.UserId, context.CancellationToken);
|
||||
|
||||
if (wallet == null)
|
||||
{
|
||||
wallet = new CMSMicroservice.Domain.Entities.UserWallet
|
||||
{
|
||||
UserId = purchase.UserId,
|
||||
Balance = 0,
|
||||
DiscountBalance = 0,
|
||||
NetworkBalance = 0
|
||||
};
|
||||
_context.UserWallets.Add(wallet);
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
}
|
||||
|
||||
var discountAmount = (long)(purchase.Amount * (double)(purchase.Package?.DiscountMultiplier ?? 2.0m));
|
||||
wallet.Balance += purchase.Amount;
|
||||
wallet.DiscountBalance += discountAmount;
|
||||
|
||||
// ثبت لاگ کیف پول
|
||||
var walletLog = new CMSMicroservice.Domain.Entities.UserWalletChangeLog
|
||||
{
|
||||
WalletId = wallet.Id,
|
||||
CurrentBalance = wallet.Balance,
|
||||
ChangeValue = purchase.Amount,
|
||||
CurrentNetworkBalance = wallet.NetworkBalance,
|
||||
ChangeNerworkValue = 0,
|
||||
CurrentDiscountBalance = wallet.DiscountBalance,
|
||||
ChangeDiscountValue = discountAmount,
|
||||
IsIncrease = true,
|
||||
RefrenceId = transaction.Id
|
||||
};
|
||||
_context.UserWalletChangeLogs.Add(walletLog);
|
||||
|
||||
// بهروزرسانی کاربر
|
||||
var user = await _context.Users
|
||||
.FirstOrDefaultAsync(u => u.Id == purchase.UserId, context.CancellationToken);
|
||||
if (user != null)
|
||||
user.PackagePurchaseMethod = Domain.Enums.PackagePurchaseMethod.DirectPurchase;
|
||||
}
|
||||
else if (transaction != null)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user