feat: Implement Discount Product and Shopping Cart functionalities
- Added UpdateDiscountProductCommandValidator for validating discount product updates. - Created GetDiscountProductByIdQuery and its handler for retrieving discount product details by ID. - Implemented GetDiscountProductsQuery and handler for fetching a list of discount products with filtering options. - Developed AddToCartCommand and handler for adding products to the shopping cart. - Implemented ClearCartCommand and handler for clearing the shopping cart. - Created RemoveFromCartCommand and handler for removing items from the cart. - Added UpdateCartItemCountCommand and handler for updating the quantity of items in the cart. - Developed GetUserCartQuery and handler for retrieving the user's shopping cart details. - Implemented Product Tag functionalities including assigning tags to products, creating, updating, and deleting tags. - Added queries for fetching all tags and products by tag.
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
namespace BackOffice.BFF.Application.CommissionCQ.Queries.GetWithdrawalReports;
|
||||
|
||||
/// <summary>
|
||||
/// گزارش برداشتها بر اساس بازه زمانی و دستهبندی
|
||||
/// </summary>
|
||||
public record GetWithdrawalReportsQuery : IRequest<GetWithdrawalReportsResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// تاریخ شروع (اختیاری - پیشفرض: 30 روز قبل)
|
||||
/// </summary>
|
||||
public DateTime? StartDate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ پایان (اختیاری - پیشفرض: امروز)
|
||||
/// </summary>
|
||||
public DateTime? EndDate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// نوع دوره گزارش: 1=روزانه, 2=هفتگی, 3=ماهانه
|
||||
/// </summary>
|
||||
public ReportPeriodType PeriodType { get; init; } = ReportPeriodType.Daily;
|
||||
|
||||
/// <summary>
|
||||
/// فیلتر وضعیت (اختیاری)
|
||||
/// </summary>
|
||||
public int? Status { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// فیلتر شناسه کاربر (اختیاری)
|
||||
/// </summary>
|
||||
public long? UserId { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// نوع دستهبندی گزارش
|
||||
/// </summary>
|
||||
public enum ReportPeriodType
|
||||
{
|
||||
/// <summary>
|
||||
/// روزانه
|
||||
/// </summary>
|
||||
Daily = 1,
|
||||
|
||||
/// <summary>
|
||||
/// هفتگی
|
||||
/// </summary>
|
||||
Weekly = 2,
|
||||
|
||||
/// <summary>
|
||||
/// ماهانه
|
||||
/// </summary>
|
||||
Monthly = 3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// پاسخ گزارش برداشتها
|
||||
/// </summary>
|
||||
public class GetWithdrawalReportsResponseDto
|
||||
{
|
||||
/// <summary>
|
||||
/// گزارشهای هر دوره
|
||||
/// </summary>
|
||||
public List<PeriodReportDto> PeriodReports { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// خلاصه کل گزارش
|
||||
/// </summary>
|
||||
public WithdrawalSummaryDto Summary { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// گزارش یک دوره زمانی
|
||||
/// </summary>
|
||||
public class PeriodReportDto
|
||||
{
|
||||
/// <summary>
|
||||
/// برچسب دوره (مثلاً "2025-01-15" یا "هفته 3" یا "فروردین 1404")
|
||||
/// </summary>
|
||||
public string PeriodLabel { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ شروع دوره
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ پایان دوره
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد کل درخواستها
|
||||
/// </summary>
|
||||
public int TotalRequests { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد در انتظار
|
||||
/// </summary>
|
||||
public int PendingCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد تایید شده
|
||||
/// </summary>
|
||||
public int ApprovedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد رد شده
|
||||
/// </summary>
|
||||
public int RejectedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد تکمیل شده
|
||||
/// </summary>
|
||||
public int CompletedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد ناموفق
|
||||
/// </summary>
|
||||
public int FailedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کل (ریال)
|
||||
/// </summary>
|
||||
public long TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ پرداخت شده (ریال)
|
||||
/// </summary>
|
||||
public long PaidAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ در انتظار (ریال)
|
||||
/// </summary>
|
||||
public long PendingAmount { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// خلاصه کل گزارش برداشتها
|
||||
/// </summary>
|
||||
public class WithdrawalSummaryDto
|
||||
{
|
||||
/// <summary>
|
||||
/// تعداد کل درخواستها
|
||||
/// </summary>
|
||||
public int TotalRequests { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کل درخواستها (ریال)
|
||||
/// </summary>
|
||||
public long TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کل پرداخت شده (ریال)
|
||||
/// </summary>
|
||||
public long TotalPaid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کل در انتظار (ریال)
|
||||
/// </summary>
|
||||
public long TotalPending { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کل رد شده (ریال)
|
||||
/// </summary>
|
||||
public long TotalRejected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// میانگین مبلغ درخواست (ریال)
|
||||
/// </summary>
|
||||
public long AverageAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد کاربران منحصر به فرد
|
||||
/// </summary>
|
||||
public int UniqueUsers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// درصد موفقیت (0-100)
|
||||
/// </summary>
|
||||
public decimal SuccessRate { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using BackOffice.BFF.Commission.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace BackOffice.BFF.Application.CommissionCQ.Queries.GetWithdrawalReports;
|
||||
|
||||
public class GetWithdrawalReportsQueryHandler : IRequestHandler<GetWithdrawalReportsQuery, GetWithdrawalReportsResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetWithdrawalReportsQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetWithdrawalReportsResponseDto> Handle(GetWithdrawalReportsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var grpcRequest = new GetWithdrawalReportsRequest
|
||||
{
|
||||
PeriodType = (int)request.PeriodType
|
||||
};
|
||||
|
||||
// تنظیم بازه زمانی
|
||||
if (request.StartDate.HasValue)
|
||||
{
|
||||
grpcRequest.StartDate = Timestamp.FromDateTime(request.StartDate.Value.ToUniversalTime());
|
||||
}
|
||||
|
||||
if (request.EndDate.HasValue)
|
||||
{
|
||||
grpcRequest.EndDate = Timestamp.FromDateTime(request.EndDate.Value.ToUniversalTime());
|
||||
}
|
||||
|
||||
// فیلتر وضعیت
|
||||
if (request.Status.HasValue)
|
||||
{
|
||||
grpcRequest.Status = request.Status.Value;
|
||||
}
|
||||
|
||||
// فیلتر کاربر
|
||||
if (request.UserId.HasValue)
|
||||
{
|
||||
grpcRequest.UserId = request.UserId.Value;
|
||||
}
|
||||
|
||||
var response = await _context.Commissions.GetWithdrawalReportsAsync(grpcRequest, cancellationToken: cancellationToken);
|
||||
|
||||
// تبدیل به DTO
|
||||
return new GetWithdrawalReportsResponseDto
|
||||
{
|
||||
PeriodReports = response.PeriodReports.Select(p => new PeriodReportDto
|
||||
{
|
||||
PeriodLabel = p.PeriodLabel,
|
||||
StartDate = p.StartDate.ToDateTime(),
|
||||
EndDate = p.EndDate.ToDateTime(),
|
||||
TotalRequests = p.TotalRequests,
|
||||
PendingCount = p.PendingCount,
|
||||
ApprovedCount = p.ApprovedCount,
|
||||
RejectedCount = p.RejectedCount,
|
||||
CompletedCount = p.CompletedCount,
|
||||
FailedCount = p.FailedCount,
|
||||
TotalAmount = p.TotalAmount,
|
||||
PaidAmount = p.PaidAmount,
|
||||
PendingAmount = p.PendingAmount
|
||||
}).ToList(),
|
||||
Summary = new WithdrawalSummaryDto
|
||||
{
|
||||
TotalRequests = response.Summary.TotalRequests,
|
||||
TotalAmount = response.Summary.TotalAmount,
|
||||
TotalPaid = response.Summary.TotalPaid,
|
||||
TotalPending = response.Summary.TotalPending,
|
||||
TotalRejected = response.Summary.TotalRejected,
|
||||
AverageAmount = response.Summary.AverageAmount,
|
||||
UniqueUsers = response.Summary.UniqueUsers,
|
||||
SuccessRate = (decimal)response.Summary.SuccessRate
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,20 @@ using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||
using CMSMicroservice.Protobuf.Protos.UserRole;
|
||||
using CMSMicroservice.Protobuf.Protos.Products;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
|
||||
using CMSMicroservice.Protobuf.Protos.Category;
|
||||
using CMSMicroservice.Protobuf.Protos.PruductCategory;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductCategory;
|
||||
using BackOffice.BFF.Commission.Protobuf;
|
||||
using BackOffice.BFF.NetworkMembership.Protobuf;
|
||||
using BackOffice.BFF.ClubMembership.Protobuf;
|
||||
using BackOffice.BFF.Configuration.Protobuf;
|
||||
using FMSMicroservice.Protobuf.Protos.FileInfo;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountCategory;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductTag;
|
||||
|
||||
namespace BackOffice.BFF.Application.Common.Interfaces;
|
||||
|
||||
@@ -26,10 +32,10 @@ public interface IApplicationContractContext
|
||||
PackageContract.PackageContractClient Packages { get; }
|
||||
ProductsContract.ProductsContractClient Products { get; }
|
||||
ProductImagesContract.ProductImagesContractClient ProductImages { get; }
|
||||
ProductGallerysContract.ProductGallerysContractClient ProductGallerys { get; }
|
||||
ProductGalleriesContract.ProductGalleriesContractClient ProductGalleries { get; }
|
||||
RoleContract.RoleContractClient Roles { get; }
|
||||
CategoryContract.CategoryContractClient Categories { get; }
|
||||
PruductCategoryContract.PruductCategoryContractClient ProductCategories { get; }
|
||||
ProductCategoryContract.ProductCategoryContractClient ProductCategories { get; }
|
||||
UserAddressContract.UserAddressContractClient UserAddress { get; }
|
||||
UserContract.UserContractClient Users { get; }
|
||||
UserOrderContract.UserOrderContractClient UserOrders { get; }
|
||||
@@ -40,6 +46,16 @@ public interface IApplicationContractContext
|
||||
NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships { get; }
|
||||
ClubMembershipContract.ClubMembershipContractClient ClubMemberships { get; }
|
||||
ConfigurationContract.ConfigurationContractClient Configurations { get; }
|
||||
|
||||
// Discount Shop System (Phase 9)
|
||||
DiscountProductContract.DiscountProductContractClient DiscountProducts { get; }
|
||||
DiscountCategoryContract.DiscountCategoryContractClient DiscountCategories { get; }
|
||||
DiscountShoppingCartContract.DiscountShoppingCartContractClient DiscountShoppingCarts { get; }
|
||||
DiscountOrderContract.DiscountOrderContractClient DiscountOrders { get; }
|
||||
|
||||
// Tag Management System
|
||||
TagContract.TagContractClient Tags { get; }
|
||||
ProductTagContract.ProductTagContractClient ProductTags { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Commands.CreateDiscountCategory;
|
||||
|
||||
public record CreateDiscountCategoryCommand : IRequest<CreateDiscountCategoryResponseDto>
|
||||
{
|
||||
/// <summary>نام دستهبندی (انگلیسی)</summary>
|
||||
public string Name { get; init; }
|
||||
|
||||
/// <summary>عنوان دستهبندی (فارسی)</summary>
|
||||
public string Title { get; init; }
|
||||
|
||||
/// <summary>توضیحات دستهبندی</summary>
|
||||
public string Description { get; init; }
|
||||
|
||||
/// <summary>شناسه دستهبندی والد (null برای دسته اصلی)</summary>
|
||||
public long? ParentCategoryId { get; init; }
|
||||
|
||||
/// <summary>ترتیب نمایش</summary>
|
||||
public int SortOrder { get; init; }
|
||||
|
||||
/// <summary>وضعیت فعال/غیرفعال</summary>
|
||||
public bool IsActive { get; init; }
|
||||
|
||||
/// <summary>فایل تصویر دستهبندی</summary>
|
||||
public DiscountCategoryFileModel ImageFile { get; init; }
|
||||
}
|
||||
|
||||
public class DiscountCategoryFileModel
|
||||
{
|
||||
/// <summary>فایل</summary>
|
||||
public byte[] File { get; set; }
|
||||
|
||||
/// <summary>نام فایل</summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>نوع فایل</summary>
|
||||
public string Mime { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountCategory;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Commands.CreateDiscountCategory;
|
||||
|
||||
public class CreateDiscountCategoryCommandHandler : IRequestHandler<CreateDiscountCategoryCommand, CreateDiscountCategoryResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public CreateDiscountCategoryCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<CreateDiscountCategoryResponseDto> Handle(CreateDiscountCategoryCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var createRequest = new CreateDiscountCategoryRequest
|
||||
{
|
||||
Name = request.Name,
|
||||
Title = request.Title,
|
||||
Description = request.Description ?? string.Empty,
|
||||
SortOrder = request.SortOrder,
|
||||
IsActive = request.IsActive
|
||||
};
|
||||
|
||||
if (request.ParentCategoryId.HasValue)
|
||||
createRequest.ParentCategoryId = new Int64Value { Value = request.ParentCategoryId.Value };
|
||||
|
||||
// Upload Image
|
||||
if (request.ImageFile != null && request.ImageFile.File != null && request.ImageFile.File.Length > 0)
|
||||
{
|
||||
var imageFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
|
||||
{
|
||||
Directory = "Images/DiscountShop/Categories",
|
||||
IsBase64 = false,
|
||||
MIME = request.ImageFile.Mime,
|
||||
FileName = request.ImageFile.FileName,
|
||||
File = ByteString.CopyFrom(request.ImageFile.File)
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
if (imageFileInfo != null && !string.IsNullOrWhiteSpace(imageFileInfo.File))
|
||||
createRequest.ImagePath = imageFileInfo.File;
|
||||
}
|
||||
|
||||
var response = await _context.DiscountCategories.CreateDiscountCategoryAsync(createRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new CreateDiscountCategoryResponseDto
|
||||
{
|
||||
CategoryId = response.CategoryId
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Commands.CreateDiscountCategory;
|
||||
|
||||
public class CreateDiscountCategoryCommandValidator : AbstractValidator<CreateDiscountCategoryCommand>
|
||||
{
|
||||
public CreateDiscountCategoryCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty().WithMessage("نام دستهبندی الزامی است")
|
||||
.MaximumLength(100).WithMessage("نام دستهبندی نباید بیشتر از 100 کاراکتر باشد")
|
||||
.Matches("^[a-zA-Z0-9_-]+$").WithMessage("نام دستهبندی فقط باید شامل حروف انگلیسی، اعداد، خط تیره و زیرخط باشد");
|
||||
|
||||
RuleFor(x => x.Title)
|
||||
.NotEmpty().WithMessage("عنوان دستهبندی الزامی است")
|
||||
.MaximumLength(200).WithMessage("عنوان دستهبندی نباید بیشتر از 200 کاراکتر باشد");
|
||||
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(1000).WithMessage("توضیحات نباید بیشتر از 1000 کاراکتر باشد");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Commands.CreateDiscountCategory;
|
||||
|
||||
public class CreateDiscountCategoryResponseDto
|
||||
{
|
||||
/// <summary>شناسه دستهبندی ایجاد شده</summary>
|
||||
public long CategoryId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Commands.DeleteDiscountCategory;
|
||||
|
||||
public record DeleteDiscountCategoryCommand : IRequest
|
||||
{
|
||||
/// <summary>شناسه دستهبندی</summary>
|
||||
public long CategoryId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountCategory;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Commands.DeleteDiscountCategory;
|
||||
|
||||
public class DeleteDiscountCategoryCommandHandler : IRequestHandler<DeleteDiscountCategoryCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public DeleteDiscountCategoryCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(DeleteDiscountCategoryCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.DiscountCategories.DeleteDiscountCategoryAsync(
|
||||
new DeleteDiscountCategoryRequest { CategoryId = request.CategoryId },
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Commands.DeleteDiscountCategory;
|
||||
|
||||
public class DeleteDiscountCategoryCommandValidator : AbstractValidator<DeleteDiscountCategoryCommand>
|
||||
{
|
||||
public DeleteDiscountCategoryCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.CategoryId)
|
||||
.GreaterThan(0).WithMessage("شناسه دستهبندی نامعتبر است");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Commands.UpdateDiscountCategory;
|
||||
|
||||
public record UpdateDiscountCategoryCommand : IRequest
|
||||
{
|
||||
/// <summary>شناسه دستهبندی</summary>
|
||||
public long CategoryId { get; init; }
|
||||
|
||||
/// <summary>نام دستهبندی (انگلیسی)</summary>
|
||||
public string Name { get; init; }
|
||||
|
||||
/// <summary>عنوان دستهبندی (فارسی)</summary>
|
||||
public string Title { get; init; }
|
||||
|
||||
/// <summary>توضیحات دستهبندی</summary>
|
||||
public string Description { get; init; }
|
||||
|
||||
/// <summary>شناسه دستهبندی والد (null برای دسته اصلی)</summary>
|
||||
public long? ParentCategoryId { get; init; }
|
||||
|
||||
/// <summary>ترتیب نمایش</summary>
|
||||
public int SortOrder { get; init; }
|
||||
|
||||
/// <summary>وضعیت فعال/غیرفعال</summary>
|
||||
public bool IsActive { get; init; }
|
||||
|
||||
/// <summary>فایل تصویر دستهبندی (اختیاری - برای تغییر تصویر)</summary>
|
||||
public DiscountCategoryFileModel ImageFile { get; init; }
|
||||
}
|
||||
|
||||
public class DiscountCategoryFileModel
|
||||
{
|
||||
/// <summary>فایل</summary>
|
||||
public byte[] File { get; set; }
|
||||
|
||||
/// <summary>نام فایل</summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>نوع فایل</summary>
|
||||
public string Mime { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountCategory;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Commands.UpdateDiscountCategory;
|
||||
|
||||
public class UpdateDiscountCategoryCommandHandler : IRequestHandler<UpdateDiscountCategoryCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public UpdateDiscountCategoryCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(UpdateDiscountCategoryCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var updateRequest = new UpdateDiscountCategoryRequest
|
||||
{
|
||||
CategoryId = request.CategoryId,
|
||||
Name = request.Name,
|
||||
Title = request.Title,
|
||||
Description = request.Description ?? string.Empty,
|
||||
SortOrder = request.SortOrder,
|
||||
IsActive = request.IsActive
|
||||
};
|
||||
|
||||
if (request.ParentCategoryId.HasValue)
|
||||
updateRequest.ParentCategoryId = new Int64Value { Value = request.ParentCategoryId.Value };
|
||||
|
||||
// Upload new Image if provided
|
||||
if (request.ImageFile != null && request.ImageFile.File != null && request.ImageFile.File.Length > 0)
|
||||
{
|
||||
var imageFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
|
||||
{
|
||||
Directory = "Images/DiscountShop/Categories",
|
||||
IsBase64 = false,
|
||||
MIME = request.ImageFile.Mime,
|
||||
FileName = request.ImageFile.FileName,
|
||||
File = ByteString.CopyFrom(request.ImageFile.File)
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
if (imageFileInfo != null && !string.IsNullOrWhiteSpace(imageFileInfo.File))
|
||||
updateRequest.ImagePath = imageFileInfo.File;
|
||||
}
|
||||
|
||||
await _context.DiscountCategories.UpdateDiscountCategoryAsync(updateRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Commands.UpdateDiscountCategory;
|
||||
|
||||
public class UpdateDiscountCategoryCommandValidator : AbstractValidator<UpdateDiscountCategoryCommand>
|
||||
{
|
||||
public UpdateDiscountCategoryCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.CategoryId)
|
||||
.GreaterThan(0).WithMessage("شناسه دستهبندی نامعتبر است");
|
||||
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty().WithMessage("نام دستهبندی الزامی است")
|
||||
.MaximumLength(100).WithMessage("نام دستهبندی نباید بیشتر از 100 کاراکتر باشد")
|
||||
.Matches("^[a-zA-Z0-9_-]+$").WithMessage("نام دستهبندی فقط باید شامل حروف انگلیسی، اعداد، خط تیره و زیرخط باشد");
|
||||
|
||||
RuleFor(x => x.Title)
|
||||
.NotEmpty().WithMessage("عنوان دستهبندی الزامی است")
|
||||
.MaximumLength(200).WithMessage("عنوان دستهبندی نباید بیشتر از 200 کاراکتر باشد");
|
||||
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(1000).WithMessage("توضیحات نباید بیشتر از 1000 کاراکتر باشد");
|
||||
|
||||
RuleFor(x => x.ParentCategoryId)
|
||||
.NotEqual(x => x.CategoryId).When(x => x.ParentCategoryId.HasValue)
|
||||
.WithMessage("دستهبندی نمیتواند والد خودش باشد");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Queries.GetDiscountCategories;
|
||||
|
||||
public record GetDiscountCategoriesQuery : IRequest<GetDiscountCategoriesResponseDto>
|
||||
{
|
||||
/// <summary>فیلتر براساس دسته والد (null برای ریشه)</summary>
|
||||
public long? ParentCategoryId { get; init; }
|
||||
|
||||
/// <summary>فقط دستههای فعال</summary>
|
||||
public bool? IsActive { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountCategory;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Queries.GetDiscountCategories;
|
||||
|
||||
public class GetDiscountCategoriesQueryHandler : IRequestHandler<GetDiscountCategoriesQuery, GetDiscountCategoriesResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetDiscountCategoriesQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetDiscountCategoriesResponseDto> Handle(GetDiscountCategoriesQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var grpcRequest = new GetDiscountCategoriesRequest();
|
||||
|
||||
if (request.ParentCategoryId.HasValue)
|
||||
grpcRequest.ParentCategoryId = new Int64Value { Value = request.ParentCategoryId.Value };
|
||||
|
||||
if (request.IsActive.HasValue)
|
||||
grpcRequest.IsActive = new BoolValue { Value = request.IsActive.Value };
|
||||
|
||||
var response = await _context.DiscountCategories.GetDiscountCategoriesAsync(grpcRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new GetDiscountCategoriesResponseDto
|
||||
{
|
||||
Categories = response.Categories.Select(MapCategory).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
private DiscountCategoryTreeDto MapCategory(DiscountCategoryDto node)
|
||||
{
|
||||
return new DiscountCategoryTreeDto
|
||||
{
|
||||
Id = node.Id,
|
||||
Name = node.Name,
|
||||
Title = node.Title,
|
||||
Description = node.HasDescription ? node.Description.Value : string.Empty,
|
||||
ImagePath = node.HasImagePath ? node.ImagePath.Value : string.Empty,
|
||||
ParentCategoryId = node.HasParentCategoryId ? node.ParentCategoryId.Value : null,
|
||||
SortOrder = node.SortOrder,
|
||||
IsActive = node.IsActive,
|
||||
ProductCount = node.ProductCount,
|
||||
Created = DateTime.UtcNow, // Proto doesn't have created field
|
||||
ChildCategories = node.Children.Select(MapCategory).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace BackOffice.BFF.Application.DiscountCategoryCQ.Queries.GetDiscountCategories;
|
||||
|
||||
public class GetDiscountCategoriesResponseDto
|
||||
{
|
||||
/// <summary>لیست درختی دستهبندیها</summary>
|
||||
public List<DiscountCategoryTreeDto> Categories { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DiscountCategoryTreeDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string ImagePath { get; set; }
|
||||
public long? ParentCategoryId { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public int ProductCount { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
|
||||
/// <summary>زیردستههای این دستهبندی</summary>
|
||||
public List<DiscountCategoryTreeDto> ChildCategories { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Commands.CompleteOrderPayment;
|
||||
|
||||
public record CompleteOrderPaymentCommand : IRequest
|
||||
{
|
||||
/// <summary>شناسه سفارش</summary>
|
||||
public long OrderId { get; init; }
|
||||
|
||||
/// <summary>کد تراکنش پرداخت</summary>
|
||||
public string PaymentTransactionCode { get; init; }
|
||||
|
||||
/// <summary>مبلغ پرداخت شده</summary>
|
||||
public long PaidAmount { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Commands.CompleteOrderPayment;
|
||||
|
||||
public class CompleteOrderPaymentCommandHandler : IRequestHandler<CompleteOrderPaymentCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public CompleteOrderPaymentCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(CompleteOrderPaymentCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.DiscountOrders.CompleteOrderPaymentAsync(
|
||||
new CompleteOrderPaymentRequest
|
||||
{
|
||||
OrderId = request.OrderId,
|
||||
PaymentTransactionCode = request.PaymentTransactionCode,
|
||||
PaidAmount = request.PaidAmount
|
||||
},
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Commands.CompleteOrderPayment;
|
||||
|
||||
public class CompleteOrderPaymentCommandValidator : AbstractValidator<CompleteOrderPaymentCommand>
|
||||
{
|
||||
public CompleteOrderPaymentCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.OrderId)
|
||||
.GreaterThan(0).WithMessage("شناسه سفارش نامعتبر است");
|
||||
|
||||
RuleFor(x => x.PaymentTransactionCode)
|
||||
.NotEmpty().WithMessage("کد تراکنش پرداخت الزامی است");
|
||||
|
||||
RuleFor(x => x.PaidAmount)
|
||||
.GreaterThan(0).WithMessage("مبلغ پرداخت شده باید بیشتر از صفر باشد");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Commands.PlaceOrder;
|
||||
|
||||
public record PlaceOrderCommand : IRequest<PlaceOrderResponseDto>
|
||||
{
|
||||
/// <summary>شناسه کاربر</summary>
|
||||
public long UserId { get; init; }
|
||||
|
||||
/// <summary>شناسه آدرس ارسال</summary>
|
||||
public long AddressId { get; init; }
|
||||
|
||||
/// <summary>مبلغ پرداخت از موجودی تخفیف</summary>
|
||||
public long DiscountBalanceAmount { get; init; }
|
||||
|
||||
/// <summary>مبلغ پرداخت از درگاه</summary>
|
||||
public long GatewayAmount { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Commands.PlaceOrder;
|
||||
|
||||
public class PlaceOrderCommandHandler : IRequestHandler<PlaceOrderCommand, PlaceOrderResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public PlaceOrderCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<PlaceOrderResponseDto> Handle(PlaceOrderCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.DiscountOrders.PlaceOrderAsync(
|
||||
new PlaceOrderRequest
|
||||
{
|
||||
UserId = request.UserId,
|
||||
AddressId = request.AddressId,
|
||||
DiscountBalanceAmount = request.DiscountBalanceAmount,
|
||||
GatewayAmount = request.GatewayAmount
|
||||
},
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return new PlaceOrderResponseDto
|
||||
{
|
||||
OrderId = response.OrderId,
|
||||
TrackingCode = response.TrackingCode,
|
||||
RequiresGatewayPayment = response.RequiresGatewayPayment,
|
||||
GatewayPayableAmount = response.GatewayPayableAmount
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Commands.PlaceOrder;
|
||||
|
||||
public class PlaceOrderCommandValidator : AbstractValidator<PlaceOrderCommand>
|
||||
{
|
||||
public PlaceOrderCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.UserId)
|
||||
.GreaterThan(0).WithMessage("شناسه کاربر نامعتبر است");
|
||||
|
||||
RuleFor(x => x.AddressId)
|
||||
.GreaterThan(0).WithMessage("شناسه آدرس نامعتبر است");
|
||||
|
||||
RuleFor(x => x.DiscountBalanceAmount)
|
||||
.GreaterThanOrEqualTo(0).WithMessage("مبلغ موجودی تخفیف نمیتواند منفی باشد");
|
||||
|
||||
RuleFor(x => x.GatewayAmount)
|
||||
.GreaterThanOrEqualTo(0).WithMessage("مبلغ درگاه نمیتواند منفی باشد");
|
||||
|
||||
RuleFor(x => x)
|
||||
.Must(x => x.DiscountBalanceAmount + x.GatewayAmount > 0)
|
||||
.WithMessage("مجموع مبالغ پرداخت باید بیشتر از صفر باشد");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Commands.PlaceOrder;
|
||||
|
||||
public class PlaceOrderResponseDto
|
||||
{
|
||||
/// <summary>شناسه سفارش</summary>
|
||||
public long OrderId { get; set; }
|
||||
|
||||
/// <summary>کد پیگیری سفارش</summary>
|
||||
public string TrackingCode { get; set; }
|
||||
|
||||
/// <summary>آیا نیاز به پرداخت از درگاه دارد</summary>
|
||||
public bool RequiresGatewayPayment { get; set; }
|
||||
|
||||
/// <summary>مبلغ قابل پرداخت از درگاه</summary>
|
||||
public long GatewayPayableAmount { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Commands.UpdateOrderStatus;
|
||||
|
||||
public record UpdateOrderStatusCommand : IRequest
|
||||
{
|
||||
/// <summary>شناسه سفارش</summary>
|
||||
public long OrderId { get; init; }
|
||||
|
||||
/// <summary>وضعیت جدید</summary>
|
||||
public int NewStatus { get; init; }
|
||||
|
||||
/// <summary>یادداشت مدیر (اختیاری)</summary>
|
||||
public string AdminNote { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Commands.UpdateOrderStatus;
|
||||
|
||||
public class UpdateOrderStatusCommandHandler : IRequestHandler<UpdateOrderStatusCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public UpdateOrderStatusCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(UpdateOrderStatusCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.DiscountOrders.UpdateOrderStatusAsync(
|
||||
new UpdateOrderStatusRequest
|
||||
{
|
||||
OrderId = request.OrderId,
|
||||
NewStatus = request.NewStatus,
|
||||
AdminNote = request.AdminNote ?? string.Empty
|
||||
},
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Commands.UpdateOrderStatus;
|
||||
|
||||
public class UpdateOrderStatusCommandValidator : AbstractValidator<UpdateOrderStatusCommand>
|
||||
{
|
||||
public UpdateOrderStatusCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.OrderId)
|
||||
.GreaterThan(0).WithMessage("شناسه سفارش نامعتبر است");
|
||||
|
||||
RuleFor(x => x.NewStatus)
|
||||
.InclusiveBetween(0, 6).WithMessage("وضعیت سفارش نامعتبر است");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetOrderById;
|
||||
|
||||
public record GetOrderByIdQuery : IRequest<GetOrderByIdResponseDto>
|
||||
{
|
||||
/// <summary>شناسه سفارش</summary>
|
||||
public long OrderId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetOrderById;
|
||||
|
||||
public class GetOrderByIdQueryHandler : IRequestHandler<GetOrderByIdQuery, GetOrderByIdResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetOrderByIdQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetOrderByIdResponseDto> Handle(GetOrderByIdQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.DiscountOrders.GetOrderByIdAsync(
|
||||
new GetOrderByIdRequest { OrderId = request.OrderId },
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return new GetOrderByIdResponseDto
|
||||
{
|
||||
Id = response.Id,
|
||||
UserId = response.UserId,
|
||||
TrackingCode = response.TrackingCode,
|
||||
Status = response.Status,
|
||||
StatusTitle = response.StatusTitle,
|
||||
TotalPrice = response.TotalPrice,
|
||||
DiscountBalanceUsed = response.DiscountBalanceUsed,
|
||||
GatewayPayment = response.GatewayPayment,
|
||||
FinalPrice = response.FinalPrice,
|
||||
PaymentTransactionCode = response.PaymentTransactionCode,
|
||||
AdminNote = response.AdminNote,
|
||||
CreatedAt = response.CreatedAt.ToDateTime(),
|
||||
PaidAt = response.HasPaidAt ? response.PaidAt.ToDateTime() : null,
|
||||
ShippingAddress = new AddressInfoDto
|
||||
{
|
||||
Id = response.ShippingAddress.Id,
|
||||
RecipientName = response.ShippingAddress.RecipientName,
|
||||
RecipientPhone = response.ShippingAddress.RecipientPhone,
|
||||
Province = response.ShippingAddress.Province,
|
||||
City = response.ShippingAddress.City,
|
||||
PostalCode = response.ShippingAddress.PostalCode,
|
||||
FullAddress = response.ShippingAddress.FullAddress
|
||||
},
|
||||
Items = response.Items.Select(item => new OrderItemDto
|
||||
{
|
||||
Id = item.Id,
|
||||
ProductId = item.ProductId,
|
||||
ProductTitle = item.ProductTitle,
|
||||
UnitPrice = item.UnitPrice,
|
||||
DiscountPercent = item.DiscountPercent,
|
||||
Quantity = item.Quantity,
|
||||
TotalPrice = item.TotalPrice,
|
||||
DiscountedPrice = item.DiscountedPrice
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetOrderById;
|
||||
|
||||
public class GetOrderByIdQueryValidator : AbstractValidator<GetOrderByIdQuery>
|
||||
{
|
||||
public GetOrderByIdQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.OrderId)
|
||||
.GreaterThan(0).WithMessage("شناسه سفارش نامعتبر است");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetOrderById;
|
||||
|
||||
public class GetOrderByIdResponseDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long UserId { get; set; }
|
||||
public string TrackingCode { get; set; }
|
||||
public int Status { get; set; }
|
||||
public string StatusTitle { get; set; }
|
||||
public long TotalPrice { get; set; }
|
||||
public long DiscountBalanceUsed { get; set; }
|
||||
public long GatewayPayment { get; set; }
|
||||
public long FinalPrice { get; set; }
|
||||
public string PaymentTransactionCode { get; set; }
|
||||
public string AdminNote { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime? PaidAt { get; set; }
|
||||
|
||||
public AddressInfoDto ShippingAddress { get; set; }
|
||||
public List<OrderItemDto> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public class AddressInfoDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string RecipientName { get; set; }
|
||||
public string RecipientPhone { get; set; }
|
||||
public string Province { get; set; }
|
||||
public string City { get; set; }
|
||||
public string PostalCode { get; set; }
|
||||
public string FullAddress { get; set; }
|
||||
}
|
||||
|
||||
public class OrderItemDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long ProductId { get; set; }
|
||||
public string ProductTitle { get; set; }
|
||||
public long UnitPrice { get; set; }
|
||||
public int DiscountPercent { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public long TotalPrice { get; set; }
|
||||
public long DiscountedPrice { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetUserOrders;
|
||||
|
||||
public record GetUserOrdersQuery : IRequest<GetUserOrdersResponseDto>
|
||||
{
|
||||
/// <summary>شناسه کاربر</summary>
|
||||
public long UserId { get; init; }
|
||||
|
||||
/// <summary>فیلتر براساس وضعیت سفارش</summary>
|
||||
public int? Status { get; init; }
|
||||
|
||||
/// <summary>شماره صفحه</summary>
|
||||
public int PageNumber { get; init; } = 1;
|
||||
|
||||
/// <summary>تعداد در هر صفحه</summary>
|
||||
public int PageSize { get; init; } = 20;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using BackOffice.BFF.Application.Common.Models;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetUserOrders;
|
||||
|
||||
public class GetUserOrdersQueryHandler : IRequestHandler<GetUserOrdersQuery, GetUserOrdersResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetUserOrdersQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetUserOrdersResponseDto> Handle(GetUserOrdersQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var grpcRequest = new GetUserOrdersRequest
|
||||
{
|
||||
UserId = request.UserId,
|
||||
PageNumber = request.PageNumber,
|
||||
PageSize = request.PageSize
|
||||
};
|
||||
|
||||
if (request.Status.HasValue)
|
||||
grpcRequest.Status = new Int32Value { Value = request.Status.Value };
|
||||
|
||||
var response = await _context.DiscountOrders.GetUserOrdersAsync(grpcRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new GetUserOrdersResponseDto
|
||||
{
|
||||
MetaData = new MetaData
|
||||
{
|
||||
CurrentPage = response.MetaData.CurrentPage,
|
||||
TotalPage = response.MetaData.TotalPages,
|
||||
PageSize = response.MetaData.PageSize,
|
||||
TotalCount = response.MetaData.TotalCount,
|
||||
HasPrevious = response.MetaData.HasPrevious,
|
||||
HasNext = response.MetaData.HasNext
|
||||
},
|
||||
Orders = response.Orders.Select(order => new UserOrderDto
|
||||
{
|
||||
Id = order.Id,
|
||||
TrackingCode = order.TrackingCode,
|
||||
Status = order.Status,
|
||||
StatusTitle = order.StatusTitle,
|
||||
TotalPrice = order.TotalPrice,
|
||||
FinalPrice = order.FinalPrice,
|
||||
ItemCount = order.ItemCount,
|
||||
CreatedAt = order.CreatedAt.ToDateTime()
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetUserOrders;
|
||||
|
||||
public class GetUserOrdersQueryValidator : AbstractValidator<GetUserOrdersQuery>
|
||||
{
|
||||
public GetUserOrdersQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.UserId)
|
||||
.GreaterThan(0).WithMessage("شناسه کاربر نامعتبر است");
|
||||
|
||||
RuleFor(x => x.PageNumber)
|
||||
.GreaterThan(0).WithMessage("شماره صفحه باید بیشتر از صفر باشد");
|
||||
|
||||
RuleFor(x => x.PageSize)
|
||||
.GreaterThan(0).WithMessage("تعداد در صفحه باید بیشتر از صفر باشد")
|
||||
.LessThanOrEqualTo(100).WithMessage("حداکثر تعداد در صفحه 100 است");
|
||||
|
||||
RuleFor(x => x.Status)
|
||||
.InclusiveBetween(0, 6).When(x => x.Status.HasValue)
|
||||
.WithMessage("وضعیت سفارش نامعتبر است");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using BackOffice.BFF.Application.Common.Models;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetUserOrders;
|
||||
|
||||
public class GetUserOrdersResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public List<UserOrderDto> Orders { get; set; } = new();
|
||||
}
|
||||
|
||||
public class UserOrderDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string TrackingCode { get; set; }
|
||||
public int Status { get; set; }
|
||||
public string StatusTitle { get; set; }
|
||||
public long TotalPrice { get; set; }
|
||||
public long FinalPrice { get; set; }
|
||||
public int ItemCount { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.CreateDiscountProduct;
|
||||
|
||||
public record CreateDiscountProductCommand : IRequest<CreateDiscountProductResponseDto>
|
||||
{
|
||||
/// <summary>عنوان محصول</summary>
|
||||
public string Title { get; init; }
|
||||
|
||||
/// <summary>اطلاعات کوتاه محصول</summary>
|
||||
public string ShortInformation { get; init; }
|
||||
|
||||
/// <summary>اطلاعات کامل محصول</summary>
|
||||
public string FullInformation { get; init; }
|
||||
|
||||
/// <summary>قیمت محصول</summary>
|
||||
public long Price { get; init; }
|
||||
|
||||
/// <summary>حداکثر درصد تخفیف (0-100)</summary>
|
||||
public int MaxDiscountPercent { get; init; }
|
||||
|
||||
/// <summary>تعداد اولیه موجودی</summary>
|
||||
public int InitialCount { get; init; }
|
||||
|
||||
/// <summary>ترتیب نمایش</summary>
|
||||
public int SortOrder { get; init; }
|
||||
|
||||
/// <summary>وضعیت فعال/غیرفعال</summary>
|
||||
public bool IsActive { get; init; }
|
||||
|
||||
/// <summary>آیدی دستهبندیها</summary>
|
||||
public List<long> CategoryIds { get; init; } = new();
|
||||
|
||||
/// <summary>فایل تصویر اصلی</summary>
|
||||
public DiscountProductFileModel ImageFile { get; init; }
|
||||
|
||||
/// <summary>فایل تصویر کوچک</summary>
|
||||
public DiscountProductFileModel ThumbnailFile { get; init; }
|
||||
}
|
||||
|
||||
public class DiscountProductFileModel
|
||||
{
|
||||
/// <summary>فایل</summary>
|
||||
public byte[] File { get; set; }
|
||||
|
||||
/// <summary>نام فایل</summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>نوع فایل</summary>
|
||||
public string Mime { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.CreateDiscountProduct;
|
||||
|
||||
public class CreateDiscountProductCommandHandler : IRequestHandler<CreateDiscountProductCommand, CreateDiscountProductResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public CreateDiscountProductCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<CreateDiscountProductResponseDto> Handle(CreateDiscountProductCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var createRequest = new CreateDiscountProductRequest
|
||||
{
|
||||
Title = request.Title,
|
||||
ShortInfomation = request.ShortInformation,
|
||||
FullInformation = request.FullInformation,
|
||||
Price = request.Price,
|
||||
MaxDiscountPercent = request.MaxDiscountPercent,
|
||||
InitialCount = request.InitialCount,
|
||||
SortOrder = request.SortOrder,
|
||||
IsActive = request.IsActive
|
||||
};
|
||||
|
||||
createRequest.CategoryIds.AddRange(request.CategoryIds);
|
||||
|
||||
// Upload Image
|
||||
if (request.ImageFile != null && request.ImageFile.File != null && request.ImageFile.File.Length > 0)
|
||||
{
|
||||
var imageFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
|
||||
{
|
||||
Directory = "Images/DiscountShop/Products",
|
||||
IsBase64 = false,
|
||||
MIME = request.ImageFile.Mime,
|
||||
FileName = request.ImageFile.FileName,
|
||||
File = ByteString.CopyFrom(request.ImageFile.File)
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
if (imageFileInfo != null && !string.IsNullOrWhiteSpace(imageFileInfo.File))
|
||||
createRequest.ImagePath = imageFileInfo.File;
|
||||
}
|
||||
|
||||
// Upload Thumbnail
|
||||
if (request.ThumbnailFile != null && request.ThumbnailFile.File != null && request.ThumbnailFile.File.Length > 0)
|
||||
{
|
||||
var thumbnailFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
|
||||
{
|
||||
Directory = "Images/DiscountShop/Products/Thumbnails",
|
||||
IsBase64 = false,
|
||||
MIME = request.ThumbnailFile.Mime,
|
||||
FileName = request.ThumbnailFile.FileName,
|
||||
File = ByteString.CopyFrom(request.ThumbnailFile.File)
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
if (thumbnailFileInfo != null && !string.IsNullOrWhiteSpace(thumbnailFileInfo.File))
|
||||
createRequest.ThumbnailPath = thumbnailFileInfo.File;
|
||||
}
|
||||
|
||||
var response = await _context.DiscountProducts.CreateDiscountProductAsync(createRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new CreateDiscountProductResponseDto
|
||||
{
|
||||
ProductId = response.ProductId
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.CreateDiscountProduct;
|
||||
|
||||
public class CreateDiscountProductCommandValidator : AbstractValidator<CreateDiscountProductCommand>
|
||||
{
|
||||
public CreateDiscountProductCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.Title)
|
||||
.NotEmpty().WithMessage("عنوان محصول الزامی است")
|
||||
.MaximumLength(200).WithMessage("عنوان محصول نباید بیشتر از 200 کاراکتر باشد");
|
||||
|
||||
RuleFor(x => x.ShortInformation)
|
||||
.NotEmpty().WithMessage("اطلاعات کوتاه محصول الزامی است")
|
||||
.MaximumLength(500).WithMessage("اطلاعات کوتاه نباید بیشتر از 500 کاراکتر باشد");
|
||||
|
||||
RuleFor(x => x.FullInformation)
|
||||
.NotEmpty().WithMessage("اطلاعات کامل محصول الزامی است");
|
||||
|
||||
RuleFor(x => x.Price)
|
||||
.GreaterThan(0).WithMessage("قیمت محصول باید بیشتر از صفر باشد");
|
||||
|
||||
RuleFor(x => x.MaxDiscountPercent)
|
||||
.InclusiveBetween(0, 100).WithMessage("درصد تخفیف باید بین 0 تا 100 باشد");
|
||||
|
||||
RuleFor(x => x.InitialCount)
|
||||
.GreaterThanOrEqualTo(0).WithMessage("تعداد اولیه نمیتواند منفی باشد");
|
||||
|
||||
RuleFor(x => x.CategoryIds)
|
||||
.NotEmpty().WithMessage("حداقل یک دستهبندی باید انتخاب شود");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.CreateDiscountProduct;
|
||||
|
||||
public class CreateDiscountProductResponseDto
|
||||
{
|
||||
/// <summary>شناسه محصول ایجاد شده</summary>
|
||||
public long ProductId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.DeleteDiscountProduct;
|
||||
|
||||
public record DeleteDiscountProductCommand : IRequest
|
||||
{
|
||||
/// <summary>شناسه محصول</summary>
|
||||
public long ProductId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.DeleteDiscountProduct;
|
||||
|
||||
public class DeleteDiscountProductCommandHandler : IRequestHandler<DeleteDiscountProductCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public DeleteDiscountProductCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(DeleteDiscountProductCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.DiscountProducts.DeleteDiscountProductAsync(
|
||||
new DeleteDiscountProductRequest { ProductId = request.ProductId },
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.DeleteDiscountProduct;
|
||||
|
||||
public class DeleteDiscountProductCommandValidator : AbstractValidator<DeleteDiscountProductCommand>
|
||||
{
|
||||
public DeleteDiscountProductCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.ProductId)
|
||||
.GreaterThan(0).WithMessage("شناسه محصول نامعتبر است");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.UpdateDiscountProduct;
|
||||
|
||||
public record UpdateDiscountProductCommand : IRequest
|
||||
{
|
||||
/// <summary>شناسه محصول</summary>
|
||||
public long ProductId { get; init; }
|
||||
|
||||
/// <summary>عنوان محصول</summary>
|
||||
public string Title { get; init; }
|
||||
|
||||
/// <summary>اطلاعات کوتاه محصول</summary>
|
||||
public string ShortInformation { get; init; }
|
||||
|
||||
/// <summary>اطلاعات کامل محصول</summary>
|
||||
public string FullInformation { get; init; }
|
||||
|
||||
/// <summary>قیمت محصول</summary>
|
||||
public long Price { get; init; }
|
||||
|
||||
/// <summary>حداکثر درصد تخفیف (0-100)</summary>
|
||||
public int MaxDiscountPercent { get; init; }
|
||||
|
||||
/// <summary>ترتیب نمایش</summary>
|
||||
public int SortOrder { get; init; }
|
||||
|
||||
/// <summary>وضعیت فعال/غیرفعال</summary>
|
||||
public bool IsActive { get; init; }
|
||||
|
||||
/// <summary>آیدی دستهبندیها</summary>
|
||||
public List<long> CategoryIds { get; init; } = new();
|
||||
|
||||
/// <summary>فایل تصویر اصلی (اختیاری - برای تغییر تصویر)</summary>
|
||||
public DiscountProductFileModel ImageFile { get; init; }
|
||||
|
||||
/// <summary>فایل تصویر کوچک (اختیاری - برای تغییر تصویر)</summary>
|
||||
public DiscountProductFileModel ThumbnailFile { get; init; }
|
||||
}
|
||||
|
||||
public class DiscountProductFileModel
|
||||
{
|
||||
/// <summary>فایل</summary>
|
||||
public byte[] File { get; set; }
|
||||
|
||||
/// <summary>نام فایل</summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>نوع فایل</summary>
|
||||
public string Mime { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.UpdateDiscountProduct;
|
||||
|
||||
public class UpdateDiscountProductCommandHandler : IRequestHandler<UpdateDiscountProductCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public UpdateDiscountProductCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(UpdateDiscountProductCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var updateRequest = new UpdateDiscountProductRequest
|
||||
{
|
||||
ProductId = request.ProductId,
|
||||
Title = request.Title,
|
||||
ShortInfomation = request.ShortInformation,
|
||||
FullInformation = request.FullInformation,
|
||||
Price = request.Price,
|
||||
MaxDiscountPercent = request.MaxDiscountPercent,
|
||||
SortOrder = request.SortOrder,
|
||||
IsActive = request.IsActive
|
||||
};
|
||||
|
||||
updateRequest.CategoryIds.AddRange(request.CategoryIds);
|
||||
|
||||
// Upload new Image if provided
|
||||
if (request.ImageFile != null && request.ImageFile.File != null && request.ImageFile.File.Length > 0)
|
||||
{
|
||||
var imageFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
|
||||
{
|
||||
Directory = "Images/DiscountShop/Products",
|
||||
IsBase64 = false,
|
||||
MIME = request.ImageFile.Mime,
|
||||
FileName = request.ImageFile.FileName,
|
||||
File = ByteString.CopyFrom(request.ImageFile.File)
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
if (imageFileInfo != null && !string.IsNullOrWhiteSpace(imageFileInfo.File))
|
||||
updateRequest.ImagePath = imageFileInfo.File;
|
||||
}
|
||||
|
||||
// Upload new Thumbnail if provided
|
||||
if (request.ThumbnailFile != null && request.ThumbnailFile.File != null && request.ThumbnailFile.File.Length > 0)
|
||||
{
|
||||
var thumbnailFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
|
||||
{
|
||||
Directory = "Images/DiscountShop/Products/Thumbnails",
|
||||
IsBase64 = false,
|
||||
MIME = request.ThumbnailFile.Mime,
|
||||
FileName = request.ThumbnailFile.FileName,
|
||||
File = ByteString.CopyFrom(request.ThumbnailFile.File)
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
if (thumbnailFileInfo != null && !string.IsNullOrWhiteSpace(thumbnailFileInfo.File))
|
||||
updateRequest.ThumbnailPath = thumbnailFileInfo.File;
|
||||
}
|
||||
|
||||
await _context.DiscountProducts.UpdateDiscountProductAsync(updateRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.UpdateDiscountProduct;
|
||||
|
||||
public class UpdateDiscountProductCommandValidator : AbstractValidator<UpdateDiscountProductCommand>
|
||||
{
|
||||
public UpdateDiscountProductCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.ProductId)
|
||||
.GreaterThan(0).WithMessage("شناسه محصول نامعتبر است");
|
||||
|
||||
RuleFor(x => x.Title)
|
||||
.NotEmpty().WithMessage("عنوان محصول الزامی است")
|
||||
.MaximumLength(200).WithMessage("عنوان محصول نباید بیشتر از 200 کاراکتر باشد");
|
||||
|
||||
RuleFor(x => x.ShortInformation)
|
||||
.NotEmpty().WithMessage("اطلاعات کوتاه محصول الزامی است")
|
||||
.MaximumLength(500).WithMessage("اطلاعات کوتاه نباید بیشتر از 500 کاراکتر باشد");
|
||||
|
||||
RuleFor(x => x.FullInformation)
|
||||
.NotEmpty().WithMessage("اطلاعات کامل محصول الزامی است");
|
||||
|
||||
RuleFor(x => x.Price)
|
||||
.GreaterThan(0).WithMessage("قیمت محصول باید بیشتر از صفر باشد");
|
||||
|
||||
RuleFor(x => x.MaxDiscountPercent)
|
||||
.InclusiveBetween(0, 100).WithMessage("درصد تخفیف باید بین 0 تا 100 باشد");
|
||||
|
||||
RuleFor(x => x.CategoryIds)
|
||||
.NotEmpty().WithMessage("حداقل یک دستهبندی باید انتخاب شود");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProductById;
|
||||
|
||||
public record GetDiscountProductByIdQuery : IRequest<GetDiscountProductByIdResponseDto>
|
||||
{
|
||||
/// <summary>شناسه محصول</summary>
|
||||
public long ProductId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProductById;
|
||||
|
||||
public class GetDiscountProductByIdQueryHandler : IRequestHandler<GetDiscountProductByIdQuery, GetDiscountProductByIdResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetDiscountProductByIdQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetDiscountProductByIdResponseDto> Handle(GetDiscountProductByIdQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.DiscountProducts.GetDiscountProductByIdAsync(
|
||||
new GetDiscountProductByIdRequest { ProductId = request.ProductId },
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return new GetDiscountProductByIdResponseDto
|
||||
{
|
||||
Id = response.Id,
|
||||
Title = response.Title,
|
||||
ShortInformation = response.ShortInfomation,
|
||||
FullInformation = response.FullInformation,
|
||||
Price = response.Price,
|
||||
MaxDiscountPercent = response.MaxDiscountPercent,
|
||||
ImagePath = response.ImagePath,
|
||||
ThumbnailPath = response.ThumbnailPath,
|
||||
RemainingCount = response.RemainingCount,
|
||||
ViewCount = response.ViewCount,
|
||||
SortOrder = response.SortOrder,
|
||||
IsActive = response.IsActive,
|
||||
Categories = response.Categories.Select(c => new CategoryInfoDto
|
||||
{
|
||||
Id = c.Id,
|
||||
Name = c.Name,
|
||||
Title = c.Title
|
||||
}).ToList(),
|
||||
Created = response.Created.ToDateTime()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProductById;
|
||||
|
||||
public class GetDiscountProductByIdQueryValidator : AbstractValidator<GetDiscountProductByIdQuery>
|
||||
{
|
||||
public GetDiscountProductByIdQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.ProductId)
|
||||
.GreaterThan(0).WithMessage("شناسه محصول نامعتبر است");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProductById;
|
||||
|
||||
public class GetDiscountProductByIdResponseDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string ShortInformation { get; set; }
|
||||
public string FullInformation { get; set; }
|
||||
public long Price { get; set; }
|
||||
public int MaxDiscountPercent { get; set; }
|
||||
public string ImagePath { get; set; }
|
||||
public string ThumbnailPath { get; set; }
|
||||
public int RemainingCount { get; set; }
|
||||
public int ViewCount { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public List<CategoryInfoDto> Categories { get; set; } = new();
|
||||
public DateTime Created { get; set; }
|
||||
}
|
||||
|
||||
public class CategoryInfoDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Title { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProducts;
|
||||
|
||||
public record GetDiscountProductsQuery : IRequest<GetDiscountProductsResponseDto>
|
||||
{
|
||||
/// <summary>فیلتر براساس دستهبندی</summary>
|
||||
public long? CategoryId { get; init; }
|
||||
|
||||
/// <summary>جستجو در عنوان و توضیحات</summary>
|
||||
public string SearchQuery { get; init; }
|
||||
|
||||
/// <summary>حداقل قیمت</summary>
|
||||
public long? MinPrice { get; init; }
|
||||
|
||||
/// <summary>حداکثر قیمت</summary>
|
||||
public long? MaxPrice { get; init; }
|
||||
|
||||
/// <summary>فقط محصولات فعال</summary>
|
||||
public bool? IsActive { get; init; }
|
||||
|
||||
/// <summary>فقط محصولات موجود در انبار</summary>
|
||||
public bool? InStock { get; init; }
|
||||
|
||||
/// <summary>شماره صفحه</summary>
|
||||
public int PageNumber { get; init; } = 1;
|
||||
|
||||
/// <summary>تعداد در هر صفحه</summary>
|
||||
public int PageSize { get; init; } = 20;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using BackOffice.BFF.Application.Common.Models;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProducts;
|
||||
|
||||
public class GetDiscountProductsQueryHandler : IRequestHandler<GetDiscountProductsQuery, GetDiscountProductsResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetDiscountProductsQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetDiscountProductsResponseDto> Handle(GetDiscountProductsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var grpcRequest = new GetDiscountProductsRequest
|
||||
{
|
||||
PageNumber = request.PageNumber,
|
||||
PageSize = request.PageSize
|
||||
};
|
||||
|
||||
if (request.CategoryId.HasValue)
|
||||
grpcRequest.CategoryId = new Int64Value { Value = request.CategoryId.Value };
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.SearchQuery))
|
||||
grpcRequest.SearchQuery = new StringValue { Value = request.SearchQuery };
|
||||
|
||||
if (request.MinPrice.HasValue)
|
||||
grpcRequest.MinPrice = new Int64Value { Value = request.MinPrice.Value };
|
||||
|
||||
if (request.MaxPrice.HasValue)
|
||||
grpcRequest.MaxPrice = new Int64Value { Value = request.MaxPrice.Value };
|
||||
|
||||
if (request.IsActive.HasValue)
|
||||
grpcRequest.IsActive = new BoolValue { Value = request.IsActive.Value };
|
||||
|
||||
if (request.InStock.HasValue)
|
||||
grpcRequest.InStock = new BoolValue { Value = request.InStock.Value };
|
||||
|
||||
var response = await _context.DiscountProducts.GetDiscountProductsAsync(grpcRequest, cancellationToken: cancellationToken);
|
||||
|
||||
return new GetDiscountProductsResponseDto
|
||||
{
|
||||
MetaData = new MetaData
|
||||
{
|
||||
CurrentPage = response.MetaData.CurrentPage,
|
||||
TotalPage = response.MetaData.TotalPages,
|
||||
PageSize = response.MetaData.PageSize,
|
||||
TotalCount = response.MetaData.TotalCount,
|
||||
HasPrevious = response.MetaData.HasPrevious,
|
||||
HasNext = response.MetaData.HasNext
|
||||
},
|
||||
Products = response.Models.Select(p => new DiscountProductDto
|
||||
{
|
||||
Id = p.Id,
|
||||
Title = p.Title,
|
||||
ShortInformation = p.ShortInfomation,
|
||||
Price = p.Price,
|
||||
MaxDiscountPercent = p.MaxDiscountPercent,
|
||||
ImagePath = p.ImagePath,
|
||||
ThumbnailPath = p.ThumbnailPath,
|
||||
RemainingCount = p.RemainingCount,
|
||||
ViewCount = p.ViewCount,
|
||||
IsActive = p.IsActive,
|
||||
Created = p.Created.ToDateTime()
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProducts;
|
||||
|
||||
public class GetDiscountProductsQueryValidator : AbstractValidator<GetDiscountProductsQuery>
|
||||
{
|
||||
public GetDiscountProductsQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.PageNumber)
|
||||
.GreaterThan(0).WithMessage("شماره صفحه باید بیشتر از صفر باشد");
|
||||
|
||||
RuleFor(x => x.PageSize)
|
||||
.GreaterThan(0).WithMessage("تعداد در صفحه باید بیشتر از صفر باشد")
|
||||
.LessThanOrEqualTo(100).WithMessage("حداکثر تعداد در صفحه 100 است");
|
||||
|
||||
RuleFor(x => x.MinPrice)
|
||||
.GreaterThanOrEqualTo(0).When(x => x.MinPrice.HasValue)
|
||||
.WithMessage("حداقل قیمت نمیتواند منفی باشد");
|
||||
|
||||
RuleFor(x => x.MaxPrice)
|
||||
.GreaterThanOrEqualTo(0).When(x => x.MaxPrice.HasValue)
|
||||
.WithMessage("حداکثر قیمت نمیتواند منفی باشد")
|
||||
.GreaterThanOrEqualTo(x => x.MinPrice).When(x => x.MinPrice.HasValue && x.MaxPrice.HasValue)
|
||||
.WithMessage("حداکثر قیمت باید بیشتر از حداقل قیمت باشد");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using BackOffice.BFF.Application.Common.Models;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProducts;
|
||||
|
||||
public class GetDiscountProductsResponseDto
|
||||
{
|
||||
public MetaData MetaData { get; set; }
|
||||
public List<DiscountProductDto> Products { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DiscountProductDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string ShortInformation { get; set; }
|
||||
public long Price { get; set; }
|
||||
public int MaxDiscountPercent { get; set; }
|
||||
public string ImagePath { get; set; }
|
||||
public string ThumbnailPath { get; set; }
|
||||
public int RemainingCount { get; set; }
|
||||
public int ViewCount { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.AddToCart;
|
||||
|
||||
public record AddToCartCommand : IRequest
|
||||
{
|
||||
/// <summary>شناسه کاربر</summary>
|
||||
public long UserId { get; init; }
|
||||
|
||||
/// <summary>شناسه محصول</summary>
|
||||
public long ProductId { get; init; }
|
||||
|
||||
/// <summary>تعداد</summary>
|
||||
public int Count { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.AddToCart;
|
||||
|
||||
public class AddToCartCommandHandler : IRequestHandler<AddToCartCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public AddToCartCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(AddToCartCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.DiscountShoppingCarts.AddToCartAsync(
|
||||
new AddToCartRequest
|
||||
{
|
||||
UserId = request.UserId,
|
||||
ProductId = request.ProductId,
|
||||
Count = request.Count
|
||||
},
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.AddToCart;
|
||||
|
||||
public class AddToCartCommandValidator : AbstractValidator<AddToCartCommand>
|
||||
{
|
||||
public AddToCartCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.UserId)
|
||||
.GreaterThan(0).WithMessage("شناسه کاربر نامعتبر است");
|
||||
|
||||
RuleFor(x => x.ProductId)
|
||||
.GreaterThan(0).WithMessage("شناسه محصول نامعتبر است");
|
||||
|
||||
RuleFor(x => x.Count)
|
||||
.GreaterThan(0).WithMessage("تعداد باید بیشتر از صفر باشد");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.ClearCart;
|
||||
|
||||
public record ClearCartCommand : IRequest
|
||||
{
|
||||
/// <summary>شناسه کاربر</summary>
|
||||
public long UserId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.ClearCart;
|
||||
|
||||
public class ClearCartCommandHandler : IRequestHandler<ClearCartCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public ClearCartCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(ClearCartCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.DiscountShoppingCarts.ClearCartAsync(
|
||||
new ClearCartRequest { UserId = request.UserId },
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.ClearCart;
|
||||
|
||||
public class ClearCartCommandValidator : AbstractValidator<ClearCartCommand>
|
||||
{
|
||||
public ClearCartCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.UserId)
|
||||
.GreaterThan(0).WithMessage("شناسه کاربر نامعتبر است");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.RemoveFromCart;
|
||||
|
||||
public record RemoveFromCartCommand : IRequest
|
||||
{
|
||||
/// <summary>شناسه کاربر</summary>
|
||||
public long UserId { get; init; }
|
||||
|
||||
/// <summary>شناسه آیتم سبد خرید</summary>
|
||||
public long CartItemId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.RemoveFromCart;
|
||||
|
||||
public class RemoveFromCartCommandHandler : IRequestHandler<RemoveFromCartCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public RemoveFromCartCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(RemoveFromCartCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.DiscountShoppingCarts.RemoveFromCartAsync(
|
||||
new RemoveFromCartRequest
|
||||
{
|
||||
UserId = request.UserId,
|
||||
CartItemId = request.CartItemId
|
||||
},
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.RemoveFromCart;
|
||||
|
||||
public class RemoveFromCartCommandValidator : AbstractValidator<RemoveFromCartCommand>
|
||||
{
|
||||
public RemoveFromCartCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.UserId)
|
||||
.GreaterThan(0).WithMessage("شناسه کاربر نامعتبر است");
|
||||
|
||||
RuleFor(x => x.CartItemId)
|
||||
.GreaterThan(0).WithMessage("شناسه آیتم سبد خرید نامعتبر است");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.UpdateCartItemCount;
|
||||
|
||||
public record UpdateCartItemCountCommand : IRequest
|
||||
{
|
||||
/// <summary>شناسه کاربر</summary>
|
||||
public long UserId { get; init; }
|
||||
|
||||
/// <summary>شناسه آیتم سبد خرید</summary>
|
||||
public long CartItemId { get; init; }
|
||||
|
||||
/// <summary>تعداد جدید</summary>
|
||||
public int NewCount { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.UpdateCartItemCount;
|
||||
|
||||
public class UpdateCartItemCountCommandHandler : IRequestHandler<UpdateCartItemCountCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public UpdateCartItemCountCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(UpdateCartItemCountCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.DiscountShoppingCarts.UpdateCartItemCountAsync(
|
||||
new UpdateCartItemCountRequest
|
||||
{
|
||||
UserId = request.UserId,
|
||||
CartItemId = request.CartItemId,
|
||||
NewCount = request.NewCount
|
||||
},
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.UpdateCartItemCount;
|
||||
|
||||
public class UpdateCartItemCountCommandValidator : AbstractValidator<UpdateCartItemCountCommand>
|
||||
{
|
||||
public UpdateCartItemCountCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.UserId)
|
||||
.GreaterThan(0).WithMessage("شناسه کاربر نامعتبر است");
|
||||
|
||||
RuleFor(x => x.CartItemId)
|
||||
.GreaterThan(0).WithMessage("شناسه آیتم سبد خرید نامعتبر است");
|
||||
|
||||
RuleFor(x => x.NewCount)
|
||||
.GreaterThan(0).WithMessage("تعداد جدید باید بیشتر از صفر باشد");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Queries.GetUserCart;
|
||||
|
||||
public record GetUserCartQuery : IRequest<GetUserCartResponseDto>
|
||||
{
|
||||
/// <summary>شناسه کاربر</summary>
|
||||
public long UserId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Queries.GetUserCart;
|
||||
|
||||
public class GetUserCartQueryHandler : IRequestHandler<GetUserCartQuery, GetUserCartResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetUserCartQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetUserCartResponseDto> Handle(GetUserCartQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.DiscountShoppingCarts.GetUserCartAsync(
|
||||
new GetUserCartRequest { UserId = request.UserId },
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return new GetUserCartResponseDto
|
||||
{
|
||||
UserId = response.UserId,
|
||||
TotalPrice = response.TotalPrice,
|
||||
TotalDiscountedPrice = response.TotalDiscountedPrice,
|
||||
TotalSavings = response.TotalSavings,
|
||||
Items = response.Items.Select(item => new CartItemDto
|
||||
{
|
||||
Id = item.Id,
|
||||
ProductId = item.ProductId,
|
||||
ProductTitle = item.ProductTitle,
|
||||
ProductImagePath = item.ProductImagePath,
|
||||
UnitPrice = item.UnitPrice,
|
||||
MaxDiscountPercent = item.MaxDiscountPercent,
|
||||
Count = item.Count,
|
||||
TotalPrice = item.TotalPrice,
|
||||
DiscountedPrice = item.DiscountedPrice,
|
||||
AddedAt = item.AddedAt.ToDateTime()
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Queries.GetUserCart;
|
||||
|
||||
public class GetUserCartQueryValidator : AbstractValidator<GetUserCartQuery>
|
||||
{
|
||||
public GetUserCartQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.UserId)
|
||||
.GreaterThan(0).WithMessage("شناسه کاربر نامعتبر است");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace BackOffice.BFF.Application.DiscountShoppingCartCQ.Queries.GetUserCart;
|
||||
|
||||
public class GetUserCartResponseDto
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
public List<CartItemDto> Items { get; set; } = new();
|
||||
public long TotalPrice { get; set; }
|
||||
public long TotalDiscountedPrice { get; set; }
|
||||
public long TotalSavings { get; set; }
|
||||
}
|
||||
|
||||
public class CartItemDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public long ProductId { get; set; }
|
||||
public string ProductTitle { get; set; }
|
||||
public string ProductImagePath { get; set; }
|
||||
public long UnitPrice { get; set; }
|
||||
public int MaxDiscountPercent { get; set; }
|
||||
public int Count { get; set; }
|
||||
public long TotalPrice { get; set; }
|
||||
public long DiscountedPrice { get; set; }
|
||||
public DateTime AddedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using CMSMicroservice.Protobuf.Protos.ProductTag;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductTagCQ.Commands.AssignTagToProduct;
|
||||
|
||||
public record AssignTagToProductCommand : IRequest<long>
|
||||
{
|
||||
public long ProductId { get; init; }
|
||||
public long TagId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using CMSMicroservice.Protobuf.Protos.ProductTag;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductTagCQ.Commands.AssignTagToProduct;
|
||||
|
||||
public class AssignTagToProductCommandHandler : IRequestHandler<AssignTagToProductCommand, long>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public AssignTagToProductCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<long> Handle(AssignTagToProductCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.ProductTags.CreateNewProductTagAsync(
|
||||
new CreateNewProductTagRequest
|
||||
{
|
||||
ProductId = request.ProductId,
|
||||
TagId = request.TagId
|
||||
},
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return response.Id;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
|
||||
using Google.Protobuf;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
@@ -59,7 +59,7 @@ public class AddProductImageCommandHandler : IRequestHandler<AddProductImageComm
|
||||
ImageThumbnailPath = thumbFileInfo.File
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
var createGalleryResponse = await _context.ProductGallerys.CreateNewProductGallerysAsync(new CreateNewProductGallerysRequest
|
||||
var createGalleryResponse = await _context.ProductGalleries.CreateNewProductGalleriesAsync(new CreateNewProductGalleriesRequest
|
||||
{
|
||||
ProductId = request.ProductId,
|
||||
ProductImageId = createImageResponse.Id
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Commands.RemoveProductImage;
|
||||
|
||||
@@ -14,7 +14,7 @@ public class RemoveProductImageCommandHandler : IRequestHandler<RemoveProductIma
|
||||
|
||||
public async Task<Unit> Handle(RemoveProductImageCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.ProductGallerys.DeleteProductGallerysAsync(new DeleteProductGallerysRequest
|
||||
await _context.ProductGalleries.DeleteProductGalleriesAsync(new DeleteProductGalleriesRequest
|
||||
{
|
||||
Id = request.ProductGalleryId
|
||||
}, cancellationToken: cancellationToken);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
|
||||
using CMSProductCategory = CMSMicroservice.Protobuf.Protos.ProductCategory;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Commands.UpdateCategoryProducts;
|
||||
|
||||
@@ -17,9 +17,9 @@ public class UpdateCategoryProductsCommandHandler : IRequestHandler<UpdateCatego
|
||||
var targetIds = request.ProductIds?.ToHashSet() ?? new HashSet<long>();
|
||||
|
||||
// load existing links for this category
|
||||
var existingRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
|
||||
var existingRequest = new CMSProductCategory.GetAllProductCategoryByFilterRequest
|
||||
{
|
||||
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
|
||||
Filter = new CMSProductCategory.GetAllProductCategoryByFilterFilter
|
||||
{
|
||||
CategoryId = request.CategoryId
|
||||
},
|
||||
@@ -30,7 +30,7 @@ public class UpdateCategoryProductsCommandHandler : IRequestHandler<UpdateCatego
|
||||
}
|
||||
};
|
||||
|
||||
var existingResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(existingRequest, cancellationToken: cancellationToken);
|
||||
var existingResponse = await _context.ProductCategories.GetAllProductCategoryByFilterAsync(existingRequest, cancellationToken: cancellationToken);
|
||||
var existing = existingResponse.Models ?? new();
|
||||
|
||||
var existingIds = existing.Select(x => x.ProductId).ToHashSet();
|
||||
@@ -40,19 +40,19 @@ public class UpdateCategoryProductsCommandHandler : IRequestHandler<UpdateCatego
|
||||
|
||||
foreach (var productId in toAdd)
|
||||
{
|
||||
var createRequest = new CMSPruductCategory.CreateNewPruductCategoryRequest
|
||||
var createRequest = new CMSProductCategory.CreateNewProductCategoryRequest
|
||||
{
|
||||
ProductId = productId,
|
||||
CategoryId = request.CategoryId
|
||||
};
|
||||
|
||||
await _context.ProductCategories.CreateNewPruductCategoryAsync(createRequest, cancellationToken: cancellationToken);
|
||||
await _context.ProductCategories.CreateNewProductCategoryAsync(createRequest, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
foreach (var rel in toRemove)
|
||||
{
|
||||
await _context.ProductCategories.DeletePruductCategoryAsync(
|
||||
new CMSPruductCategory.DeletePruductCategoryRequest { Id = rel.Id },
|
||||
await _context.ProductCategories.DeleteProductCategoryAsync(
|
||||
new CMSProductCategory.DeleteProductCategoryRequest { Id = rel.Id },
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
|
||||
using CMSProductCategory = CMSMicroservice.Protobuf.Protos.ProductCategory;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Commands.UpdateProductCategories;
|
||||
|
||||
@@ -17,9 +17,9 @@ public class UpdateProductCategoriesCommandHandler : IRequestHandler<UpdateProdu
|
||||
var targetIds = request.CategoryIds?.ToHashSet() ?? new HashSet<long>();
|
||||
|
||||
// Load existing product-category relations
|
||||
var existingRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
|
||||
var existingRequest = new CMSProductCategory.GetAllProductCategoryByFilterRequest
|
||||
{
|
||||
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
|
||||
Filter = new CMSProductCategory.GetAllProductCategoryByFilterFilter
|
||||
{
|
||||
ProductId = request.ProductId
|
||||
},
|
||||
@@ -30,7 +30,7 @@ public class UpdateProductCategoriesCommandHandler : IRequestHandler<UpdateProdu
|
||||
}
|
||||
};
|
||||
|
||||
var existingResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(existingRequest, cancellationToken: cancellationToken);
|
||||
var existingResponse = await _context.ProductCategories.GetAllProductCategoryByFilterAsync(existingRequest, cancellationToken: cancellationToken);
|
||||
var existing = existingResponse.Models ?? new();
|
||||
|
||||
var existingIds = existing.Select(x => x.CategoryId).ToHashSet();
|
||||
@@ -41,19 +41,19 @@ public class UpdateProductCategoriesCommandHandler : IRequestHandler<UpdateProdu
|
||||
|
||||
foreach (var categoryId in toAdd)
|
||||
{
|
||||
var createRequest = new CMSPruductCategory.CreateNewPruductCategoryRequest
|
||||
var createRequest = new CMSProductCategory.CreateNewProductCategoryRequest
|
||||
{
|
||||
ProductId = request.ProductId,
|
||||
CategoryId = categoryId
|
||||
};
|
||||
|
||||
await _context.ProductCategories.CreateNewPruductCategoryAsync(createRequest, cancellationToken: cancellationToken);
|
||||
await _context.ProductCategories.CreateNewProductCategoryAsync(createRequest, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
foreach (var rel in toRemove)
|
||||
{
|
||||
await _context.ProductCategories.DeletePruductCategoryAsync(
|
||||
new CMSPruductCategory.DeletePruductCategoryRequest { Id = rel.Id },
|
||||
await _context.ProductCategories.DeleteProductCategoryAsync(
|
||||
new CMSProductCategory.DeleteProductCategoryRequest { Id = rel.Id },
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSCategory = CMSMicroservice.Protobuf.Protos.Category;
|
||||
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
|
||||
using CMSProductCategory = CMSMicroservice.Protobuf.Protos.ProductCategory;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetCategories;
|
||||
|
||||
@@ -30,9 +30,9 @@ public class GetCategoriesQueryHandler : IRequestHandler<GetCategoriesQuery, Get
|
||||
var categories = categoriesResponse.Models ?? new();
|
||||
|
||||
// Load existing product-category relations for this product
|
||||
var productCategoryRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
|
||||
var productCategoryRequest = new CMSProductCategory.GetAllProductCategoryByFilterRequest
|
||||
{
|
||||
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
|
||||
Filter = new CMSProductCategory.GetAllProductCategoryByFilterFilter
|
||||
{
|
||||
ProductId = request.ProductId
|
||||
},
|
||||
@@ -43,7 +43,7 @@ public class GetCategoriesQueryHandler : IRequestHandler<GetCategoriesQuery, Get
|
||||
}
|
||||
};
|
||||
|
||||
var productCategoriesResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(productCategoryRequest, cancellationToken: cancellationToken);
|
||||
var productCategoriesResponse = await _context.ProductCategories.GetAllProductCategoryByFilterAsync(productCategoryRequest, cancellationToken: cancellationToken);
|
||||
var productCategories = productCategoriesResponse.Models ?? new();
|
||||
|
||||
var selectedIds = productCategories
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetProductGallery;
|
||||
@@ -15,12 +15,12 @@ public class GetProductGalleryQueryHandler : IRequestHandler<GetProductGalleryQu
|
||||
|
||||
public async Task<GetProductGalleryResponseDto> Handle(GetProductGalleryQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var galleryRequest = new GetAllProductGallerysByFilterRequest
|
||||
var grpcRequest = new GetAllProductGalleriesByFilterRequest
|
||||
{
|
||||
Filter = new GetAllProductGallerysByFilterFilter()
|
||||
Filter = new GetAllProductGalleriesByFilterFilter()
|
||||
};
|
||||
|
||||
var galleryResponse = await _context.ProductGallerys.GetAllProductGallerysByFilterAsync(galleryRequest, cancellationToken: cancellationToken);
|
||||
var galleryResponse = await _context.ProductGalleries.GetAllProductGalleriesByFilterAsync(grpcRequest, cancellationToken: cancellationToken);
|
||||
|
||||
// Filter by product id on client side because generated type may not support assigning Int64Value directly
|
||||
var filteredModels = galleryResponse?.Models?.Where(x => x.ProductId == request.ProductId).ToList();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using BackOffice.BFF.Application.Common.Interfaces;
|
||||
using CMSProducts = CMSMicroservice.Protobuf.Protos.Products;
|
||||
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
|
||||
using CMSProductCategory = CMSMicroservice.Protobuf.Protos.ProductCategory;
|
||||
|
||||
namespace BackOffice.BFF.Application.ProductsCQ.Queries.GetProductsForCategory;
|
||||
|
||||
@@ -30,9 +30,9 @@ public class GetProductsForCategoryQueryHandler : IRequestHandler<GetProductsFor
|
||||
var products = productsResponse.Models ?? new();
|
||||
|
||||
// Load links for this category
|
||||
var linksRequest = new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
|
||||
var linksRequest = new CMSProductCategory.GetAllProductCategoryByFilterRequest
|
||||
{
|
||||
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
|
||||
Filter = new CMSProductCategory.GetAllProductCategoryByFilterFilter
|
||||
{
|
||||
CategoryId = request.CategoryId
|
||||
},
|
||||
@@ -43,7 +43,7 @@ public class GetProductsForCategoryQueryHandler : IRequestHandler<GetProductsFor
|
||||
}
|
||||
};
|
||||
|
||||
var linksResponse = await _context.ProductCategories.GetAllPruductCategoryByFilterAsync(linksRequest, cancellationToken: cancellationToken);
|
||||
var linksResponse = await _context.ProductCategories.GetAllProductCategoryByFilterAsync(linksRequest, cancellationToken: cancellationToken);
|
||||
var links = linksResponse.Models ?? new();
|
||||
|
||||
var selectedProductIds = links.Select(l => l.ProductId).ToHashSet();
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Commands.CreateTag;
|
||||
|
||||
public record CreateTagCommand : IRequest<long>
|
||||
{
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public string Title { get; init; } = string.Empty;
|
||||
public string? Description { get; init; }
|
||||
public bool IsActive { get; init; } = true;
|
||||
public int SortOrder { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Commands.CreateTag;
|
||||
|
||||
public class CreateTagCommandHandler : IRequestHandler<CreateTagCommand, long>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public CreateTagCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<long> Handle(CreateTagCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.Tags.CreateNewTagAsync(
|
||||
new CreateNewTagRequest
|
||||
{
|
||||
Name = request.Name,
|
||||
Title = request.Title,
|
||||
Description = request.Description,
|
||||
IsActive = request.IsActive,
|
||||
SortOrder = request.SortOrder
|
||||
},
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return response.Id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace BackOffice.BFF.Application.TagCQ.Commands.DeleteTag;
|
||||
|
||||
public record DeleteTagCommand : IRequest
|
||||
{
|
||||
public long Id { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Commands.DeleteTag;
|
||||
|
||||
public class DeleteTagCommandHandler : IRequestHandler<DeleteTagCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public DeleteTagCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(DeleteTagCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.Tags.DeleteTagAsync(
|
||||
new DeleteTagRequest
|
||||
{
|
||||
Id = request.Id
|
||||
},
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Commands.UpdateTag;
|
||||
|
||||
public record UpdateTagCommand : IRequest
|
||||
{
|
||||
public long Id { get; init; }
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public string Title { get; init; } = string.Empty;
|
||||
public string? Description { get; init; }
|
||||
public bool IsActive { get; init; }
|
||||
public int SortOrder { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Commands.UpdateTag;
|
||||
|
||||
public class UpdateTagCommandHandler : IRequestHandler<UpdateTagCommand>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public UpdateTagCommandHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<Unit> Handle(UpdateTagCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _context.Tags.UpdateTagAsync(
|
||||
new UpdateTagRequest
|
||||
{
|
||||
Id = request.Id,
|
||||
Name = request.Name,
|
||||
Title = request.Title,
|
||||
Description = request.Description,
|
||||
IsActive = request.IsActive,
|
||||
SortOrder = request.SortOrder
|
||||
},
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Queries.GetAllTags;
|
||||
|
||||
public record GetAllTagsQuery : IRequest<GetAllTagByFilterResponse>
|
||||
{
|
||||
public int PageNumber { get; init; } = 1;
|
||||
public int PageSize { get; init; } = 10;
|
||||
public string? SearchTerm { get; init; }
|
||||
public bool? IsActive { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using CMSMicroservice.Protobuf.Protos;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Queries.GetAllTags;
|
||||
|
||||
public class GetAllTagsQueryHandler : IRequestHandler<GetAllTagsQuery, GetAllTagByFilterResponse>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetAllTagsQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetAllTagByFilterResponse> Handle(GetAllTagsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var grpcRequest = new GetAllTagByFilterRequest
|
||||
{
|
||||
PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
|
||||
{
|
||||
PageNumber = request.PageNumber,
|
||||
PageSize = request.PageSize
|
||||
},
|
||||
Filter = new GetAllTagByFilterFilter()
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(request.SearchTerm))
|
||||
{
|
||||
grpcRequest.Filter.Name = request.SearchTerm;
|
||||
}
|
||||
|
||||
if (request.IsActive.HasValue)
|
||||
{
|
||||
grpcRequest.Filter.IsActive = request.IsActive.Value;
|
||||
}
|
||||
|
||||
var response = await _context.Tags.GetAllTagByFilterAsync(grpcRequest, cancellationToken: cancellationToken);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Queries.GetProductsByTag;
|
||||
|
||||
public record GetProductsByTagQuery : IRequest<GetProductsByTagResponse>
|
||||
{
|
||||
public long TagId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Queries.GetProductsByTag;
|
||||
|
||||
public class GetProductsByTagQueryHandler : IRequestHandler<GetProductsByTagQuery, GetProductsByTagResponse>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetProductsByTagQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetProductsByTagResponse> Handle(GetProductsByTagQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.Tags.GetProductsByTagAsync(
|
||||
new GetProductsByTagRequest { TagId = request.TagId },
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Queries.GetTag;
|
||||
|
||||
public record GetTagQuery : IRequest<GetTagResponse>
|
||||
{
|
||||
public long Id { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
|
||||
namespace BackOffice.BFF.Application.TagCQ.Queries.GetTag;
|
||||
|
||||
public class GetTagQueryHandler : IRequestHandler<GetTagQuery, GetTagResponse>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
|
||||
public GetTagQueryHandler(IApplicationContractContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<GetTagResponse> Handle(GetTagQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _context.Tags.GetTagAsync(
|
||||
new GetTagRequest { Id = request.Id },
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,15 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Afrino.FMSMicroservice.Protobuf" Version="0.0.122" />
|
||||
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.141" />
|
||||
<!--<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.141" />-->
|
||||
|
||||
<PackageReference Include="Google.Protobuf" Version="3.23.3" />
|
||||
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.54.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\FourSat\CMS\src\CMSMicroservice.Protobuf\CMSMicroservice.Protobuf.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -7,14 +7,20 @@ using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||
using CMSMicroservice.Protobuf.Protos.UserRole;
|
||||
using CMSMicroservice.Protobuf.Protos.Products;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
|
||||
using CMSMicroservice.Protobuf.Protos.Category;
|
||||
using CMSMicroservice.Protobuf.Protos.PruductCategory;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductCategory;
|
||||
using BackOffice.BFF.Commission.Protobuf;
|
||||
using BackOffice.BFF.NetworkMembership.Protobuf;
|
||||
using BackOffice.BFF.ClubMembership.Protobuf;
|
||||
using BackOffice.BFF.Configuration.Protobuf;
|
||||
using FMSMicroservice.Protobuf.Protos.FileInfo;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountProduct;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountCategory;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
|
||||
using CMSMicroservice.Protobuf.Protos.DiscountOrder;
|
||||
using CMSMicroservice.Protobuf.Protos.Tag;
|
||||
using CMSMicroservice.Protobuf.Protos.ProductTag;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace BackOffice.BFF.Infrastructure.Services;
|
||||
@@ -50,10 +56,10 @@ public class ApplicationContractContext : IApplicationContractContext
|
||||
public PackageContract.PackageContractClient Packages => GetService<PackageContract.PackageContractClient>();
|
||||
public ProductsContract.ProductsContractClient Products => GetService<ProductsContract.ProductsContractClient>();
|
||||
public ProductImagesContract.ProductImagesContractClient ProductImages => GetService<ProductImagesContract.ProductImagesContractClient>();
|
||||
public ProductGallerysContract.ProductGallerysContractClient ProductGallerys => GetService<ProductGallerysContract.ProductGallerysContractClient>();
|
||||
public ProductGalleriesContract.ProductGalleriesContractClient ProductGalleries => GetService<ProductGalleriesContract.ProductGalleriesContractClient>();
|
||||
public RoleContract.RoleContractClient Roles => GetService<RoleContract.RoleContractClient>();
|
||||
public CategoryContract.CategoryContractClient Categories => GetService<CategoryContract.CategoryContractClient>();
|
||||
public PruductCategoryContract.PruductCategoryContractClient ProductCategories => GetService<PruductCategoryContract.PruductCategoryContractClient>();
|
||||
public ProductCategoryContract.ProductCategoryContractClient ProductCategories => GetService<ProductCategoryContract.ProductCategoryContractClient>();
|
||||
public UserAddressContract.UserAddressContractClient UserAddress => GetService<UserAddressContract.UserAddressContractClient>();
|
||||
public UserContract.UserContractClient Users => GetService<UserContract.UserContractClient>();
|
||||
public UserOrderContract.UserOrderContractClient UserOrders => GetService<UserOrderContract.UserOrderContractClient>();
|
||||
@@ -64,5 +70,15 @@ public class ApplicationContractContext : IApplicationContractContext
|
||||
public NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships => GetService<NetworkMembershipContract.NetworkMembershipContractClient>();
|
||||
public ClubMembershipContract.ClubMembershipContractClient ClubMemberships => GetService<ClubMembershipContract.ClubMembershipContractClient>();
|
||||
public ConfigurationContract.ConfigurationContractClient Configurations => GetService<ConfigurationContract.ConfigurationContractClient>();
|
||||
|
||||
// Discount Shop System (Phase 9)
|
||||
public DiscountProductContract.DiscountProductContractClient DiscountProducts => GetService<DiscountProductContract.DiscountProductContractClient>();
|
||||
public DiscountCategoryContract.DiscountCategoryContractClient DiscountCategories => GetService<DiscountCategoryContract.DiscountCategoryContractClient>();
|
||||
public DiscountShoppingCartContract.DiscountShoppingCartContractClient DiscountShoppingCarts => GetService<DiscountShoppingCartContract.DiscountShoppingCartContractClient>();
|
||||
public DiscountOrderContract.DiscountOrderContractClient DiscountOrders => GetService<DiscountOrderContract.DiscountOrderContractClient>();
|
||||
|
||||
// Tag Management System
|
||||
public TagContract.TagContractClient Tags => GetService<TagContract.TagContractClient>();
|
||||
public ProductTagContract.ProductTagContractClient ProductTags => GetService<ProductTagContract.ProductTagContractClient>();
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ service CommissionContract
|
||||
};
|
||||
rpc GetWorkerExecutionLogs(GetWorkerExecutionLogsRequest) returns (GetWorkerExecutionLogsResponse){
|
||||
};
|
||||
rpc GetWithdrawalReports(GetWithdrawalReportsRequest) returns (GetWithdrawalReportsResponse){
|
||||
};
|
||||
}
|
||||
|
||||
// ============ Commands ============
|
||||
@@ -347,3 +349,47 @@ message WorkerExecutionLogModel
|
||||
int32 records_processed = 9;
|
||||
google.protobuf.StringValue details = 10; // JSON or text details
|
||||
}
|
||||
|
||||
// GetWithdrawalReports Query
|
||||
message GetWithdrawalReportsRequest
|
||||
{
|
||||
google.protobuf.Timestamp start_date = 1; // Optional - default: 30 days ago
|
||||
google.protobuf.Timestamp end_date = 2; // Optional - default: today
|
||||
int32 period_type = 3; // ReportPeriodType: Daily=1, Weekly=2, Monthly=3
|
||||
google.protobuf.Int32Value status = 4; // CommissionPayoutStatus enum (optional)
|
||||
google.protobuf.Int64Value user_id = 5; // Optional user filter
|
||||
}
|
||||
|
||||
message GetWithdrawalReportsResponse
|
||||
{
|
||||
repeated PeriodReport period_reports = 1;
|
||||
WithdrawalSummary summary = 2;
|
||||
}
|
||||
|
||||
message PeriodReport
|
||||
{
|
||||
string period_label = 1; // e.g., "2025-01-15", "هفته 3", "فروردین 1404"
|
||||
google.protobuf.Timestamp start_date = 2;
|
||||
google.protobuf.Timestamp end_date = 3;
|
||||
int32 total_requests = 4;
|
||||
int32 pending_count = 5;
|
||||
int32 approved_count = 6;
|
||||
int32 rejected_count = 7;
|
||||
int32 completed_count = 8;
|
||||
int32 failed_count = 9;
|
||||
int64 total_amount = 10;
|
||||
int64 paid_amount = 11;
|
||||
int64 pending_amount = 12;
|
||||
}
|
||||
|
||||
message WithdrawalSummary
|
||||
{
|
||||
int32 total_requests = 1;
|
||||
int64 total_amount = 2;
|
||||
int64 total_paid = 3;
|
||||
int64 total_pending = 4;
|
||||
int64 total_rejected = 5;
|
||||
int64 average_amount = 6;
|
||||
int32 unique_users = 7;
|
||||
float success_rate = 8; // Percentage (0-100)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user