Complete FrontOffice BFF to CMS Migration
- Migrated all 9 services from FrontOffice.BFF to CMS architecture - Enhanced user.proto with 7 additional Customer API endpoints: * UpdateCustomerProfile, GetCustomerProfile * ChangeCustomerPassword with validation * GetCustomerReferrals with commission stats * UploadCustomerAvatar with file validation * GetCustomerSettings, UpdateCustomerSettings - All services now support Customer endpoints with /Customer/ prefix - Mock implementations with realistic Persian data - Fixed namespace conflicts and compilation issues - Comprehensive testing completed for all endpoints - Services migrated: Categories, City, UserCarts, Products, UserWallet, Transaction, UserOrder, Package, User (enhanced)
This commit is contained in:
-39
@@ -1,39 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.ApplyDiscountToOrder;
|
||||
|
||||
/// <summary>
|
||||
/// اعمال تخفیف به سفارش
|
||||
/// </summary>
|
||||
public record ApplyDiscountToOrderCommand : IRequest<ApplyDiscountToOrderResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه سفارش
|
||||
/// </summary>
|
||||
public long OrderId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ تخفیف (ریال)
|
||||
/// </summary>
|
||||
public long DiscountAmount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// دلیل تخفیف
|
||||
/// </summary>
|
||||
public string Reason { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// کد تخفیف (اختیاری)
|
||||
/// </summary>
|
||||
public string? DiscountCode { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// پاسخ اعمال تخفیف
|
||||
/// </summary>
|
||||
public class ApplyDiscountToOrderResponseDto
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Message { get; set; } = string.Empty;
|
||||
public long OriginalAmount { get; set; }
|
||||
public long DiscountAmount { get; set; }
|
||||
public long FinalAmount { get; set; }
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.ApplyDiscountToOrder;
|
||||
|
||||
public class ApplyDiscountToOrderCommandHandler : IRequestHandler<ApplyDiscountToOrderCommand, ApplyDiscountToOrderResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ILogger<ApplyDiscountToOrderCommandHandler> _logger;
|
||||
|
||||
public ApplyDiscountToOrderCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ILogger<ApplyDiscountToOrderCommandHandler> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<ApplyDiscountToOrderResponseDto> Handle(ApplyDiscountToOrderCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: پیادهسازی اعمال تخفیف به سفارش
|
||||
// 1. پیدا کردن سفارش:
|
||||
// - var order = await _context.UserOrders.FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken)
|
||||
// - بررسی null و پرتاب NotFoundException
|
||||
//
|
||||
// 2. بررسی شرایط اعمال تخفیف:
|
||||
// - سفارش نباید Delivered یا Cancelled باشد
|
||||
// - مبلغ تخفیف نباید بیشتر از Amount باشد
|
||||
// - if (order.DeliveryStatus == DeliveryStatus.Delivered || order.DeliveryStatus == DeliveryStatus.Cancelled)
|
||||
// throw new InvalidOperationException("نمیتوان به این سفارش تخفیف اعمال کرد")
|
||||
// - if (request.DiscountAmount > order.Amount)
|
||||
// throw new InvalidOperationException("مبلغ تخفیف نمیتواند بیشتر از مبلغ سفارش باشد")
|
||||
//
|
||||
// 3. محاسبه مبلغ نهایی:
|
||||
// - var originalAmount = order.Amount
|
||||
// - var newDiscountedPrice = order.Amount - request.DiscountAmount
|
||||
// - مطمئن شوید که منفی نشود: newDiscountedPrice = Math.Max(0, newDiscountedPrice)
|
||||
//
|
||||
// 4. بهروزرسانی سفارش:
|
||||
// - order.DiscountedPrice = newDiscountedPrice
|
||||
// - اگر فیلد OrderDiscountAmount وجود دارد، آن را هم بهروز کنید
|
||||
// - order.OrderDiscountAmount = request.DiscountAmount
|
||||
// - اضافه کردن به توضیحات:
|
||||
// order.DeliveryDescription = (order.DeliveryDescription ?? "") +
|
||||
// $"\nتخفیف اعمال شده: {request.DiscountAmount} ریال - دلیل: {request.Reason}"
|
||||
//
|
||||
// 5. ذخیره Log تخفیف (اختیاری - اگر جدول OrderDiscountLog دارید):
|
||||
// - var discountLog = new OrderDiscountLog {
|
||||
// OrderId = order.Id,
|
||||
// DiscountAmount = request.DiscountAmount,
|
||||
// Reason = request.Reason,
|
||||
// DiscountCode = request.DiscountCode,
|
||||
// AppliedAt = DateTime.Now
|
||||
// }
|
||||
// - await _context.OrderDiscountLogs.AddAsync(discountLog, cancellationToken)
|
||||
//
|
||||
// 6. ذخیره و Log:
|
||||
// - await _context.SaveChangesAsync(cancellationToken)
|
||||
// - _logger.LogInformation("Discount {Amount} applied to order {OrderId}: {Reason}",
|
||||
// request.DiscountAmount, request.OrderId, request.Reason)
|
||||
//
|
||||
// 7. برگشت Response:
|
||||
// - return new ApplyDiscountToOrderResponseDto {
|
||||
// Success = true,
|
||||
// Message = "تخفیف با موفقیت اعمال شد",
|
||||
// OriginalAmount = originalAmount,
|
||||
// DiscountAmount = request.DiscountAmount,
|
||||
// FinalAmount = newDiscountedPrice
|
||||
// }
|
||||
//
|
||||
// نکته: این تخفیف برای تخفیفات دستی Admin است و جدا از تخفیفهای محصول
|
||||
|
||||
throw new NotImplementedException("ApplyDiscountToOrder needs implementation");
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.ApplyDiscountToOrder;
|
||||
|
||||
public class ApplyDiscountToOrderCommandValidator : AbstractValidator<ApplyDiscountToOrderCommand>
|
||||
{
|
||||
public ApplyDiscountToOrderCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.OrderId)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("شناسه سفارش باید بزرگتر از 0 باشد");
|
||||
|
||||
RuleFor(x => x.DiscountAmount)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("مبلغ تخفیف باید بزرگتر از 0 باشد");
|
||||
|
||||
RuleFor(x => x.Reason)
|
||||
.NotEmpty()
|
||||
.WithMessage("دلیل تخفیف الزامی است")
|
||||
.MaximumLength(500)
|
||||
.WithMessage("دلیل تخفیف نمیتواند بیشتر از 500 کاراکتر باشد");
|
||||
}
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.CancelOrder;
|
||||
|
||||
/// <summary>
|
||||
/// Command برای لغو سفارش
|
||||
/// </summary>
|
||||
public record CancelOrderCommand : IRequest<CancelOrderResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه سفارش
|
||||
/// </summary>
|
||||
public long OrderId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// دلیل لغو سفارش
|
||||
/// </summary>
|
||||
public string CancelReason { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// آیا مبلغ باید بازگردانده شود؟
|
||||
/// </summary>
|
||||
public bool RefundPayment { get; init; }
|
||||
}
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Events;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.CancelOrder;
|
||||
|
||||
public class CancelOrderCommandHandler : IRequestHandler<CancelOrderCommand, CancelOrderResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly IInventoryService _inventoryService;
|
||||
|
||||
public CancelOrderCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
IInventoryService inventoryService)
|
||||
{
|
||||
_context = context;
|
||||
_inventoryService = inventoryService;
|
||||
}
|
||||
|
||||
public async Task<CancelOrderResponseDto> Handle(CancelOrderCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// پیدا کردن سفارش با جزئیات
|
||||
var order = await _context.UserOrders
|
||||
.Include(o => o.Transaction)
|
||||
.Include(o => o.FactorDetails)
|
||||
.FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken);
|
||||
|
||||
if (order == null)
|
||||
{
|
||||
throw new NotFoundException(nameof(UserOrder), request.OrderId);
|
||||
}
|
||||
|
||||
// چک کردن که سفارش قابل لغو باشد
|
||||
if (order.DeliveryStatus == DeliveryStatus.Delivered)
|
||||
{
|
||||
throw new InvalidOperationException("سفارش تحویل داده شده قابل لغو نیست");
|
||||
}
|
||||
|
||||
if (order.DeliveryStatus == DeliveryStatus.Cancelled)
|
||||
{
|
||||
throw new InvalidOperationException("این سفارش قبلاً لغو شده است");
|
||||
}
|
||||
|
||||
// برگشت موجودی محصولات به انبار
|
||||
foreach (var factorDetail in order.FactorDetails)
|
||||
{
|
||||
await _inventoryService.ProcessReturnAsync(
|
||||
factorDetail.ProductId,
|
||||
ProductType.RegularProduct,
|
||||
factorDetail.Count,
|
||||
order.Id,
|
||||
$"لغو سفارش: {request.CancelReason}",
|
||||
null,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
// تغییر وضعیت سفارش
|
||||
order.DeliveryStatus = DeliveryStatus.Cancelled;
|
||||
order.DeliveryDescription = $"لغو شده: {request.CancelReason}";
|
||||
|
||||
// اگر درخواست بازگشت پول داریم و پرداخت موفق بوده
|
||||
if (request.RefundPayment &&
|
||||
order.Transaction != null &&
|
||||
order.Transaction.PaymentStatus == PaymentStatus.Success)
|
||||
{
|
||||
// ایجاد تراکنش استرداد
|
||||
var refundTransaction = new Transaction
|
||||
{
|
||||
Amount = -order.Amount,
|
||||
Description = $"بازگشت وجه سفارش {request.OrderId}: {request.CancelReason}",
|
||||
PaymentStatus = PaymentStatus.Success,
|
||||
PaymentDate = DateTime.Now,
|
||||
RefId = $"REFUND-ORDER-{order.Id}",
|
||||
Type = TransactionType.Buy
|
||||
};
|
||||
|
||||
await _context.Transactions.AddAsync(refundTransaction, cancellationToken);
|
||||
}
|
||||
|
||||
// ثبت Event
|
||||
order.AddDomainEvent(new CancelOrderEvent(order, request.CancelReason));
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return new CancelOrderResponseDto
|
||||
{
|
||||
OrderId = order.Id,
|
||||
Status = order.DeliveryStatus,
|
||||
Message = "سفارش با موفقیت لغو شد",
|
||||
RefundProcessed = request.RefundPayment && order.Transaction != null
|
||||
};
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.CancelOrder;
|
||||
|
||||
public class CancelOrderCommandValidator : AbstractValidator<CancelOrderCommand>
|
||||
{
|
||||
public CancelOrderCommandValidator()
|
||||
{
|
||||
RuleFor(v => v.OrderId)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("شناسه سفارش باید بزرگتر از صفر باشد");
|
||||
|
||||
RuleFor(v => v.CancelReason)
|
||||
.NotEmpty()
|
||||
.WithMessage("دلیل لغو سفارش الزامی است")
|
||||
.MaximumLength(500)
|
||||
.WithMessage("دلیل لغو نباید بیش از 500 کاراکتر باشد");
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.CancelOrder;
|
||||
|
||||
public class CancelOrderResponseDto
|
||||
{
|
||||
public long OrderId { get; set; }
|
||||
public DeliveryStatus Status { get; set; }
|
||||
public string Message { get; set; }
|
||||
public bool RefundProcessed { get; set; }
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder;
|
||||
public record CreateNewUserOrderCommand : IRequest<CreateNewUserOrderResponseDto>
|
||||
{
|
||||
//قیمت
|
||||
public long Amount { get; init; }
|
||||
//شناسه پکیج
|
||||
public long PackageId { get; init; }
|
||||
//شناسه تراکنش
|
||||
public long? TransactionId { get; init; }
|
||||
//وضعیت پرداخت
|
||||
public PaymentStatus PaymentStatus { get; init; }
|
||||
//تاریخ پرداخت
|
||||
public DateTime? PaymentDate { get; init; }
|
||||
//شناسه کاربر
|
||||
public long UserId { get; init; }
|
||||
//شناسه آدرس کاربر
|
||||
public long UserAddressId { get; init; }
|
||||
//
|
||||
public PaymentMethod? PaymentMethod { get; init; }
|
||||
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
using CMSMicroservice.Domain.Events;
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder;
|
||||
public class CreateNewUserOrderCommandHandler : IRequestHandler<CreateNewUserOrderCommand, CreateNewUserOrderResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
|
||||
public CreateNewUserOrderCommandHandler(IApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<CreateNewUserOrderResponseDto> Handle(CreateNewUserOrderCommand request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (await _context.UserOrders.AnyAsync(x => x.UserId == request.UserId && x.PackageId == request.PackageId, cancellationToken: cancellationToken))
|
||||
throw new Exception(message: "duplicate order!!");
|
||||
|
||||
var package = await _context.Packages
|
||||
.FirstOrDefaultAsync(x => x.Id == request.PackageId, cancellationToken) ?? throw new NotFoundException(nameof(Package), request.PackageId);
|
||||
|
||||
var entity = request.Adapt<UserOrder>();
|
||||
entity.Amount = package.Price;
|
||||
await _context.UserOrders.AddAsync(entity, cancellationToken);
|
||||
entity.AddDomainEvent(new CreateNewUserOrderEvent(entity));
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
return entity.Adapt<CreateNewUserOrderResponseDto>();
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder;
|
||||
public class CreateNewUserOrderCommandValidator : AbstractValidator<CreateNewUserOrderCommand>
|
||||
{
|
||||
public CreateNewUserOrderCommandValidator()
|
||||
{
|
||||
RuleFor(model => model.Amount)
|
||||
.NotNull();
|
||||
RuleFor(model => model.PackageId)
|
||||
.NotNull();
|
||||
RuleFor(model => model.PaymentStatus)
|
||||
.IsInEnum()
|
||||
.NotNull();
|
||||
RuleFor(model => model.UserId)
|
||||
.NotNull();
|
||||
RuleFor(model => model.UserAddressId)
|
||||
.NotNull();
|
||||
RuleFor(model => model.PaymentMethod)
|
||||
.IsInEnum();
|
||||
}
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(ValidationContext<CreateNewUserOrderCommand>.CreateWithOptions((CreateNewUserOrderCommand)model, x => x.IncludeProperties(propertyName)));
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder;
|
||||
public class CreateNewUserOrderResponseDto
|
||||
{
|
||||
//شناسه
|
||||
public long Id { get; set; }
|
||||
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.DeleteUserOrder;
|
||||
public record DeleteUserOrderCommand : IRequest<Unit>
|
||||
{
|
||||
//شناسه
|
||||
public long Id { get; init; }
|
||||
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
using CMSMicroservice.Domain.Events;
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.DeleteUserOrder;
|
||||
public class DeleteUserOrderCommandHandler : IRequestHandler<DeleteUserOrderCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
|
||||
public DeleteUserOrderCommandHandler(IApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(DeleteUserOrderCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var entity = await _context.UserOrders
|
||||
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserOrder), request.Id);
|
||||
entity.IsDeleted = true;
|
||||
_context.UserOrders.Update(entity);
|
||||
entity.AddDomainEvent(new DeleteUserOrderEvent(entity));
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.DeleteUserOrder;
|
||||
public class DeleteUserOrderCommandValidator : AbstractValidator<DeleteUserOrderCommand>
|
||||
{
|
||||
public DeleteUserOrderCommandValidator()
|
||||
{
|
||||
RuleFor(model => model.Id)
|
||||
.NotNull();
|
||||
}
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(ValidationContext<DeleteUserOrderCommand>.CreateWithOptions((DeleteUserOrderCommand)model, x => x.IncludeProperties(propertyName)));
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.SubmitShopBuyOrder;
|
||||
public record SubmitShopBuyOrderCommand : IRequest<SubmitShopBuyOrderResponseDto>
|
||||
{
|
||||
//کل مبلغ ورودی
|
||||
public long TotalAmount { get; init; }
|
||||
//شناسه کاربر
|
||||
public long UserId { get; init; }
|
||||
|
||||
}
|
||||
-241
@@ -1,241 +0,0 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using CMSMicroservice.Domain.Events;
|
||||
using CMSMicroservice.Domain.Entities.Order;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.SubmitShopBuyOrder;
|
||||
|
||||
public class
|
||||
SubmitShopBuyOrderCommandHandler : IRequestHandler<SubmitShopBuyOrderCommand, SubmitShopBuyOrderResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly IInventoryService _inventoryService;
|
||||
private readonly ILogger<SubmitShopBuyOrderCommandHandler> _logger;
|
||||
private float _vatRate;
|
||||
|
||||
public SubmitShopBuyOrderCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
IInventoryService inventoryService,
|
||||
ILogger<SubmitShopBuyOrderCommandHandler> logger)
|
||||
{
|
||||
_context = context;
|
||||
_inventoryService = inventoryService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<SubmitShopBuyOrderResponseDto> Handle(SubmitShopBuyOrderCommand request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var user = await _context.Users
|
||||
.Include(i => i.UserAddresses)
|
||||
.Include(i => i.UserWallets)
|
||||
.ThenInclude(i => i.UserWalletChangeLogs)
|
||||
.Include(i => i.UserCarts)
|
||||
.ThenInclude(i => i.Product)
|
||||
.FirstOrDefaultAsync(w => w.Id == request.UserId, cancellationToken: cancellationToken);
|
||||
if (user.UserCarts.Count == 0)
|
||||
throw new NotFoundException("UserCart", request.UserId);
|
||||
|
||||
// چک موجودی محصولات
|
||||
var outOfStockProducts = new List<string>();
|
||||
var insufficientStockProducts = new List<(string Title, int Requested, int Available)>();
|
||||
|
||||
foreach (var cartItem in user.UserCarts)
|
||||
{
|
||||
if (cartItem.Product.RemainingCount <= 0)
|
||||
{
|
||||
outOfStockProducts.Add(cartItem.Product.Title);
|
||||
}
|
||||
else if (cartItem.Product.RemainingCount < cartItem.Count)
|
||||
{
|
||||
insufficientStockProducts.Add((cartItem.Product.Title, cartItem.Count,
|
||||
cartItem.Product.RemainingCount));
|
||||
}
|
||||
}
|
||||
|
||||
if (outOfStockProducts.Any())
|
||||
{
|
||||
throw new Exception($"محصولات زیر ناموجود شدهاند: {string.Join("، ", outOfStockProducts)}");
|
||||
}
|
||||
|
||||
if (insufficientStockProducts.Any())
|
||||
{
|
||||
var messages = insufficientStockProducts.Select(p =>
|
||||
$"«{p.Title}»: درخواست {p.Requested} عدد، موجودی {p.Available} عدد");
|
||||
throw new Exception($"موجودی محصولات زیر کافی نیست: {string.Join(" | ", messages)}");
|
||||
}
|
||||
|
||||
long finalAmount = 0;
|
||||
|
||||
// استفاده از SystemConstants برای VAT
|
||||
if (SystemConstants.ShopVATEnabled)
|
||||
{
|
||||
_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}",
|
||||
user.UserCarts.Sum(s => s.Count * s.Product.Price), _vatRate, finalAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
finalAmount = user.UserCarts.Sum(s => s.Count * s.Product.Price);
|
||||
}
|
||||
|
||||
if (finalAmount != request.TotalAmount)
|
||||
throw new Exception("مبلغ سفارش با مجموع سبد خرید مطابقت ندارد.");
|
||||
|
||||
|
||||
var userWallet = user.UserWallets.FirstOrDefault();
|
||||
if (userWallet == null)
|
||||
throw new Exception("کیف پول کاربر یافت نشد.");
|
||||
|
||||
if (userWallet.Balance <= 0 || userWallet.Balance < request.TotalAmount)
|
||||
throw new Exception("موجودی کیف پول کاربر برای انجام این تراکنش کافی نیست.");
|
||||
|
||||
var newTransaction = new Transaction()
|
||||
{
|
||||
Amount = request.TotalAmount,
|
||||
Description = "خرید از فروشگاه",
|
||||
PaymentStatus = PaymentStatus.Success,
|
||||
PaymentDate = DateTime.Now,
|
||||
Type = TransactionType.Buy,
|
||||
RefId = "localwallet-" + Guid.NewGuid().ToString()
|
||||
};
|
||||
await _context.Transactions.AddAsync(newTransaction, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var newWalletLog = new UserWalletChangeLog()
|
||||
{
|
||||
CurrentBalance = userWallet.Balance,
|
||||
CurrentNetworkBalance = userWallet.NetworkBalance,
|
||||
WalletId = userWallet.Id,
|
||||
ChangeValue = -1 * request.TotalAmount,
|
||||
IsIncrease = false,
|
||||
RefrenceId = newTransaction.Id,
|
||||
};
|
||||
userWallet.Balance -= request.TotalAmount;
|
||||
|
||||
await _context.UserWalletChangeLogs.AddAsync(newWalletLog, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var newOrder = new UserOrder()
|
||||
{
|
||||
Amount = request.TotalAmount,
|
||||
PaymentStatus = PaymentStatus.Success,
|
||||
PaymentMethod = PaymentMethod.Wallet,
|
||||
PaymentDate = DateTime.Now,
|
||||
UserId = request.UserId,
|
||||
UserAddressId = user.UserAddresses.First(f => f.IsDefault).Id,
|
||||
TransactionId = newTransaction.Id,
|
||||
// سفارش فروشگاهی فیزیکی است، پس در ابتدا در انتظار ارسال است
|
||||
DeliveryStatus = DeliveryStatus.Pending
|
||||
};
|
||||
await _context.UserOrders.AddAsync(newOrder, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// محاسبه و ثبت VAT (اگر فعال باشد)
|
||||
var vatCreated = await CalculateAndSaveVAT(newOrder.Id, request.TotalAmount, cancellationToken);
|
||||
if (vatCreated)
|
||||
{
|
||||
newOrder.HasVAT = true;
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
var factorDetailsList = user.UserCarts.Select(s => new FactorDetails()
|
||||
{
|
||||
ProductId = s.ProductId,
|
||||
Count = s.Count,
|
||||
UnitPrice = SystemConstants.ShopVATEnabled ? AddVAT(s.Product.Price) : s.Product.Price,
|
||||
OrderId = newOrder.Id
|
||||
});
|
||||
await _context.FactorDetails.AddRangeAsync(factorDetailsList, cancellationToken);
|
||||
|
||||
// کاهش موجودی محصولات و افزایش تعداد فروش از طریق InventoryService
|
||||
foreach (var cartItem in user.UserCarts)
|
||||
{
|
||||
// استفاده از سرویس انبارداری برای کسر موجودی
|
||||
await _inventoryService.ConfirmSaleAsync(
|
||||
cartItem.ProductId,
|
||||
ProductType.RegularProduct,
|
||||
cartItem.Count,
|
||||
newOrder.Id,
|
||||
cancellationToken);
|
||||
|
||||
// افزایش تعداد فروش
|
||||
cartItem.Product.SaleCount += cartItem.Count;
|
||||
}
|
||||
|
||||
user.UserCarts.Clear();
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
_logger.LogInformation("Order {OrderId} completed. Stock updated for {ProductCount} products.",
|
||||
newOrder.Id, factorDetailsList.Count());
|
||||
|
||||
var finalResult = new SubmitShopBuyOrderResponseDto()
|
||||
{
|
||||
Id = newOrder.Id,
|
||||
};
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
public long CalculateVAT(long amount) => (long)(amount * _vatRate);
|
||||
|
||||
/// <summary>
|
||||
/// محاسبه قیمت با احتساب مالیات
|
||||
/// </summary>
|
||||
public long AddVAT(long amount) => amount + CalculateVAT(amount);
|
||||
|
||||
private async Task<bool> CalculateAndSaveVAT(long orderId, long orderAmount, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
// بررسی فعال بودن VAT از SystemConstants
|
||||
if (!SystemConstants.ShopVATEnabled)
|
||||
{
|
||||
_logger.LogInformation("VAT is disabled. Skipping VAT calculation for order {OrderId}", orderId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// دریافت نرخ VAT از SystemConstants
|
||||
var vatRate = SystemConstants.ShopVAT;
|
||||
|
||||
// محاسبه مالیات
|
||||
var vatAmount = (long)(orderAmount * vatRate);
|
||||
var totalAmount = orderAmount + vatAmount;
|
||||
|
||||
// ثبت VAT
|
||||
var orderVAT = new OrderVAT
|
||||
{
|
||||
OrderId = orderId,
|
||||
VATRate = vatRate,
|
||||
BaseAmount = orderAmount,
|
||||
VATAmount = vatAmount,
|
||||
TotalAmount = totalAmount,
|
||||
IsPaid = true,
|
||||
PaidAt = DateTime.Now
|
||||
};
|
||||
|
||||
await _context.OrderVATs.AddAsync(orderVAT, cancellationToken);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
_logger.LogInformation(
|
||||
"VAT calculated and saved for order {OrderId}. Rate: {Rate}%, Base: {Base}, VAT: {VAT}, Total: {Total}",
|
||||
orderId,
|
||||
vatRate * 100,
|
||||
orderAmount,
|
||||
vatAmount,
|
||||
totalAmount
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error calculating VAT for order {OrderId}", orderId);
|
||||
// عدم محاسبه VAT نباید مانع ثبت سفارش شود
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.SubmitShopBuyOrder;
|
||||
public class SubmitShopBuyOrderCommandValidator : AbstractValidator<SubmitShopBuyOrderCommand>
|
||||
{
|
||||
public SubmitShopBuyOrderCommandValidator()
|
||||
{
|
||||
RuleFor(model => model.TotalAmount)
|
||||
.NotNull();
|
||||
RuleFor(model => model.UserId)
|
||||
.NotNull();
|
||||
}
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(ValidationContext<SubmitShopBuyOrderCommand>.CreateWithOptions((SubmitShopBuyOrderCommand)model, x => x.IncludeProperties(propertyName)));
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.SubmitShopBuyOrder;
|
||||
public class SubmitShopBuyOrderResponseDto
|
||||
{
|
||||
//شناسه
|
||||
public long Id { get; set; }
|
||||
|
||||
}
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateOrderStatus;
|
||||
|
||||
/// <summary>
|
||||
/// تغییر وضعیت سفارش
|
||||
/// </summary>
|
||||
public record UpdateOrderStatusCommand : IRequest<UpdateOrderStatusResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه سفارش
|
||||
/// </summary>
|
||||
public long OrderId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// وضعیت تحویل جدید
|
||||
/// </summary>
|
||||
public DeliveryStatus NewStatus { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// توضیحات (اختیاری)
|
||||
/// </summary>
|
||||
public string? Description { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// پاسخ تغییر وضعیت سفارش
|
||||
/// </summary>
|
||||
public class UpdateOrderStatusResponseDto
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Message { get; set; } = string.Empty;
|
||||
public DeliveryStatus CurrentStatus { get; set; }
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ValidationException = FluentValidation.ValidationException;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateOrderStatus;
|
||||
|
||||
public class UpdateOrderStatusCommandHandler : IRequestHandler<UpdateOrderStatusCommand, UpdateOrderStatusResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ILogger<UpdateOrderStatusCommandHandler> _logger;
|
||||
|
||||
public UpdateOrderStatusCommandHandler(
|
||||
IApplicationDbContext context,
|
||||
ILogger<UpdateOrderStatusCommandHandler> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<UpdateOrderStatusResponseDto> Handle(UpdateOrderStatusCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var order = await _context.UserOrders
|
||||
.FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken);
|
||||
|
||||
if (order == null)
|
||||
{
|
||||
throw new NotFoundException(nameof(order), request.OrderId);
|
||||
}
|
||||
|
||||
var oldStatus = order.DeliveryStatus;
|
||||
|
||||
// قوانین ساده انتقال وضعیت: از Cancelled نمیتوان خارج شد
|
||||
if (oldStatus == DeliveryStatus.Cancelled)
|
||||
{
|
||||
throw new ValidationException("امکان تغییر وضعیت سفارش لغو شده وجود ندارد");
|
||||
}
|
||||
|
||||
order.DeliveryStatus = request.NewStatus;
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
_logger.LogInformation(
|
||||
"Order {OrderId} status changed from {OldStatus} to {NewStatus}",
|
||||
request.OrderId,
|
||||
oldStatus,
|
||||
request.NewStatus);
|
||||
|
||||
return new UpdateOrderStatusResponseDto
|
||||
{
|
||||
Success = true,
|
||||
Message = "وضعیت سفارش با موفقیت تغییر کرد",
|
||||
CurrentStatus = order.DeliveryStatus
|
||||
};
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateOrderStatus;
|
||||
|
||||
public class UpdateOrderStatusCommandValidator : AbstractValidator<UpdateOrderStatusCommand>
|
||||
{
|
||||
public UpdateOrderStatusCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.OrderId)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("شناسه سفارش باید بزرگتر از 0 باشد");
|
||||
|
||||
RuleFor(x => x.NewStatus)
|
||||
.IsInEnum()
|
||||
.WithMessage("وضعیت تحویل نامعتبر است");
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateUserOrder;
|
||||
public record UpdateUserOrderCommand : IRequest<Unit>
|
||||
{
|
||||
//شناسه
|
||||
public long Id { get; init; }
|
||||
//قیمت
|
||||
public long? Amount { get; init; }
|
||||
//شناسه پکیج
|
||||
public long? PackageId { get; init; }
|
||||
//شناسه تراکنش
|
||||
public long? TransactionId { get; init; }
|
||||
//وضعیت پرداخت
|
||||
public PaymentStatus? PaymentStatus { get; init; }
|
||||
//تاریخ پرداخت
|
||||
public DateTime? PaymentDate { get; init; }
|
||||
//شناسه کاربر
|
||||
public long? UserId { get; init; }
|
||||
//شناسه آدرس کاربر
|
||||
public long? UserAddressId { get; init; }
|
||||
//
|
||||
public PaymentMethod? PaymentMethod { get; init; }
|
||||
// وضعیت ارسال سفارش
|
||||
public DeliveryStatus? DeliveryStatus { get; init; }
|
||||
// کد رهگیری مرسوله
|
||||
public string? TrackingCode { get; init; }
|
||||
// توضیحات ارسال
|
||||
public string? DeliveryDescription { get; init; }
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
using CMSMicroservice.Domain.Events;
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateUserOrder;
|
||||
public class UpdateUserOrderCommandHandler : IRequestHandler<UpdateUserOrderCommand, Unit>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
|
||||
public UpdateUserOrderCommandHandler(IApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(UpdateUserOrderCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var entity = await _context.UserOrders
|
||||
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(UserOrder), request.Id);
|
||||
request.Adapt(entity);
|
||||
_context.UserOrders.Update(entity);
|
||||
entity.AddDomainEvent(new UpdateUserOrderEvent(entity));
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateUserOrder;
|
||||
public class UpdateUserOrderCommandValidator : AbstractValidator<UpdateUserOrderCommand>
|
||||
{
|
||||
public UpdateUserOrderCommandValidator()
|
||||
{
|
||||
RuleFor(model => model.Id)
|
||||
.NotNull();
|
||||
// RuleFor(model => model.Amount)
|
||||
// .NotNull();
|
||||
// RuleFor(model => model.PackageId)
|
||||
// .NotNull();
|
||||
// RuleFor(model => model.PaymentStatus)
|
||||
// .IsInEnum()
|
||||
// .NotNull();
|
||||
// RuleFor(model => model.UserId)
|
||||
// .NotNull();
|
||||
// RuleFor(model => model.UserAddressId)
|
||||
// .NotNull();
|
||||
// RuleFor(model => model.PaymentMethod)
|
||||
// .IsInEnum();
|
||||
}
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(ValidationContext<UpdateUserOrderCommand>.CreateWithOptions((UpdateUserOrderCommand)model, x => x.IncludeProperties(propertyName)));
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using CMSMicroservice.Domain.Events;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.EventHandlers.CancelOrderEventHandlers;
|
||||
|
||||
public class CancelOrderEventHandler : INotificationHandler<CancelOrderEvent>
|
||||
{
|
||||
private readonly ILogger<CancelOrderEventHandler> _logger;
|
||||
|
||||
public CancelOrderEventHandler(ILogger<CancelOrderEventHandler> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task Handle(CancelOrderEvent notification, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Order {OrderId} cancelled. Reason: {Reason}",
|
||||
notification.Order.Id,
|
||||
notification.CancelReason);
|
||||
|
||||
// اینجا میتونیم اعلان به کاربر بفرستیم
|
||||
// یا موجودی محصولات رو بازگردانیم به انبار
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
using CMSMicroservice.Domain.Events;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.EventHandlers;
|
||||
|
||||
public class CreateNewUserOrderEventHandler : INotificationHandler<CreateNewUserOrderEvent>
|
||||
{
|
||||
private readonly ILogger<CreateNewUserOrderEventHandler> _logger;
|
||||
|
||||
public CreateNewUserOrderEventHandler(ILogger<CreateNewUserOrderEventHandler> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task Handle(CreateNewUserOrderEvent notification, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
using CMSMicroservice.Domain.Events;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.EventHandlers;
|
||||
|
||||
public class DeleteUserOrderEventHandler : INotificationHandler<DeleteUserOrderEvent>
|
||||
{
|
||||
private readonly ILogger<DeleteUserOrderEventHandler> _logger;
|
||||
|
||||
public DeleteUserOrderEventHandler(ILogger<DeleteUserOrderEventHandler> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task Handle(DeleteUserOrderEvent notification, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
using CMSMicroservice.Domain.Events;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.EventHandlers;
|
||||
|
||||
public class SubmitShopBuyOrderEventHandler : INotificationHandler<SubmitShopBuyOrderEvent>
|
||||
{
|
||||
private readonly ILogger<
|
||||
SubmitShopBuyOrderEventHandler> _logger;
|
||||
|
||||
public SubmitShopBuyOrderEventHandler(ILogger<SubmitShopBuyOrderEventHandler> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task Handle(SubmitShopBuyOrderEvent notification, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
using CMSMicroservice.Domain.Events;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.EventHandlers;
|
||||
|
||||
public class UpdateUserOrderEventHandler : INotificationHandler<UpdateUserOrderEvent>
|
||||
{
|
||||
private readonly ILogger<UpdateUserOrderEventHandler> _logger;
|
||||
|
||||
public UpdateUserOrderEventHandler(ILogger<UpdateUserOrderEventHandler> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task Handle(UpdateUserOrderEvent notification, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Domain Event: {DomainEvent}", notification.GetType().Name);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.CalculateOrderPV;
|
||||
|
||||
/// <summary>
|
||||
/// محاسبه امتیاز PV سفارش
|
||||
/// </summary>
|
||||
public record CalculateOrderPVQuery : IRequest<CalculateOrderPVResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه سفارش
|
||||
/// </summary>
|
||||
public long OrderId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// پاسخ محاسبه PV سفارش
|
||||
/// </summary>
|
||||
public class CalculateOrderPVResponseDto
|
||||
{
|
||||
/// <summary>
|
||||
/// مجموع امتیاز PV سفارش
|
||||
/// </summary>
|
||||
public decimal TotalPV { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// جزئیات PV هر محصول
|
||||
/// </summary>
|
||||
public List<ProductPVDto> ProductPVs { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ قابل پرداخت
|
||||
/// </summary>
|
||||
public long PayableAmount { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// جزئیات PV یک محصول در سفارش
|
||||
/// </summary>
|
||||
public class ProductPVDto
|
||||
{
|
||||
public long ProductId { get; set; }
|
||||
public string ProductTitle { get; set; } = string.Empty;
|
||||
public int Quantity { get; set; }
|
||||
public decimal UnitPV { get; set; }
|
||||
public decimal TotalPV { get; set; }
|
||||
public long UnitPrice { get; set; }
|
||||
}
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
using CMSMicroservice.Application.Common.Exceptions;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.CalculateOrderPV;
|
||||
|
||||
public class CalculateOrderPVQueryHandler : IRequestHandler<CalculateOrderPVQuery, CalculateOrderPVResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ILogger<CalculateOrderPVQueryHandler> _logger;
|
||||
|
||||
// نسبت PV به قیمت بر اساس مثالهای بیزینسی:
|
||||
// محصول ۱: قیمت 100,000 → PV = 50
|
||||
// محصول ۲: قیمت 200,000 → PV = 100
|
||||
// یعنی: PV = Price / 2000
|
||||
private const decimal PvPerRial = 1m / 2000m;
|
||||
|
||||
public CalculateOrderPVQueryHandler(
|
||||
IApplicationDbContext context,
|
||||
ILogger<CalculateOrderPVQueryHandler> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<CalculateOrderPVResponseDto> Handle(CalculateOrderPVQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var order = await _context.UserOrders
|
||||
.Include(o => o.FactorDetails)
|
||||
.ThenInclude(fd => fd.Product)
|
||||
.FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken);
|
||||
|
||||
if (order == null)
|
||||
{
|
||||
throw new NotFoundException(nameof(order), request.OrderId);
|
||||
}
|
||||
|
||||
var productPVs = new List<ProductPVDto>();
|
||||
decimal totalPV = 0;
|
||||
|
||||
foreach (var detail in order.FactorDetails)
|
||||
{
|
||||
if (detail.Product == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var unitPrice = detail.Product.Price;
|
||||
var unitPV = Math.Round(unitPrice * PvPerRial, 2, MidpointRounding.AwayFromZero);
|
||||
var itemTotalPV = unitPV * detail.Count;
|
||||
|
||||
productPVs.Add(new ProductPVDto
|
||||
{
|
||||
ProductId = detail.ProductId,
|
||||
ProductTitle = detail.Product.Title,
|
||||
Quantity = detail.Count,
|
||||
UnitPV = unitPV,
|
||||
TotalPV = itemTotalPV,
|
||||
UnitPrice = unitPrice
|
||||
});
|
||||
|
||||
totalPV += itemTotalPV;
|
||||
}
|
||||
|
||||
var response = new CalculateOrderPVResponseDto
|
||||
{
|
||||
TotalPV = totalPV,
|
||||
ProductPVs = productPVs,
|
||||
// فعلاً مبلغ قابل پرداخت همان Amount است؛ در آینده میتوان تخفیف را هم اعمال کرد
|
||||
PayableAmount = order.Amount
|
||||
};
|
||||
|
||||
_logger.LogInformation(
|
||||
"Calculated PV for order {OrderId}: {TotalPV}",
|
||||
request.OrderId,
|
||||
totalPV);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.CalculateOrderPV;
|
||||
|
||||
public class CalculateOrderPVQueryValidator : AbstractValidator<CalculateOrderPVQuery>
|
||||
{
|
||||
public CalculateOrderPVQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.OrderId)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("شناسه سفارش باید بزرگتر از 0 باشد");
|
||||
}
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter;
|
||||
public record GetAllUserOrderByFilterQuery : IRequest<GetAllUserOrderByFilterResponseDto>
|
||||
{
|
||||
//موقعیت صفحه بندی
|
||||
public PaginationState? PaginationState { get; init; }
|
||||
//مرتب سازی بر اساس
|
||||
public string? SortBy { get; init; }
|
||||
//فیلتر
|
||||
public GetAllUserOrderByFilterFilter? Filter { get; init; }
|
||||
|
||||
}public class GetAllUserOrderByFilterFilter
|
||||
{
|
||||
//شناسه
|
||||
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 DeliveryStatus? DeliveryStatus { get; set; }
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter;
|
||||
public class GetAllUserOrderByFilterQueryHandler : IRequestHandler<GetAllUserOrderByFilterQuery, GetAllUserOrderByFilterResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
|
||||
public GetAllUserOrderByFilterQueryHandler(IApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetAllUserOrderByFilterResponseDto> Handle(GetAllUserOrderByFilterQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _context.UserOrders
|
||||
.Include(i => i.UserAddress)
|
||||
.Include(i => i.User)
|
||||
.Include(i => i.FactorDetails)
|
||||
.ThenInclude(t => t.Product)
|
||||
.Include(i => i.OrderVAT)
|
||||
.ApplyOrder(sortBy: request.SortBy)
|
||||
.AsNoTracking()
|
||||
.AsQueryable();
|
||||
if (request.Filter is not null)
|
||||
{
|
||||
query = query
|
||||
.Where(x => request.Filter.Id == null || x.Id == request.Filter.Id)
|
||||
.Where(x => request.Filter.Amount == null || x.Amount == request.Filter.Amount)
|
||||
.Where(x => request.Filter.PackageId == null || x.PackageId == request.Filter.PackageId)
|
||||
.Where(x => request.Filter.TransactionId == null || x.TransactionId == request.Filter.TransactionId)
|
||||
.Where(x => request.Filter.PaymentStatus == null || x.PaymentStatus == request.Filter.PaymentStatus.Value)
|
||||
.Where(x => request.Filter.PaymentDate == null || x.PaymentDate >= request.Filter.PaymentDate)
|
||||
.Where(x => request.Filter.UserId == null || x.UserId == request.Filter.UserId)
|
||||
.Where(x => request.Filter.UserAddressId == null || x.UserAddressId == request.Filter.UserAddressId)
|
||||
.Where(x => request.Filter.PaymentMethod == null || x.PaymentMethod == request.Filter.PaymentMethod)
|
||||
.Where(x => request.Filter.DeliveryStatus == null || x.DeliveryStatus== request.Filter.DeliveryStatus);
|
||||
}
|
||||
var meta = await query.GetMetaData(request.PaginationState, cancellationToken);
|
||||
|
||||
var models = await query
|
||||
.PaginatedListAsync(paginationState: request.PaginationState)
|
||||
.Select(x => new GetAllUserOrderByFilterResponseModel
|
||||
{
|
||||
Id = x.Id,
|
||||
Amount = x.Amount,
|
||||
PackageId = x.PackageId ?? 0,
|
||||
TransactionId = x.TransactionId,
|
||||
PaymentStatus = x.PaymentStatus,
|
||||
PaymentDate = x.PaymentDate,
|
||||
UserId = x.UserId,
|
||||
UserAddressId = x.UserAddressId,
|
||||
PaymentMethod = x.PaymentMethod,
|
||||
UserAddressText = x.UserAddress.Address,
|
||||
FactorDetails = x.FactorDetails.Select(fd => new GetAllUserOrderByFilterResponseModelFactorDetail
|
||||
{
|
||||
ProductId = fd.ProductId,
|
||||
ProductTitle = fd.Product.Title,
|
||||
ProductThumbnailPath = fd.Product.ThumbnailPath,
|
||||
UnitPrice = fd.UnitPrice,
|
||||
Count = fd.Count,
|
||||
UnitDiscountPrice = fd.UnitDiscountPrice
|
||||
}).ToList(),
|
||||
DeliveryStatus = x.DeliveryStatus,
|
||||
TrackingCode = x.TrackingCode,
|
||||
DeliveryDescription = x.DeliveryDescription,
|
||||
UserFullName = (x.User.FirstName ?? string.Empty) + " " + (x.User.LastName ?? string.Empty),
|
||||
UserNationalCode = x.User.NationalCode,
|
||||
VatAmount = x.OrderVAT != null ? x.OrderVAT.VATAmount : 0,
|
||||
VatPercentage = x.OrderVAT != null ? (double)(x.OrderVAT.VATRate * 100) : 0
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return new GetAllUserOrderByFilterResponseDto
|
||||
{
|
||||
MetaData = meta,
|
||||
Models = models
|
||||
};
|
||||
}
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter;
|
||||
public class GetAllUserOrderByFilterQueryValidator : AbstractValidator<GetAllUserOrderByFilterQuery>
|
||||
{
|
||||
public GetAllUserOrderByFilterQueryValidator()
|
||||
{
|
||||
}
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(ValidationContext<GetAllUserOrderByFilterQuery>.CreateWithOptions((GetAllUserOrderByFilterQuery)model, x => x.IncludeProperties(propertyName)));
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter;
|
||||
public class GetAllUserOrderByFilterResponseDto
|
||||
{
|
||||
//متادیتا
|
||||
public MetaData MetaData { get; set; }
|
||||
//مدل خروجی
|
||||
public List<GetAllUserOrderByFilterResponseModel>? Models { get; set; }
|
||||
|
||||
}public class GetAllUserOrderByFilterResponseModel
|
||||
{
|
||||
//شناسه
|
||||
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<GetAllUserOrderByFilterResponseModelFactorDetail>? FactorDetails { get; set; }
|
||||
// وضعیت ارسال سفارش
|
||||
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; }
|
||||
// درصد مالیات بر ارزش افزوده (مثلاً 9 برای 9٪)
|
||||
public double VatPercentage { get; set; }
|
||||
}
|
||||
public class GetAllUserOrderByFilterResponseModelFactorDetail
|
||||
{
|
||||
//شناسه
|
||||
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; }
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange;
|
||||
|
||||
/// <summary>
|
||||
/// دریافت سفارشات بر اساس بازه زمانی
|
||||
/// </summary>
|
||||
public record GetOrdersByDateRangeQuery : IRequest<GetOrdersByDateRangeResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// تاریخ شروع (UTC)
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ پایان (UTC)
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// فیلتر وضعیت تحویل (اختیاری)
|
||||
/// </summary>
|
||||
public DeliveryStatus? Status { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// شناسه کاربر (اختیاری - برای فیلتر بر اساس کاربر)
|
||||
/// </summary>
|
||||
public long? UserId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// شماره صفحه
|
||||
/// </summary>
|
||||
public int PageIndex { get; init; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// تعداد در صفحه
|
||||
/// </summary>
|
||||
public int PageSize { get; init; } = 20;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// پاسخ لیست سفارشات
|
||||
/// </summary>
|
||||
public class GetOrdersByDateRangeResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; } = new();
|
||||
public List<OrderSummaryDto> Orders { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// خلاصه اطلاعات سفارش
|
||||
/// </summary>
|
||||
public class OrderSummaryDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long UserId { get; set; }
|
||||
public string UserFullName { get; set; } = string.Empty;
|
||||
public long Amount { get; set; }
|
||||
public long DiscountedPrice { get; set; }
|
||||
public DeliveryStatus Status { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
public DateTime? ShippedAt { get; set; }
|
||||
public DateTime? DeliveredAt { get; set; }
|
||||
public int ItemsCount { get; set; }
|
||||
}
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Application.Common.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange;
|
||||
|
||||
public class GetOrdersByDateRangeQueryHandler : IRequestHandler<GetOrdersByDateRangeQuery, GetOrdersByDateRangeResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ILogger<GetOrdersByDateRangeQueryHandler> _logger;
|
||||
|
||||
public GetOrdersByDateRangeQueryHandler(
|
||||
IApplicationDbContext context,
|
||||
ILogger<GetOrdersByDateRangeQueryHandler> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<GetOrdersByDateRangeResponseDto> Handle(GetOrdersByDateRangeQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _context.UserOrders
|
||||
.AsNoTracking()
|
||||
.Include(o => o.User)
|
||||
.Include(o => o.FactorDetails)
|
||||
.AsQueryable();
|
||||
|
||||
query = query.Where(o => o.Created >= request.StartDate && o.Created <= request.EndDate);
|
||||
|
||||
if (request.Status.HasValue)
|
||||
{
|
||||
query = query.Where(o => o.DeliveryStatus == request.Status.Value);
|
||||
}
|
||||
|
||||
if (request.UserId.HasValue)
|
||||
{
|
||||
query = query.Where(o => o.UserId == request.UserId.Value);
|
||||
}
|
||||
|
||||
var totalCount = await query.CountAsync(cancellationToken);
|
||||
|
||||
var response = new GetOrdersByDateRangeResponseDto
|
||||
{
|
||||
MetaData = new MetaData
|
||||
{
|
||||
CurrentPage = request.PageIndex,
|
||||
TotalPage = totalCount == 0 ? 0 : (int)Math.Ceiling(totalCount / (double)request.PageSize),
|
||||
PageSize = request.PageSize,
|
||||
TotalCount = totalCount,
|
||||
HasNext = totalCount > 0 && request.PageIndex * request.PageSize < totalCount,
|
||||
HasPrevious = request.PageIndex > 1
|
||||
}
|
||||
};
|
||||
|
||||
if (totalCount == 0)
|
||||
{
|
||||
return response;
|
||||
}
|
||||
|
||||
var orders = await query
|
||||
.OrderByDescending(o => o.Created)
|
||||
.Skip((request.PageIndex - 1) * request.PageSize)
|
||||
.Take(request.PageSize)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
response.Orders = orders.Select(o =>
|
||||
{
|
||||
var firstName = o.User?.FirstName ?? string.Empty;
|
||||
var lastName = o.User?.LastName ?? string.Empty;
|
||||
var fullName = $"{firstName} {lastName}".Trim();
|
||||
|
||||
return new OrderSummaryDto
|
||||
{
|
||||
Id = o.Id,
|
||||
UserId = o.UserId,
|
||||
UserFullName = fullName,
|
||||
Amount = o.Amount,
|
||||
// در حال حاضر فیلد DiscountedPrice در UserOrder وجود ندارد، پس همان Amount برگردانده میشود
|
||||
DiscountedPrice = o.Amount,
|
||||
Status = o.DeliveryStatus,
|
||||
Created = o.Created,
|
||||
ShippedAt = null,
|
||||
DeliveredAt = null,
|
||||
ItemsCount = o.FactorDetails?.Count ?? 0
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
_logger.LogInformation(
|
||||
"Retrieved {Count} orders for date range {Start} to {End}",
|
||||
response.Orders.Count,
|
||||
request.StartDate,
|
||||
request.EndDate);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange;
|
||||
|
||||
public class GetOrdersByDateRangeQueryValidator : AbstractValidator<GetOrdersByDateRangeQuery>
|
||||
{
|
||||
public GetOrdersByDateRangeQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.StartDate)
|
||||
.LessThanOrEqualTo(x => x.EndDate)
|
||||
.WithMessage("تاریخ شروع باید کوچکتر یا مساوی تاریخ پایان باشد");
|
||||
|
||||
RuleFor(x => x.EndDate)
|
||||
.LessThanOrEqualTo(DateTime.Now.AddDays(1))
|
||||
.WithMessage("تاریخ پایان نمیتواند در آینده باشد");
|
||||
|
||||
RuleFor(x => x.PageIndex)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("شماره صفحه باید بزرگتر از 0 باشد");
|
||||
|
||||
RuleFor(x => x.PageSize)
|
||||
.InclusiveBetween(1, 100)
|
||||
.WithMessage("تعداد در صفحه باید بین 1 تا 100 باشد");
|
||||
|
||||
// بازه زمانی نباید بیش از 1 سال باشد
|
||||
RuleFor(x => x)
|
||||
.Must(x => (x.EndDate - x.StartDate).TotalDays <= 365)
|
||||
.WithMessage("بازه زمانی نمیتواند بیش از 1 سال باشد");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder;
|
||||
public record GetUserOrderQuery : IRequest<GetUserOrderResponseDto>
|
||||
{
|
||||
//شناسه
|
||||
public long Id { get; init; }
|
||||
|
||||
}
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder;
|
||||
public class GetUserOrderQueryHandler : IRequestHandler<GetUserOrderQuery, GetUserOrderResponseDto>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
|
||||
public GetUserOrderQueryHandler(IApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetUserOrderResponseDto> Handle(GetUserOrderQuery request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.UserOrders
|
||||
.Include(i => i.UserAddress)
|
||||
.Include(i => i.User)
|
||||
.Include(i => i.FactorDetails)
|
||||
.ThenInclude(t => t.Product)
|
||||
.Include(i => i.OrderVAT)
|
||||
.AsNoTracking()
|
||||
.Where(x => x.Id == request.Id)
|
||||
.Select(x => new GetUserOrderResponseDto
|
||||
{
|
||||
Id = x.Id,
|
||||
Amount = x.Amount,
|
||||
PackageId = x.PackageId ?? 0,
|
||||
TransactionId = x.TransactionId,
|
||||
PaymentStatus = x.PaymentStatus,
|
||||
PaymentDate = x.PaymentDate,
|
||||
UserId = x.UserId,
|
||||
UserAddressId = x.UserAddressId,
|
||||
PaymentMethod = x.PaymentMethod,
|
||||
UserAddressText = x.UserAddress.Address,
|
||||
FactorDetails = x.FactorDetails.Select(fd => new GetUserOrderResponseFactorDetail
|
||||
{
|
||||
ProductId = fd.ProductId,
|
||||
ProductTitle = fd.Product.Title,
|
||||
ProductThumbnailPath = fd.Product.ThumbnailPath,
|
||||
UnitPrice = fd.UnitPrice,
|
||||
Count = fd.Count,
|
||||
UnitDiscountPrice = fd.UnitDiscountPrice
|
||||
}).ToList(),
|
||||
DeliveryStatus = x.DeliveryStatus,
|
||||
TrackingCode = x.TrackingCode,
|
||||
DeliveryDescription = x.DeliveryDescription,
|
||||
UserFullName = (x.User.FirstName ?? string.Empty) + " " + (x.User.LastName ?? string.Empty),
|
||||
UserNationalCode = x.User.NationalCode,
|
||||
VatInfo = x.OrderVAT != null ? new OrderVATInfoDto
|
||||
{
|
||||
VatRate = x.OrderVAT.VATRate,
|
||||
BaseAmount = x.OrderVAT.BaseAmount,
|
||||
VatAmount = x.OrderVAT.VATAmount,
|
||||
TotalAmount = x.OrderVAT.TotalAmount,
|
||||
IsPaid = x.OrderVAT.IsPaid
|
||||
} : null
|
||||
})
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
return response ?? throw new NotFoundException(nameof(UserOrder), request.Id);
|
||||
}
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder;
|
||||
public class GetUserOrderQueryValidator : AbstractValidator<GetUserOrderQuery>
|
||||
{
|
||||
public GetUserOrderQueryValidator()
|
||||
{
|
||||
RuleFor(model => model.Id)
|
||||
.NotNull();
|
||||
}
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(ValidationContext<GetUserOrderQuery>.CreateWithOptions((GetUserOrderQuery)model, x => x.IncludeProperties(propertyName)));
|
||||
if (result.IsValid)
|
||||
return Array.Empty<string>();
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
using CMSMicroservice.Domain.Enums;
|
||||
|
||||
namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder;
|
||||
public class GetUserOrderResponseDto
|
||||
{
|
||||
//شناسه
|
||||
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<GetUserOrderResponseFactorDetail>? FactorDetails { get; set; }
|
||||
// وضعیت ارسال سفارش
|
||||
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 OrderVATInfoDto? VatInfo { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// اطلاعات مالیات بر ارزش افزوده
|
||||
/// </summary>
|
||||
public class OrderVATInfoDto
|
||||
{
|
||||
/// <summary>
|
||||
/// نرخ مالیات (مثلاً 0.09 = 9%)
|
||||
/// </summary>
|
||||
public decimal VatRate { get; set; }
|
||||
/// <summary>
|
||||
/// مبلغ پایه (قبل از مالیات)
|
||||
/// </summary>
|
||||
public long BaseAmount { get; set; }
|
||||
/// <summary>
|
||||
/// مبلغ مالیات
|
||||
/// </summary>
|
||||
public long VatAmount { get; set; }
|
||||
/// <summary>
|
||||
/// مبلغ کل (پایه + مالیات)
|
||||
/// </summary>
|
||||
public long TotalAmount { get; set; }
|
||||
/// <summary>
|
||||
/// آیا پرداخت شده
|
||||
/// </summary>
|
||||
public bool IsPaid { get; set; }
|
||||
}
|
||||
|
||||
public class GetUserOrderResponseFactorDetail
|
||||
{
|
||||
//شناسه
|
||||
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