feat: Implement customer profile and referral queries
- Add GetCustomerProfileResponseDto for retrieving customer profile information. - Create GetCustomerReferralsQuery and GetCustomerReferralsQueryHandler to fetch customer referrals with pagination and filtering options. - Introduce GetCustomerReferralsResponseDto to structure the response for customer referrals. - Implement GetCustomerSettingsQuery and GetCustomerSettingsQueryHandler to retrieve user settings. - Add GetCustomerOrder and GetCustomerOrderQueryHandler for fetching specific customer orders. - Create GetCustomerOrderHistoryQuery and GetCustomerOrderHistoryQueryHandler to retrieve order history with filtering options. - Implement GetCustomerOrdersQuery and GetCustomerOrdersQueryHandler for fetching multiple customer orders with filters. - Add GetCustomerWalletChangeLogQuery and GetCustomerWalletChangeLogQueryHandler for retrieving wallet change logs. - Implement GetCustomerWithdrawalSettingsQuery and GetCustomerWithdrawalSettingsQueryHandler for fetching withdrawal settings. - Create GetCustomerWithdrawalsQuery and GetCustomerWithdrawalsQueryHandler to retrieve customer withdrawal requests.
This commit is contained in:
+1
-1
@@ -66,7 +66,7 @@ public class CreateNewOtpTokenCommandHandler : IRequestHandler<CreateNewOtpToken
|
||||
|
||||
return new CreateNewOtpTokenResponseDto
|
||||
{
|
||||
IsSuccess = true,
|
||||
Success = true,
|
||||
Message = "کد تایید با موفقیت ارسال شد",
|
||||
ExpiresAt = otpToken.ExpiresAt
|
||||
};
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ namespace CMSMicroservice.Application.UserCQ.Commands.CreateNewOtpToken;
|
||||
public class CreateNewOtpTokenResponseDto
|
||||
{
|
||||
//موفق؟
|
||||
public bool IsSuccess { get; set; }
|
||||
public bool Success { get; set; }
|
||||
//پیام
|
||||
public string Message { get; set; }
|
||||
//تلاش باقی مانده
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@ public class VerifyOtpTokenCommandHandler : IRequestHandler<VerifyOtpTokenComman
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (otpToken == null || !otpToken.IsValid(request.Code))
|
||||
return new VerifyOtpTokenResponseDto { IsSuccess = false, Message = "کد تایید نامعتبر است" };
|
||||
return new VerifyOtpTokenResponseDto { Success = false, Message = "کد تایید نامعتبر است" };
|
||||
|
||||
var user = await _context.Users
|
||||
.Include(u => u.UserContracts)
|
||||
@@ -33,7 +33,7 @@ public class VerifyOtpTokenCommandHandler : IRequestHandler<VerifyOtpTokenComman
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (user == null)
|
||||
return new VerifyOtpTokenResponseDto { IsSuccess = false, Message = "کاربر یافت نشد" };
|
||||
return new VerifyOtpTokenResponseDto { Success = false, Message = "کاربر یافت نشد" };
|
||||
|
||||
// Mark OTP as used
|
||||
otpToken.IsUsed = true;
|
||||
@@ -44,7 +44,7 @@ public class VerifyOtpTokenCommandHandler : IRequestHandler<VerifyOtpTokenComman
|
||||
|
||||
return new VerifyOtpTokenResponseDto
|
||||
{
|
||||
IsSuccess = true,
|
||||
Success = true,
|
||||
Message = "کد تایید با موفقیت تایید شد",
|
||||
Token = token
|
||||
};
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ namespace CMSMicroservice.Application.UserCQ.Commands.VerifyOtpToken;
|
||||
public class VerifyOtpTokenResponseDto
|
||||
{
|
||||
//موفق؟
|
||||
public bool IsSuccess { get; set; }
|
||||
public bool Success { get; set; }
|
||||
//پیام
|
||||
public string Message { get; set; }
|
||||
//توکن
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
namespace CMSMicroservice.Application.UserCQ.Queries.GetCustomerProfile;
|
||||
|
||||
public class GetCustomerProfileQuery : IRequest<GetCustomerProfileResponseDto>
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
|
||||
namespace CMSMicroservice.Application.UserCQ.Queries.GetCustomerProfile;
|
||||
|
||||
public class GetCustomerProfileQueryHandler : IRequestHandler<GetCustomerProfileQuery, GetCustomerProfileResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public GetCustomerProfileQueryHandler(IApplicationDbContext context, ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<GetCustomerProfileResponseDto> Handle(GetCustomerProfileQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
// Get userId from ICurrentUserService if not provided
|
||||
var userId = request.UserId == 0
|
||||
? (long.TryParse(_currentUser.UserId, out var id) ? id : 0)
|
||||
: request.UserId;
|
||||
|
||||
if (userId == 0)
|
||||
throw new UnauthorizedAccessException("User ID not found in JWT token");
|
||||
|
||||
var user = await _context.Users
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Id == userId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (user == null)
|
||||
throw new NotFoundException(nameof(User), userId);
|
||||
|
||||
var fullName = $"{user.FirstName} {user.LastName}".Trim();
|
||||
var profileCompletionPercentage = CalculateProfileCompletion(user);
|
||||
|
||||
return new GetCustomerProfileResponseDto
|
||||
{
|
||||
Id = user.Id,
|
||||
FirstName = user.FirstName,
|
||||
LastName = user.LastName,
|
||||
Mobile = user.Mobile,
|
||||
Email = user.Email,
|
||||
NationalCode = user.NationalCode,
|
||||
AvatarPath = user.AvatarPath,
|
||||
ParentId = user.NetworkParentId,
|
||||
ReferralCode = user.ReferralCode,
|
||||
IsMobileVerified = user.IsMobileVerified,
|
||||
MobileVerifiedAt = user.MobileVerifiedAt,
|
||||
EmailNotifications = user.EmailNotifications,
|
||||
SmsNotifications = user.SmsNotifications,
|
||||
PushNotifications = user.PushNotifications,
|
||||
BirthDate = user.BirthDate,
|
||||
FullName = fullName,
|
||||
ProfileCompletionPercentage = profileCompletionPercentage
|
||||
};
|
||||
}
|
||||
|
||||
private int CalculateProfileCompletion(Domain.Entities.User user)
|
||||
{
|
||||
var totalFields = 10;
|
||||
var completedFields = 0;
|
||||
|
||||
if (!string.IsNullOrEmpty(user.FirstName)) completedFields++;
|
||||
if (!string.IsNullOrEmpty(user.LastName)) completedFields++;
|
||||
if (!string.IsNullOrEmpty(user.Mobile)) completedFields++;
|
||||
if (!string.IsNullOrEmpty(user.Email)) completedFields++;
|
||||
if (!string.IsNullOrEmpty(user.NationalCode)) completedFields++;
|
||||
if (!string.IsNullOrEmpty(user.AvatarPath)) completedFields++;
|
||||
if (user.BirthDate.HasValue) completedFields++;
|
||||
if (user.IsMobileVerified) completedFields++;
|
||||
if (user.NetworkParentId.HasValue) completedFields++;
|
||||
if (!string.IsNullOrEmpty(user.ReferralCode)) completedFields++;
|
||||
|
||||
return (int)((double)completedFields / totalFields * 100);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
namespace CMSMicroservice.Application.UserCQ.Queries.GetCustomerProfile;
|
||||
|
||||
public class GetCustomerProfileResponseDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
public string Mobile { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? NationalCode { get; set; }
|
||||
public string? AvatarPath { get; set; }
|
||||
public long? ParentId { get; set; }
|
||||
public string ReferralCode { get; set; }
|
||||
public bool IsMobileVerified { get; set; }
|
||||
public DateTime? MobileVerifiedAt { get; set; }
|
||||
public bool EmailNotifications { get; set; }
|
||||
public bool SmsNotifications { get; set; }
|
||||
public bool PushNotifications { get; set; }
|
||||
public DateTime? BirthDate { get; set; }
|
||||
public string FullName { get; set; }
|
||||
public int ProfileCompletionPercentage { get; set; }
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
|
||||
namespace CMSMicroservice.Application.UserCQ.Queries.GetCustomerReferrals;
|
||||
|
||||
public class GetCustomerReferralsQuery : IRequest<GetCustomerReferralsResponseDto>
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
public PaginationState? PaginationState { get; set; }
|
||||
public string? StatusFilter { get; set; } // ACTIVE, INACTIVE, ALL
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
|
||||
namespace CMSMicroservice.Application.UserCQ.Queries.GetCustomerReferrals;
|
||||
|
||||
public class GetCustomerReferralsQueryHandler : IRequestHandler<GetCustomerReferralsQuery, GetCustomerReferralsResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public GetCustomerReferralsQueryHandler(IApplicationDbContext context, ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<GetCustomerReferralsResponseDto> Handle(GetCustomerReferralsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
// Get userId from ICurrentUserService if not provided
|
||||
var userId = request.UserId == 0
|
||||
? (long.TryParse(_currentUser.UserId, out var id) ? id : 0)
|
||||
: request.UserId;
|
||||
|
||||
if (userId == 0)
|
||||
throw new UnauthorizedAccessException("User ID not found in JWT token");
|
||||
|
||||
// Get referrals (children in network)
|
||||
var query = _context.Users
|
||||
.AsNoTracking()
|
||||
.Where(x => x.NetworkParentId == userId);
|
||||
|
||||
// Apply status filter
|
||||
if (!string.IsNullOrEmpty(request.StatusFilter))
|
||||
{
|
||||
if (request.StatusFilter.ToUpper() == "ACTIVE")
|
||||
query = query.Where(x => x.IsMobileVerified);
|
||||
else if (request.StatusFilter.ToUpper() == "INACTIVE")
|
||||
query = query.Where(x => !x.IsMobileVerified);
|
||||
// ALL - no additional filter
|
||||
}
|
||||
|
||||
query = query.OrderByDescending(x => x.Created);
|
||||
|
||||
// Calculate stats
|
||||
var allReferrals = await _context.Users
|
||||
.AsNoTracking()
|
||||
.Where(x => x.NetworkParentId == userId)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var totalReferrals = allReferrals.Count;
|
||||
var activeReferrals = allReferrals.Count(x => x.IsMobileVerified);
|
||||
|
||||
// Calculate commission for current user
|
||||
var userWallet = await _context.UserWallets
|
||||
.AsNoTracking()
|
||||
.Where(x => x.UserId == userId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
var totalCommission = userWallet?.NetworkBalance ?? 0;
|
||||
|
||||
// Calculate this month's commission from wallet changelog
|
||||
var startOfMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
|
||||
var thisMonthCommission = await _context.UserWalletChangeLogs
|
||||
.AsNoTracking()
|
||||
.Include(x => x.Wallet)
|
||||
.Where(x => x.Wallet.UserId == userId && x.Created >= startOfMonth)
|
||||
.SumAsync(x => x.ChangeNerworkValue, cancellationToken);
|
||||
|
||||
// Pagination
|
||||
var totalCount = await query.CountAsync(cancellationToken);
|
||||
|
||||
var paginationState = request.PaginationState ?? new PaginationState { PageNumber = 1, PageSize = 10 };
|
||||
var referrals = await query
|
||||
.Skip((paginationState.PageNumber - 1) * paginationState.PageSize)
|
||||
.Take(paginationState.PageSize)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var metaData = new MetaData
|
||||
{
|
||||
TotalCount = totalCount,
|
||||
CurrentPage = paginationState.PageNumber,
|
||||
PageSize = paginationState.PageSize,
|
||||
TotalPage = (int)Math.Ceiling((double)totalCount / paginationState.PageSize),
|
||||
HasPrevious = paginationState.PageNumber > 1,
|
||||
HasNext = paginationState.PageNumber < (int)Math.Ceiling((double)totalCount / paginationState.PageSize)
|
||||
};
|
||||
|
||||
var referralModels = referrals.Select(r => new CustomerReferralModel
|
||||
{
|
||||
Id = r.Id,
|
||||
FirstName = r.FirstName,
|
||||
LastName = r.LastName,
|
||||
Mobile = r.Mobile,
|
||||
JoinDate = r.Created,
|
||||
IsActive = r.IsMobileVerified,
|
||||
StatusMessage = r.IsMobileVerified ? "Active" : "Inactive",
|
||||
Level = 1, // Direct referral
|
||||
TotalCommission = 0 // Not tracking per-referral commission
|
||||
}).ToList();
|
||||
|
||||
return new GetCustomerReferralsResponseDto
|
||||
{
|
||||
MetaData = metaData,
|
||||
Referrals = referralModels,
|
||||
Stats = new CustomerReferralStats
|
||||
{
|
||||
TotalReferrals = totalReferrals,
|
||||
ActiveReferrals = activeReferrals,
|
||||
TotalCommissionEarned = totalCommission,
|
||||
ThisMonthCommission = thisMonthCommission
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
|
||||
namespace CMSMicroservice.Application.UserCQ.Queries.GetCustomerReferrals;
|
||||
|
||||
public class GetCustomerReferralsResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public List<CustomerReferralModel> Referrals { get; set; }
|
||||
public CustomerReferralStats Stats { get; set; }
|
||||
}
|
||||
|
||||
public class CustomerReferralModel
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
public string Mobile { get; set; }
|
||||
public DateTime JoinDate { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public string StatusMessage { get; set; }
|
||||
public int Level { get; set; }
|
||||
public long TotalCommission { get; set; }
|
||||
}
|
||||
|
||||
public class CustomerReferralStats
|
||||
{
|
||||
public int TotalReferrals { get; set; }
|
||||
public int ActiveReferrals { get; set; }
|
||||
public long TotalCommissionEarned { get; set; }
|
||||
public long ThisMonthCommission { get; set; }
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
namespace CMSMicroservice.Application.UserCQ.Queries.GetCustomerSettings;
|
||||
|
||||
public class GetCustomerSettingsQuery : IRequest<GetCustomerSettingsResponseDto>
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
|
||||
namespace CMSMicroservice.Application.UserCQ.Queries.GetCustomerSettings;
|
||||
|
||||
public class GetCustomerSettingsQueryHandler : IRequestHandler<GetCustomerSettingsQuery, GetCustomerSettingsResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public GetCustomerSettingsQueryHandler(IApplicationDbContext context, ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<GetCustomerSettingsResponseDto> Handle(GetCustomerSettingsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
// Get userId from ICurrentUserService if not provided
|
||||
var userId = request.UserId == 0
|
||||
? (long.TryParse(_currentUser.UserId, out var id) ? id : 0)
|
||||
: request.UserId;
|
||||
|
||||
if (userId == 0)
|
||||
throw new UnauthorizedAccessException("User ID not found in JWT token");
|
||||
|
||||
var user = await _context.Users
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Id == userId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (user == null)
|
||||
throw new NotFoundException(nameof(User), userId);
|
||||
|
||||
return new GetCustomerSettingsResponseDto
|
||||
{
|
||||
EmailNotifications = user.EmailNotifications,
|
||||
SmsNotifications = user.SmsNotifications,
|
||||
PushNotifications = user.PushNotifications,
|
||||
MarketingNotifications = false, // Not in User entity, default to false
|
||||
PreferredLanguage = "fa", // Default Persian
|
||||
TimeZone = "Asia/Tehran", // Default Iran timezone
|
||||
TwoFactorAuthEnabled = false // Not implemented yet
|
||||
};
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
namespace CMSMicroservice.Application.UserCQ.Queries.GetCustomerSettings;
|
||||
|
||||
public class GetCustomerSettingsResponseDto
|
||||
{
|
||||
public bool EmailNotifications { get; set; }
|
||||
public bool SmsNotifications { get; set; }
|
||||
public bool PushNotifications { get; set; }
|
||||
public bool MarketingNotifications { get; set; }
|
||||
public string PreferredLanguage { get; set; }
|
||||
public string TimeZone { get; set; }
|
||||
public bool TwoFactorAuthEnabled { get; set; }
|
||||
}
|
||||
@@ -2,21 +2,28 @@ namespace CMSMicroservice.Application.UserCQ.Queries.GetUser;
|
||||
public class GetUserQueryHandler : IRequestHandler<GetUserQuery, GetUserResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public GetUserQueryHandler(IApplicationDbContext context)
|
||||
public GetUserQueryHandler(IApplicationDbContext context, ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<GetUserResponseDto> Handle(GetUserQuery request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// If Id is 0 or not provided, get the current authenticated user's ID
|
||||
var userId = request.Id == 0
|
||||
? (long.TryParse(_currentUser.UserId, out var currentUserId) ? currentUserId : 0)
|
||||
: request.Id;
|
||||
|
||||
var response = await _context.Users
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Id == request.Id)
|
||||
.Where(x => x.Id == userId)
|
||||
.ProjectToType<GetUserResponseDto>()
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
return response ?? throw new NotFoundException(nameof(User), request.Id);
|
||||
return response ?? throw new NotFoundException(nameof(User), userId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user