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:
+7
@@ -0,0 +1,7 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrder;
|
||||
|
||||
public class GetCustomerOrderQuery : IRequest<GetCustomerOrderResponseDto>
|
||||
{
|
||||
public long OrderId { get; set; }
|
||||
public long UserId { get; set; }
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
using CMSMicroservice.Application.Common.Exceptions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrder;
|
||||
|
||||
public class GetCustomerOrderQueryHandler : IRequestHandler<GetCustomerOrderQuery, GetCustomerOrderResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public GetCustomerOrderQueryHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<GetCustomerOrderResponseDto> Handle(GetCustomerOrderQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
// Resolve UserId from JWT if not specified
|
||||
var userId = request.UserId == 0
|
||||
? (long.TryParse(_currentUser.UserId, out var currentUserId) ? currentUserId : 0)
|
||||
: request.UserId;
|
||||
|
||||
if (userId == 0)
|
||||
throw new UnauthorizedAccessException("User ID not found");
|
||||
|
||||
var order = await _context.UserOrders
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Id == request.OrderId && x.UserId == userId)
|
||||
.Include(x => x.Package)
|
||||
.Include(x => x.Transaction)
|
||||
.Include(x => x.UserAddress)
|
||||
.Include(x => x.User)
|
||||
.Include(x => x.FactorDetails)
|
||||
.ThenInclude(f => f.Product)
|
||||
.Include(x => x.OrderVAT)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
if (order == null)
|
||||
throw new NotFoundException(nameof(UserOrder), request.OrderId);
|
||||
|
||||
return new GetCustomerOrderResponseDto
|
||||
{
|
||||
Id = order.Id,
|
||||
Amount = order.Amount,
|
||||
PackageId = order.PackageId,
|
||||
TransactionId = order.TransactionId,
|
||||
PaymentStatus = order.PaymentStatus,
|
||||
PaymentDate = order.PaymentDate,
|
||||
UserId = order.UserId,
|
||||
UserAddressId = order.UserAddressId,
|
||||
PaymentMethod = order.PaymentMethod,
|
||||
UserAddressText = order.UserAddress?.Address ?? "",
|
||||
DeliveryStatus = order.DeliveryStatus,
|
||||
TrackingCode = order.TrackingCode ?? "",
|
||||
DeliveryDescription = order.DeliveryDescription ?? "",
|
||||
UserFullName = $"{order.User?.FirstName ?? ""} {order.User?.LastName ?? ""}".Trim(),
|
||||
UserNationalCode = order.User?.NationalCode ?? "",
|
||||
VatAmount = order.OrderVAT?.VATAmount ?? 0,
|
||||
VatPercentage = order.OrderVAT != null ? (double)order.OrderVAT.VATRate * 100 : 0,
|
||||
FactorDetails = order.FactorDetails?.Select(fd => new FactorDetailDto
|
||||
{
|
||||
ProductId = fd.ProductId,
|
||||
ProductTitle = fd.Product?.Title ?? "",
|
||||
ProductThumbnailPath = fd.Product?.ThumbnailPath ?? "",
|
||||
UnitPrice = fd.UnitPrice,
|
||||
Count = fd.Count,
|
||||
UnitDiscountPrice = fd.UnitDiscountPrice
|
||||
}).ToList() ?? new List<FactorDetailDto>()
|
||||
};
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrder;
|
||||
|
||||
public class GetCustomerOrderResponseDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long Amount { get; set; }
|
||||
public long? PackageId { get; set; }
|
||||
public long? TransactionId { get; set; }
|
||||
public PaymentStatus PaymentStatus { get; set; }
|
||||
public DateTime? PaymentDate { get; set; }
|
||||
public long UserId { get; set; }
|
||||
public long UserAddressId { get; set; }
|
||||
public PaymentMethod? PaymentMethod { get; set; }
|
||||
public string UserAddressText { get; set; }
|
||||
public List<FactorDetailDto> FactorDetails { get; set; } = new();
|
||||
public DeliveryStatus DeliveryStatus { get; set; }
|
||||
public string TrackingCode { get; set; }
|
||||
public string DeliveryDescription { get; set; }
|
||||
public string UserFullName { get; set; }
|
||||
public string UserNationalCode { get; set; }
|
||||
public long VatAmount { get; set; }
|
||||
public double VatPercentage { get; set; }
|
||||
}
|
||||
|
||||
public class FactorDetailDto
|
||||
{
|
||||
public long ProductId { get; set; }
|
||||
public string ProductTitle { get; set; }
|
||||
public string ProductThumbnailPath { get; set; }
|
||||
public long? UnitPrice { get; set; }
|
||||
public int? Count { get; set; }
|
||||
public long? UnitDiscountPrice { get; set; }
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrderHistory;
|
||||
|
||||
public class GetCustomerOrderHistoryQuery : IRequest<GetCustomerOrderHistoryResponseDto>
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
public PaginationState PaginationState { get; set; }
|
||||
public int? StatusFilter { get; set; }
|
||||
public DateTime? FromDate { get; set; }
|
||||
public DateTime? ToDate { get; set; }
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
using CMSMicroservice.Application.Common.Extensions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrderHistory;
|
||||
|
||||
public class GetCustomerOrderHistoryQueryHandler : IRequestHandler<GetCustomerOrderHistoryQuery, GetCustomerOrderHistoryResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public GetCustomerOrderHistoryQueryHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<GetCustomerOrderHistoryResponseDto> Handle(GetCustomerOrderHistoryQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
// Resolve UserId from JWT if not specified
|
||||
var userId = request.UserId == 0
|
||||
? (long.TryParse(_currentUser.UserId, out var currentUserId) ? currentUserId : 0)
|
||||
: request.UserId;
|
||||
|
||||
if (userId == 0)
|
||||
throw new UnauthorizedAccessException("User ID not found");
|
||||
|
||||
var query = _context.UserOrders
|
||||
.AsNoTracking()
|
||||
.Where(x => x.UserId == userId)
|
||||
.Include(x => x.Package)
|
||||
.Include(x => x.FactorDetails)
|
||||
.AsQueryable();
|
||||
|
||||
// Apply status filter if specified
|
||||
if (request.StatusFilter.HasValue)
|
||||
{
|
||||
// Status filter is based on OrderStatusEnum from Proto
|
||||
// We need to map to DeliveryStatus enum values
|
||||
var deliveryStatus = MapProtoStatusToDeliveryStatus(request.StatusFilter.Value);
|
||||
if (deliveryStatus.HasValue)
|
||||
query = query.Where(x => x.DeliveryStatus == deliveryStatus.Value);
|
||||
}
|
||||
|
||||
// Apply date filters
|
||||
if (request.FromDate.HasValue)
|
||||
query = query.Where(x => x.Created >= request.FromDate.Value);
|
||||
|
||||
if (request.ToDate.HasValue)
|
||||
query = query.Where(x => x.Created <= request.ToDate.Value);
|
||||
|
||||
// Order by most recent first
|
||||
query = query.OrderByDescending(x => x.Created);
|
||||
|
||||
// Get metadata
|
||||
var metaData = await query.GetMetaData(request.PaginationState, cancellationToken);
|
||||
|
||||
// Get paginated results
|
||||
var orders = await query
|
||||
.PaginatedListAsync(request.PaginationState)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var orderModels = orders.Select(order => new CustomerOrderHistoryModel
|
||||
{
|
||||
Id = order.Id,
|
||||
Amount = order.Amount,
|
||||
PackageId = order.PackageId,
|
||||
PackageName = order.Package?.Title ?? "سفارش محصولات",
|
||||
Status = MapDeliveryStatusToProtoStatus(order.DeliveryStatus),
|
||||
StatusMessage = GetStatusMessage(order.DeliveryStatus),
|
||||
OrderDate = order.Created,
|
||||
DeliveryDate = order.PaymentDate?.AddDays(GetEstimatedDeliveryDays(order.DeliveryStatus)),
|
||||
TrackingCode = order.TrackingCode ?? "",
|
||||
ItemsCount = order.FactorDetails?.Count ?? 0,
|
||||
CanCancel = CanCancelOrder(order.DeliveryStatus, order.Created),
|
||||
CanReorder = true // همیشه میتوان دوباره سفارش داد
|
||||
}).ToList();
|
||||
|
||||
return new GetCustomerOrderHistoryResponseDto
|
||||
{
|
||||
MetaData = metaData,
|
||||
Orders = orderModels
|
||||
};
|
||||
}
|
||||
|
||||
private DeliveryStatus? MapProtoStatusToDeliveryStatus(int protoStatus)
|
||||
{
|
||||
// OrderStatusEnum from Proto:
|
||||
// 0=Pending, 1=Confirmed, 2=Processing, 3=Shipped, 4=Delivered, 5=Cancelled, 6=Refunded
|
||||
return protoStatus switch
|
||||
{
|
||||
0 => DeliveryStatus.Pending,
|
||||
1 => DeliveryStatus.Pending,
|
||||
2 => DeliveryStatus.Pending,
|
||||
3 => DeliveryStatus.InTransit,
|
||||
4 => DeliveryStatus.Delivered,
|
||||
5 => DeliveryStatus.Cancelled,
|
||||
6 => DeliveryStatus.Cancelled,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
private int MapDeliveryStatusToProtoStatus(DeliveryStatus status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
DeliveryStatus.None => 0,
|
||||
DeliveryStatus.Pending => 1,
|
||||
DeliveryStatus.InTransit => 3,
|
||||
DeliveryStatus.Delivered => 4,
|
||||
DeliveryStatus.Cancelled => 5,
|
||||
DeliveryStatus.Returned => 6,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
private string GetStatusMessage(DeliveryStatus status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
DeliveryStatus.None => "ثبت نشده",
|
||||
DeliveryStatus.Pending => "در انتظار پردازش",
|
||||
DeliveryStatus.InTransit => "ارسال شده",
|
||||
DeliveryStatus.Delivered => "تحویل داده شد",
|
||||
DeliveryStatus.Cancelled => "لغو شده",
|
||||
DeliveryStatus.Returned => "مرجوع شده",
|
||||
_ => "نامشخص"
|
||||
};
|
||||
}
|
||||
|
||||
private int GetEstimatedDeliveryDays(DeliveryStatus status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
DeliveryStatus.None => 7,
|
||||
DeliveryStatus.Pending => 5,
|
||||
DeliveryStatus.InTransit => 3,
|
||||
DeliveryStatus.Delivered => 0,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
private bool CanCancelOrder(DeliveryStatus status, DateTime orderDate)
|
||||
{
|
||||
// فقط سفارشات Pending یا None که کمتر از 24 ساعت از ثبت آنها گذشته قابل لغو هستند
|
||||
if (status != DeliveryStatus.Pending && status != DeliveryStatus.None)
|
||||
return false;
|
||||
|
||||
var hoursSinceOrder = (DateTime.UtcNow - orderDate).TotalHours;
|
||||
return hoursSinceOrder < 24;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrderHistory;
|
||||
|
||||
public class GetCustomerOrderHistoryResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public List<CustomerOrderHistoryModel> Orders { get; set; } = new();
|
||||
}
|
||||
|
||||
public class CustomerOrderHistoryModel
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long Amount { get; set; }
|
||||
public long? PackageId { get; set; }
|
||||
public string PackageName { get; set; }
|
||||
public int Status { get; set; }
|
||||
public string StatusMessage { get; set; }
|
||||
public DateTime OrderDate { get; set; }
|
||||
public DateTime? DeliveryDate { get; set; }
|
||||
public string TrackingCode { get; set; }
|
||||
public int ItemsCount { get; set; }
|
||||
public bool CanCancel { get; set; }
|
||||
public bool CanReorder { get; set; }
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrders;
|
||||
|
||||
public class GetCustomerOrdersQuery : IRequest<GetCustomerOrdersResponseDto>
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
public PaginationState PaginationState { get; set; }
|
||||
public int? PaymentStatusFilter { get; set; }
|
||||
public int? DeliveryStatusFilter { get; set; }
|
||||
public DateTime? FromDate { get; set; }
|
||||
public DateTime? ToDate { get; set; }
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
using CMSMicroservice.Application.Common.Extensions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using Mapster;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrders;
|
||||
|
||||
public class GetCustomerOrdersQueryHandler : IRequestHandler<GetCustomerOrdersQuery, GetCustomerOrdersResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public GetCustomerOrdersQueryHandler(
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUser)
|
||||
{
|
||||
_context = context;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<GetCustomerOrdersResponseDto> Handle(GetCustomerOrdersQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
// Resolve UserId from JWT if not specified
|
||||
var userId = request.UserId == 0
|
||||
? (long.TryParse(_currentUser.UserId, out var currentUserId) ? currentUserId : 0)
|
||||
: request.UserId;
|
||||
|
||||
if (userId == 0)
|
||||
throw new UnauthorizedAccessException("User ID not found");
|
||||
|
||||
var query = _context.UserOrders
|
||||
.AsNoTracking()
|
||||
.Where(x => x.UserId == userId)
|
||||
.Include(x => x.Package)
|
||||
.Include(x => x.Transaction)
|
||||
.Include(x => x.UserAddress)
|
||||
.Include(x => x.User)
|
||||
.Include(x => x.FactorDetails)
|
||||
.ThenInclude(f => f.Product)
|
||||
.Include(x => x.OrderVAT)
|
||||
.AsQueryable();
|
||||
|
||||
// Apply filters
|
||||
if (request.PaymentStatusFilter.HasValue)
|
||||
query = query.Where(x => (int)x.PaymentStatus == request.PaymentStatusFilter.Value);
|
||||
|
||||
if (request.DeliveryStatusFilter.HasValue)
|
||||
query = query.Where(x => (int)x.DeliveryStatus == request.DeliveryStatusFilter.Value);
|
||||
|
||||
if (request.FromDate.HasValue)
|
||||
query = query.Where(x => x.Created >= request.FromDate.Value);
|
||||
|
||||
if (request.ToDate.HasValue)
|
||||
query = query.Where(x => x.Created <= request.ToDate.Value);
|
||||
|
||||
// Order by most recent first
|
||||
query = query.OrderByDescending(x => x.Created);
|
||||
|
||||
// Get metadata
|
||||
var metaData = await query.GetMetaData(request.PaginationState, cancellationToken);
|
||||
|
||||
// Get paginated results
|
||||
var orders = await query
|
||||
.PaginatedListAsync(request.PaginationState)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var models = orders.Select(order => new CustomerOrderModel
|
||||
{
|
||||
Id = order.Id,
|
||||
Amount = order.Amount,
|
||||
PackageId = order.PackageId,
|
||||
TransactionId = order.TransactionId,
|
||||
PaymentStatus = order.PaymentStatus,
|
||||
PaymentDate = order.PaymentDate,
|
||||
UserId = order.UserId,
|
||||
UserAddressId = order.UserAddressId,
|
||||
PaymentMethod = order.PaymentMethod,
|
||||
UserAddressText = order.UserAddress?.Address ?? "",
|
||||
DeliveryStatus = order.DeliveryStatus,
|
||||
TrackingCode = order.TrackingCode ?? "",
|
||||
DeliveryDescription = order.DeliveryDescription ?? "",
|
||||
UserFullName = $"{order.User?.FirstName ?? ""} {order.User?.LastName ?? ""}".Trim(),
|
||||
UserNationalCode = order.User?.NationalCode ?? "",
|
||||
VatAmount = order.OrderVAT?.VATAmount ?? 0,
|
||||
VatPercentage = order.OrderVAT != null ? (double)order.OrderVAT.VATRate * 100 : 0,
|
||||
FactorDetails = order.FactorDetails?.Select(fd => new FactorDetailModel
|
||||
{
|
||||
ProductId = fd.ProductId,
|
||||
ProductTitle = fd.Product?.Title ?? "",
|
||||
ProductThumbnailPath = fd.Product?.ThumbnailPath ?? "",
|
||||
UnitPrice = fd.UnitPrice,
|
||||
Count = fd.Count,
|
||||
UnitDiscountPrice = fd.UnitDiscountPrice
|
||||
}).ToList() ?? new List<FactorDetailModel>()
|
||||
}).ToList();
|
||||
|
||||
return new GetCustomerOrdersResponseDto
|
||||
{
|
||||
MetaData = metaData,
|
||||
Models = models
|
||||
};
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetCustomerOrders;
|
||||
|
||||
public class GetCustomerOrdersResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public List<CustomerOrderModel> Models { get; set; } = new();
|
||||
}
|
||||
|
||||
public class CustomerOrderModel
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long Amount { get; set; }
|
||||
public long? PackageId { get; set; }
|
||||
public long? TransactionId { get; set; }
|
||||
public PaymentStatus PaymentStatus { get; set; }
|
||||
public DateTime? PaymentDate { get; set; }
|
||||
public long UserId { get; set; }
|
||||
public long UserAddressId { get; set; }
|
||||
public PaymentMethod? PaymentMethod { get; set; }
|
||||
public string UserAddressText { get; set; }
|
||||
public List<FactorDetailModel> FactorDetails { get; set; } = new();
|
||||
public DeliveryStatus DeliveryStatus { get; set; }
|
||||
public string TrackingCode { get; set; }
|
||||
public string DeliveryDescription { get; set; }
|
||||
public string UserFullName { get; set; }
|
||||
public string UserNationalCode { get; set; }
|
||||
public long VatAmount { get; set; }
|
||||
public double VatPercentage { get; set; }
|
||||
}
|
||||
|
||||
public class FactorDetailModel
|
||||
{
|
||||
public long ProductId { get; set; }
|
||||
public string ProductTitle { get; set; }
|
||||
public string ProductThumbnailPath { get; set; }
|
||||
public long? UnitPrice { get; set; }
|
||||
public int? Count { get; set; }
|
||||
public long? UnitDiscountPrice { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user