diff --git a/docs/EXCLUDED-HANDLERS-FIX-PLAN.md b/docs/EXCLUDED-HANDLERS-FIX-PLAN.md
index 12a8613..4f5ba1f 100644
--- a/docs/EXCLUDED-HANDLERS-FIX-PLAN.md
+++ b/docs/EXCLUDED-HANDLERS-FIX-PLAN.md
@@ -1,22 +1,71 @@
# Plan: فعالسازی مرحلهای Handler های کامنتشده
**تاریخ:** 8 دسامبر 2025
-**وضعیت:** در انتظار اجرا
-**تعداد کل فایلهای کامنتشده:** 37 فایل در 3 دسته
+**وضعیت:** ✅ کامل شده
+**آخرین بهروزرسانی:** 1 ژانویه 2026
---
## خلاصه اجرایی
-در `BackOffice.BFF.Application.csproj` سه دسته handler کامنت شدهاند:
+در `BackOffice.BFF.Application.csproj` سه دسته handler کامنت شده بودند که همه فعال شدند:
-1. **DiscountOrderCQ/** (18 فایل) - عدم تطابق Proto با CMS
-2. **DiscountShoppingCartCQ/** (16 فایل) - عدم تطابق Proto
-3. **CommissionCQ/Commands/ProcessWithdrawal/** (3 فایل) - مشکل تبدیل StringValue
+1. **DiscountOrderCQ/** (18 فایل) - ✅ فعال شد
+2. **DiscountShoppingCartCQ/** (16 فایل) - ✅ فعال شد و با CMS proto هماهنگ شد
+3. **CommissionCQ/Commands/ProcessWithdrawal/** (3 فایل) - ✅ قبلاً فعال شده بود
+
+**همچنین در BackOffice UI (1 ژانویه 2026):**
+- فعالسازی همه سرویسها در `ConfigureService.cs`
+- ثبت gRPC Clients برای DiscountProduct, DiscountCategory, DiscountOrder, Tag, ProductTag, PublicMessage
+- ثبت Application Services
---
-## مرحله 1: ProcessWithdrawal (30 دقیقه - ساده ✅)
+## تغییرات انجامشده (1 ژانویه 2026)
+
+### BackOffice UI - فعالسازی فرانتاند
+
+#### ConfigureService.cs
+- فعالسازی using statements برای همه proto clients
+- ثبت gRPC Clients در DI container
+- ثبت Application Services (IDiscountProductService, IDiscountCategoryService, etc.)
+
+#### صفحات فعال شده:
+| Route | صفحه |
+|-------|------|
+| `/discount-products` | مدیریت محصولات تخفیفی |
+| `/discount-categories` | مدیریت دستهبندیها |
+| `/discount-orders` | مدیریت سفارشات |
+| `/tags` | مدیریت تگها |
+| `/public-messages` | پیامهای عمومی |
+
+---
+
+## تغییرات انجامشده (13 ژانویه 2025)
+
+### DiscountShoppingCartCQ - اصلاحات Proto
+
+#### RemoveFromCart
+- `CartItemId` → `ProductId` (مطابق با proto)
+
+#### UpdateCartItemCount
+- `CartItemId` → `ProductId` (مطابق با proto)
+
+#### GetUserCart Response
+- حذف `UserId` از response
+- `TotalDiscountedPrice` → `TotalDiscountAmount`
+- `TotalSavings` → حذف شد
+- اضافه شدن `FinalPrice`
+
+#### CartItemDto
+- حذف `Id`
+- `DiscountedPrice` → `DiscountAmount`
+- `AddedAt` → `Created`
+- اضافه شدن `FinalPrice`, `ProductRemainingCount`
+
+---
+
+## مرحله 1: ProcessWithdrawal ✅ (قبلاً انجام شده)
### ویژگی بیزینسی
مدیریت درخواستهای برداشت کمیسیون توسط ادمین (تایید/رد)
diff --git a/src/BackOffice.BFF.Application/BackOffice.BFF.Application.csproj b/src/BackOffice.BFF.Application/BackOffice.BFF.Application.csproj
index 46a75ad..e79f19d 100644
--- a/src/BackOffice.BFF.Application/BackOffice.BFF.Application.csproj
+++ b/src/BackOffice.BFF.Application/BackOffice.BFF.Application.csproj
@@ -5,14 +5,10 @@
enable
-
+
+
-
-
-
-
-
-
+
diff --git a/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetAllDiscountOrders/GetAllDiscountOrdersQuery.cs b/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetAllDiscountOrders/GetAllDiscountOrdersQuery.cs
new file mode 100644
index 0000000..7689338
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetAllDiscountOrders/GetAllDiscountOrdersQuery.cs
@@ -0,0 +1,50 @@
+namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetAllDiscountOrders;
+
+///
+/// کوئری دریافت همه سفارشات فروشگاه تخفیفی برای ادمین
+///
+public class GetAllDiscountOrdersQuery : IRequest
+{
+ public int PageNumber { get; set; } = 1;
+ public int PageSize { get; set; } = 20;
+
+ public long? UserId { get; set; }
+ public int? PaymentStatus { get; set; }
+ public int? DeliveryStatus { get; set; }
+ public string? UserMobile { get; set; }
+ public string? TrackingCode { get; set; }
+ public DateTime? FromDate { get; set; }
+ public DateTime? ToDate { get; set; }
+ public long? MinAmount { get; set; }
+ public long? MaxAmount { get; set; }
+}
+
+public class GetAllDiscountOrdersResponseDto
+{
+ public MetaData MetaData { get; set; } = new();
+ public List Orders { get; set; } = new();
+}
+
+public class AdminOrderDto
+{
+ public long Id { get; set; }
+ public long UserId { get; set; }
+ public string UserFullName { get; set; } = string.Empty;
+ public string UserMobile { get; set; } = string.Empty;
+ public long TotalAmount { get; set; }
+ public long DiscountBalanceUsed { get; set; }
+ public long GatewayAmountPaid { get; set; }
+ public long VatAmount { get; set; }
+ public int PaymentStatus { get; set; }
+ public DateTime? PaymentDate { get; set; }
+ public int DeliveryStatus { get; set; }
+ public DateTime? DeliveryDate { get; set; }
+ public string? ShippingAddress { get; set; }
+ public string? ReceiverName { get; set; }
+ public string? ReceiverMobile { get; set; }
+ public string? TrackingCode { get; set; }
+ public string? AdminNote { get; set; }
+ public DateTime Created { get; set; }
+ public DateTime? LastModified { get; set; }
+ public int ItemsCount { get; set; }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetAllDiscountOrders/GetAllDiscountOrdersQueryHandler.cs b/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetAllDiscountOrders/GetAllDiscountOrdersQueryHandler.cs
new file mode 100644
index 0000000..b6e2805
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetAllDiscountOrders/GetAllDiscountOrdersQueryHandler.cs
@@ -0,0 +1,88 @@
+using CMSMicroservice.Protobuf.Protos.DiscountOrder;
+using Google.Protobuf.WellKnownTypes;
+
+namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetAllDiscountOrders;
+
+public class GetAllDiscountOrdersQueryHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public GetAllDiscountOrdersQueryHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(GetAllDiscountOrdersQuery request, CancellationToken cancellationToken)
+ {
+ var grpcRequest = new GetAllDiscountOrdersRequest
+ {
+ PageNumber = request.PageNumber,
+ PageSize = request.PageSize
+ };
+
+ if (request.UserId.HasValue)
+ grpcRequest.UserId = request.UserId.Value;
+
+ if (request.PaymentStatus.HasValue)
+ grpcRequest.PaymentStatus = request.PaymentStatus.Value;
+
+ if (request.DeliveryStatus.HasValue)
+ grpcRequest.DeliveryStatus = request.DeliveryStatus.Value;
+
+ if (!string.IsNullOrWhiteSpace(request.UserMobile))
+ grpcRequest.UserMobile = request.UserMobile;
+
+ if (!string.IsNullOrWhiteSpace(request.TrackingCode))
+ grpcRequest.TrackingCode = request.TrackingCode;
+
+ if (request.FromDate.HasValue)
+ grpcRequest.FromDate = Timestamp.FromDateTime(DateTime.SpecifyKind(request.FromDate.Value, DateTimeKind.Utc));
+
+ if (request.ToDate.HasValue)
+ grpcRequest.ToDate = Timestamp.FromDateTime(DateTime.SpecifyKind(request.ToDate.Value, DateTimeKind.Utc));
+
+ if (request.MinAmount.HasValue)
+ grpcRequest.MinAmount = request.MinAmount.Value;
+
+ if (request.MaxAmount.HasValue)
+ grpcRequest.MaxAmount = request.MaxAmount.Value;
+
+ var response = await _context.DiscountOrders.GetAllDiscountOrdersAsync(grpcRequest, cancellationToken: cancellationToken);
+
+ return new GetAllDiscountOrdersResponseDto
+ {
+ MetaData = new MetaData
+ {
+ CurrentPage = response.MetaData.CurrentPage,
+ TotalPage = response.MetaData.TotalPage,
+ PageSize = response.MetaData.PageSize,
+ TotalCount = response.MetaData.TotalCount,
+ HasPrevious = response.MetaData.HasPrevious,
+ HasNext = response.MetaData.HasNext
+ },
+ Orders = response.Models.Select(o => new AdminOrderDto
+ {
+ Id = o.Id,
+ UserId = o.UserId,
+ UserFullName = o.UserFullName,
+ UserMobile = o.UserMobile,
+ TotalAmount = o.TotalAmount,
+ DiscountBalanceUsed = o.DiscountBalanceUsed,
+ GatewayAmountPaid = o.GatewayAmountPaid,
+ VatAmount = o.VatAmount,
+ PaymentStatus = (int)o.PaymentStatus,
+ PaymentDate = o.PaymentDate?.ToDateTime(),
+ DeliveryStatus = (int)o.DeliveryStatus,
+ DeliveryDate = o.DeliveryDate?.ToDateTime(),
+ ShippingAddress = o.ShippingAddress,
+ ReceiverName = o.ReceiverName,
+ ReceiverMobile = o.ReceiverMobile,
+ TrackingCode = o.TrackingCode,
+ AdminNote = o.AdminNote,
+ Created = o.Created.ToDateTime(),
+ LastModified = o.LastModified?.ToDateTime(),
+ ItemsCount = o.ItemsCount
+ }).ToList()
+ };
+ }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetDiscountSalesReport/GetDiscountSalesReportQuery.cs b/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetDiscountSalesReport/GetDiscountSalesReportQuery.cs
new file mode 100644
index 0000000..01f1cee
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetDiscountSalesReport/GetDiscountSalesReportQuery.cs
@@ -0,0 +1,53 @@
+namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetDiscountSalesReport;
+
+public class GetDiscountSalesReportQuery : IRequest
+{
+ public DateTime FromDate { get; set; }
+ public DateTime ToDate { get; set; }
+ public ReportPeriodType PeriodType { get; set; } = ReportPeriodType.Daily;
+}
+
+public enum ReportPeriodType
+{
+ Summary = 0,
+ Daily = 1,
+ Weekly = 2,
+ Monthly = 3
+}
+
+public class DiscountSalesReportDto
+{
+ public DateTime FromDate { get; set; }
+ public DateTime ToDate { get; set; }
+ public ReportPeriodType PeriodType { get; set; }
+ public SalesSummaryDto Summary { get; set; } = new();
+ public List Periods { get; set; } = new();
+}
+
+public class SalesSummaryDto
+{
+ public int TotalOrders { get; set; }
+ public int SuccessfulOrders { get; set; }
+ public int PendingOrders { get; set; }
+ public int RejectedOrders { get; set; }
+ public decimal TotalRevenue { get; set; }
+ public decimal TotalDiscountUsed { get; set; }
+ public decimal TotalGatewayPayments { get; set; }
+ public decimal TotalVat { get; set; }
+ public int TotalItemsSold { get; set; }
+ public int UniqueCustomers { get; set; }
+ public decimal AverageOrderValue { get; set; }
+}
+
+public class PeriodSalesDto
+{
+ public string PeriodLabel { get; set; } = string.Empty;
+ public DateTime PeriodStart { get; set; }
+ public DateTime PeriodEnd { get; set; }
+ public int OrderCount { get; set; }
+ public decimal Revenue { get; set; }
+ public decimal DiscountUsed { get; set; }
+ public decimal GatewayPayments { get; set; }
+ public decimal VatAmount { get; set; }
+ public int ItemsSold { get; set; }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetDiscountSalesReport/GetDiscountSalesReportQueryHandler.cs b/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetDiscountSalesReport/GetDiscountSalesReportQueryHandler.cs
new file mode 100644
index 0000000..c763937
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountOrderCQ/Queries/GetDiscountSalesReport/GetDiscountSalesReportQueryHandler.cs
@@ -0,0 +1,59 @@
+using CMSMicroservice.Protobuf.Protos.DiscountOrder;
+using Google.Protobuf.WellKnownTypes;
+
+namespace BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetDiscountSalesReport;
+
+public class GetDiscountSalesReportQueryHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public GetDiscountSalesReportQueryHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(GetDiscountSalesReportQuery request, CancellationToken cancellationToken)
+ {
+ var grpcRequest = new GetDiscountSalesReportRequest
+ {
+ FromDate = Timestamp.FromDateTime(DateTime.SpecifyKind(request.FromDate, DateTimeKind.Utc)),
+ ToDate = Timestamp.FromDateTime(DateTime.SpecifyKind(request.ToDate, DateTimeKind.Utc)),
+ ReportType = (SalesReportType)request.PeriodType
+ };
+
+ var response = await _context.DiscountOrders.GetDiscountSalesReportAsync(grpcRequest, cancellationToken: cancellationToken);
+
+ return new DiscountSalesReportDto
+ {
+ FromDate = request.FromDate,
+ ToDate = request.ToDate,
+ PeriodType = request.PeriodType,
+ Summary = new SalesSummaryDto
+ {
+ TotalOrders = response.Summary.TotalOrders,
+ SuccessfulOrders = response.Summary.CompletedOrders,
+ PendingOrders = response.Summary.PendingOrders,
+ RejectedOrders = response.Summary.CancelledOrders,
+ TotalRevenue = response.Summary.TotalSalesAmount,
+ TotalDiscountUsed = response.Summary.TotalDiscountUsed,
+ TotalGatewayPayments = response.Summary.TotalGatewayPaid,
+ TotalVat = response.Summary.TotalVatAmount,
+ TotalItemsSold = response.Summary.TotalProductsSold,
+ UniqueCustomers = response.Summary.UniqueCustomers,
+ AverageOrderValue = response.Summary.AverageOrderValue
+ },
+ Periods = response.Periods.Select(p => new PeriodSalesDto
+ {
+ PeriodLabel = p.PeriodLabel,
+ PeriodStart = p.PeriodStart.ToDateTime(),
+ PeriodEnd = p.PeriodEnd.ToDateTime(),
+ OrderCount = p.OrdersCount,
+ Revenue = p.TotalAmount,
+ DiscountUsed = p.DiscountUsed,
+ GatewayPayments = p.GatewayPaid,
+ VatAmount = 0, // Not in proto response
+ ItemsSold = 0 // Not in proto response
+ }).ToList()
+ };
+ }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/AddDiscountProductImage/AddDiscountProductImageCommand.cs b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/AddDiscountProductImage/AddDiscountProductImageCommand.cs
new file mode 100644
index 0000000..cb1d773
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/AddDiscountProductImage/AddDiscountProductImageCommand.cs
@@ -0,0 +1,22 @@
+namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.AddDiscountProductImage;
+
+public class AddDiscountProductImageCommand : IRequest
+{
+ public long DiscountProductId { get; set; }
+ public ImageFileInput? ImageFile { get; set; }
+ public ImageFileInput? ThumbnailFile { get; set; }
+ public string? Title { get; set; }
+ public string? AltText { get; set; }
+}
+
+public class ImageFileInput
+{
+ public byte[] Data { get; set; } = [];
+ public string FileName { get; set; } = string.Empty;
+ public string MimeType { get; set; } = string.Empty;
+}
+
+public class AddDiscountProductImageResponseDto
+{
+ public long ImageId { get; set; }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/AddDiscountProductImage/AddDiscountProductImageCommandHandler.cs b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/AddDiscountProductImage/AddDiscountProductImageCommandHandler.cs
new file mode 100644
index 0000000..468c5bf
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/AddDiscountProductImage/AddDiscountProductImageCommandHandler.cs
@@ -0,0 +1,67 @@
+using CMSMicroservice.Protobuf.Protos.DiscountProduct;
+using Google.Protobuf;
+
+namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.AddDiscountProductImage;
+
+public class AddDiscountProductImageCommandHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public AddDiscountProductImageCommandHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(AddDiscountProductImageCommand request, CancellationToken cancellationToken)
+ {
+ var addRequest = new AddDiscountProductImageRequest
+ {
+ DiscountProductId = request.DiscountProductId
+ };
+
+ if (!string.IsNullOrWhiteSpace(request.Title))
+ addRequest.Title = request.Title;
+
+ if (!string.IsNullOrWhiteSpace(request.AltText))
+ addRequest.AltText = request.AltText;
+
+ // Upload Image
+ if (request.ImageFile != null && request.ImageFile.Data != null && request.ImageFile.Data.Length > 0)
+ {
+ var imageFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
+ {
+ Directory = "Images/DiscountShop/Products/Gallery",
+ IsBase64 = false,
+ MIME = request.ImageFile.MimeType,
+ FileName = request.ImageFile.FileName,
+ File = ByteString.CopyFrom(request.ImageFile.Data)
+ }, cancellationToken: cancellationToken);
+
+ if (imageFileInfo != null && !string.IsNullOrWhiteSpace(imageFileInfo.File))
+ addRequest.ImagePath = imageFileInfo.File;
+ }
+
+ // Upload Thumbnail
+ if (request.ThumbnailFile != null && request.ThumbnailFile.Data != null && request.ThumbnailFile.Data.Length > 0)
+ {
+ var thumbnailFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
+ {
+ Directory = "Images/DiscountShop/Products/Gallery/Thumbnails",
+ IsBase64 = false,
+ MIME = request.ThumbnailFile.MimeType,
+ FileName = request.ThumbnailFile.FileName,
+ File = ByteString.CopyFrom(request.ThumbnailFile.Data)
+ }, cancellationToken: cancellationToken);
+
+ if (thumbnailFileInfo != null && !string.IsNullOrWhiteSpace(thumbnailFileInfo.File))
+ addRequest.ThumbnailPath = thumbnailFileInfo.File;
+ }
+
+ var response = await _context.DiscountProducts.AddDiscountProductImageAsync(addRequest, cancellationToken: cancellationToken);
+
+ return new AddDiscountProductImageResponseDto
+ {
+ ImageId = response.ImageId
+ };
+ }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/DeleteDiscountProductImage/DeleteDiscountProductImageCommand.cs b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/DeleteDiscountProductImage/DeleteDiscountProductImageCommand.cs
new file mode 100644
index 0000000..8e9fbf1
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/DeleteDiscountProductImage/DeleteDiscountProductImageCommand.cs
@@ -0,0 +1,6 @@
+namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.DeleteDiscountProductImage;
+
+public class DeleteDiscountProductImageCommand : IRequest
+{
+ public long Id { get; set; }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/DeleteDiscountProductImage/DeleteDiscountProductImageCommandHandler.cs b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/DeleteDiscountProductImage/DeleteDiscountProductImageCommandHandler.cs
new file mode 100644
index 0000000..5ed2890
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/DeleteDiscountProductImage/DeleteDiscountProductImageCommandHandler.cs
@@ -0,0 +1,23 @@
+using CMSMicroservice.Protobuf.Protos.DiscountProduct;
+
+namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.DeleteDiscountProductImage;
+
+public class DeleteDiscountProductImageCommandHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public DeleteDiscountProductImageCommandHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(DeleteDiscountProductImageCommand request, CancellationToken cancellationToken)
+ {
+ await _context.DiscountProducts.DeleteDiscountProductImageAsync(new DeleteDiscountProductImageRequest
+ {
+ Id = request.Id
+ }, cancellationToken: cancellationToken);
+
+ return Unit.Value;
+ }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/ReorderDiscountProductImages/ReorderDiscountProductImagesCommand.cs b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/ReorderDiscountProductImages/ReorderDiscountProductImagesCommand.cs
new file mode 100644
index 0000000..1637a57
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/ReorderDiscountProductImages/ReorderDiscountProductImagesCommand.cs
@@ -0,0 +1,7 @@
+namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.ReorderDiscountProductImages;
+
+public class ReorderDiscountProductImagesCommand : IRequest
+{
+ public long DiscountProductId { get; set; }
+ public List ImageIds { get; set; } = new();
+}
diff --git a/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/ReorderDiscountProductImages/ReorderDiscountProductImagesCommandHandler.cs b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/ReorderDiscountProductImages/ReorderDiscountProductImagesCommandHandler.cs
new file mode 100644
index 0000000..5f877d8
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/ReorderDiscountProductImages/ReorderDiscountProductImagesCommandHandler.cs
@@ -0,0 +1,26 @@
+using CMSMicroservice.Protobuf.Protos.DiscountProduct;
+
+namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.ReorderDiscountProductImages;
+
+public class ReorderDiscountProductImagesCommandHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public ReorderDiscountProductImagesCommandHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(ReorderDiscountProductImagesCommand request, CancellationToken cancellationToken)
+ {
+ var reorderRequest = new ReorderDiscountProductImagesRequest
+ {
+ DiscountProductId = request.DiscountProductId
+ };
+ reorderRequest.ImageIds.AddRange(request.ImageIds);
+
+ await _context.DiscountProducts.ReorderDiscountProductImagesAsync(reorderRequest, cancellationToken: cancellationToken);
+
+ return Unit.Value;
+ }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/UpdateDiscountProductImage/UpdateDiscountProductImageCommand.cs b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/UpdateDiscountProductImage/UpdateDiscountProductImageCommand.cs
new file mode 100644
index 0000000..872bfcb
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/UpdateDiscountProductImage/UpdateDiscountProductImageCommand.cs
@@ -0,0 +1,13 @@
+using BackOffice.BFF.Application.DiscountProductCQ.Commands.AddDiscountProductImage;
+
+namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.UpdateDiscountProductImage;
+
+public class UpdateDiscountProductImageCommand : IRequest
+{
+ public long Id { get; set; }
+ public ImageFileInput? ImageFile { get; set; }
+ public ImageFileInput? ThumbnailFile { get; set; }
+ public string? Title { get; set; }
+ public string? AltText { get; set; }
+ public bool IsActive { get; set; }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/UpdateDiscountProductImage/UpdateDiscountProductImageCommandHandler.cs b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/UpdateDiscountProductImage/UpdateDiscountProductImageCommandHandler.cs
new file mode 100644
index 0000000..382f7a9
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountProductCQ/Commands/UpdateDiscountProductImage/UpdateDiscountProductImageCommandHandler.cs
@@ -0,0 +1,65 @@
+using CMSMicroservice.Protobuf.Protos.DiscountProduct;
+using Google.Protobuf;
+
+namespace BackOffice.BFF.Application.DiscountProductCQ.Commands.UpdateDiscountProductImage;
+
+public class UpdateDiscountProductImageCommandHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public UpdateDiscountProductImageCommandHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(UpdateDiscountProductImageCommand request, CancellationToken cancellationToken)
+ {
+ var updateRequest = new UpdateDiscountProductImageRequest
+ {
+ Id = request.Id,
+ IsActive = request.IsActive
+ };
+
+ if (!string.IsNullOrWhiteSpace(request.Title))
+ updateRequest.Title = request.Title;
+
+ if (!string.IsNullOrWhiteSpace(request.AltText))
+ updateRequest.AltText = request.AltText;
+
+ // Upload new Image if provided
+ if (request.ImageFile != null && request.ImageFile.Data != null && request.ImageFile.Data.Length > 0)
+ {
+ var imageFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
+ {
+ Directory = "Images/DiscountShop/Products/Gallery",
+ IsBase64 = false,
+ MIME = request.ImageFile.MimeType,
+ FileName = request.ImageFile.FileName,
+ File = ByteString.CopyFrom(request.ImageFile.Data)
+ }, cancellationToken: cancellationToken);
+
+ if (imageFileInfo != null && !string.IsNullOrWhiteSpace(imageFileInfo.File))
+ updateRequest.ImagePath = imageFileInfo.File;
+ }
+
+ // Upload new Thumbnail if provided
+ if (request.ThumbnailFile != null && request.ThumbnailFile.Data != null && request.ThumbnailFile.Data.Length > 0)
+ {
+ var thumbnailFileInfo = await _context.FileInfos.CreateNewFileInfoAsync(new()
+ {
+ Directory = "Images/DiscountShop/Products/Gallery/Thumbnails",
+ IsBase64 = false,
+ MIME = request.ThumbnailFile.MimeType,
+ FileName = request.ThumbnailFile.FileName,
+ File = ByteString.CopyFrom(request.ThumbnailFile.Data)
+ }, cancellationToken: cancellationToken);
+
+ if (thumbnailFileInfo != null && !string.IsNullOrWhiteSpace(thumbnailFileInfo.File))
+ updateRequest.ThumbnailPath = thumbnailFileInfo.File;
+ }
+
+ await _context.DiscountProducts.UpdateDiscountProductImageAsync(updateRequest, cancellationToken: cancellationToken);
+
+ return Unit.Value;
+ }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountProductCQ/Queries/GetDiscountProductImages/GetDiscountProductImagesQuery.cs b/src/BackOffice.BFF.Application/DiscountProductCQ/Queries/GetDiscountProductImages/GetDiscountProductImagesQuery.cs
new file mode 100644
index 0000000..bfa0112
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountProductCQ/Queries/GetDiscountProductImages/GetDiscountProductImagesQuery.cs
@@ -0,0 +1,24 @@
+namespace BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProductImages;
+
+public class GetDiscountProductImagesQuery : IRequest
+{
+ public long DiscountProductId { get; set; }
+ public bool OnlyActive { get; set; } = false; // Admin can see all
+}
+
+public class GetDiscountProductImagesResponseDto
+{
+ public List Images { get; set; } = new();
+}
+
+public class DiscountProductImageDto
+{
+ public long Id { get; set; }
+ public long DiscountProductId { get; set; }
+ public string ImagePath { get; set; } = string.Empty;
+ public string? ThumbnailPath { get; set; }
+ public string? Title { get; set; }
+ public string? AltText { get; set; }
+ public int SortOrder { get; set; }
+ public bool IsActive { get; set; }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountProductCQ/Queries/GetDiscountProductImages/GetDiscountProductImagesQueryHandler.cs b/src/BackOffice.BFF.Application/DiscountProductCQ/Queries/GetDiscountProductImages/GetDiscountProductImagesQueryHandler.cs
new file mode 100644
index 0000000..3da89d8
--- /dev/null
+++ b/src/BackOffice.BFF.Application/DiscountProductCQ/Queries/GetDiscountProductImages/GetDiscountProductImagesQueryHandler.cs
@@ -0,0 +1,39 @@
+using CMSMicroservice.Protobuf.Protos.DiscountProduct;
+
+namespace BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProductImages;
+
+public class GetDiscountProductImagesQueryHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public GetDiscountProductImagesQueryHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(GetDiscountProductImagesQuery request, CancellationToken cancellationToken)
+ {
+ var grpcRequest = new GetDiscountProductImagesRequest
+ {
+ DiscountProductId = request.DiscountProductId,
+ OnlyActive = request.OnlyActive
+ };
+
+ var response = await _context.DiscountProducts.GetDiscountProductImagesAsync(grpcRequest, cancellationToken: cancellationToken);
+
+ return new GetDiscountProductImagesResponseDto
+ {
+ Images = response.Images.Select(i => new DiscountProductImageDto
+ {
+ Id = i.Id,
+ DiscountProductId = i.DiscountProductId,
+ ImagePath = i.ImagePath,
+ ThumbnailPath = i.ThumbnailPath,
+ Title = i.Title,
+ AltText = i.AltText,
+ SortOrder = i.SortOrder,
+ IsActive = i.IsActive
+ }).ToList()
+ };
+ }
+}
diff --git a/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/RemoveFromCart/RemoveFromCartCommand.cs b/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/RemoveFromCart/RemoveFromCartCommand.cs
index c433270..6335f2a 100644
--- a/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/RemoveFromCart/RemoveFromCartCommand.cs
+++ b/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/RemoveFromCart/RemoveFromCartCommand.cs
@@ -5,6 +5,6 @@ public record RemoveFromCartCommand : IRequest
/// شناسه کاربر
public long UserId { get; init; }
- /// شناسه آیتم سبد خرید
- public long CartItemId { get; init; }
+ /// شناسه محصول
+ public long ProductId { get; init; }
}
diff --git a/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/RemoveFromCart/RemoveFromCartCommandHandler.cs b/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/RemoveFromCart/RemoveFromCartCommandHandler.cs
index 88c3f29..0f14d7a 100644
--- a/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/RemoveFromCart/RemoveFromCartCommandHandler.cs
+++ b/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/RemoveFromCart/RemoveFromCartCommandHandler.cs
@@ -17,7 +17,7 @@ public class RemoveFromCartCommandHandler : IRequestHandler x.UserId)
.GreaterThan(0).WithMessage("شناسه کاربر نامعتبر است");
- RuleFor(x => x.CartItemId)
- .GreaterThan(0).WithMessage("شناسه آیتم سبد خرید نامعتبر است");
+ RuleFor(x => x.ProductId)
+ .GreaterThan(0).WithMessage("شناسه محصول نامعتبر است");
}
}
diff --git a/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/UpdateCartItemCount/UpdateCartItemCountCommand.cs b/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/UpdateCartItemCount/UpdateCartItemCountCommand.cs
index 1827200..16bb878 100644
--- a/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/UpdateCartItemCount/UpdateCartItemCountCommand.cs
+++ b/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/UpdateCartItemCount/UpdateCartItemCountCommand.cs
@@ -5,8 +5,8 @@ public record UpdateCartItemCountCommand : IRequest
/// شناسه کاربر
public long UserId { get; init; }
- /// شناسه آیتم سبد خرید
- public long CartItemId { get; init; }
+ /// شناسه محصول
+ public long ProductId { get; init; }
/// تعداد جدید
public int NewCount { get; init; }
diff --git a/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/UpdateCartItemCount/UpdateCartItemCountCommandHandler.cs b/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/UpdateCartItemCount/UpdateCartItemCountCommandHandler.cs
index 5a9e815..b685233 100644
--- a/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/UpdateCartItemCount/UpdateCartItemCountCommandHandler.cs
+++ b/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Commands/UpdateCartItemCount/UpdateCartItemCountCommandHandler.cs
@@ -17,7 +17,7 @@ public class UpdateCartItemCountCommandHandler : IRequestHandler x.UserId)
.GreaterThan(0).WithMessage("شناسه کاربر نامعتبر است");
- RuleFor(x => x.CartItemId)
- .GreaterThan(0).WithMessage("شناسه آیتم سبد خرید نامعتبر است");
+ RuleFor(x => x.ProductId)
+ .GreaterThan(0).WithMessage("شناسه محصول نامعتبر است");
RuleFor(x => x.NewCount)
.GreaterThan(0).WithMessage("تعداد جدید باید بیشتر از صفر باشد");
diff --git a/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Queries/GetUserCart/GetUserCartQueryHandler.cs b/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Queries/GetUserCart/GetUserCartQueryHandler.cs
index 48541ed..3bc13b0 100644
--- a/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Queries/GetUserCart/GetUserCartQueryHandler.cs
+++ b/src/BackOffice.BFF.Application/DiscountShoppingCartCQ/Queries/GetUserCart/GetUserCartQueryHandler.cs
@@ -19,13 +19,11 @@ public class GetUserCartQueryHandler : IRequestHandler new CartItemDto
{
- Id = item.Id,
ProductId = item.ProductId,
ProductTitle = item.ProductTitle,
ProductImagePath = item.ProductImagePath,
@@ -33,8 +31,10 @@ public class GetUserCartQueryHandler : IRequestHandler Items { get; set; } = new();
+ /// جمع کل قیمت (بدون تخفیف)
public long TotalPrice { get; set; }
- public long TotalDiscountedPrice { get; set; }
- public long TotalSavings { get; set; }
+ /// جمع تخفیفها
+ public long TotalDiscountAmount { get; set; }
+ /// قیمت نهایی (با تخفیف)
+ public long FinalPrice { 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 string ProductTitle { get; set; } = string.Empty;
+ public string ProductImagePath { get; set; } = string.Empty;
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; }
+ /// مبلغ تخفیف
+ public long DiscountAmount { get; set; }
+ /// قیمت نهایی آیتم
+ public long FinalPrice { get; set; }
+ public int ProductRemainingCount { get; set; }
+ public DateTime Created { get; set; }
}
diff --git a/src/BackOffice.BFF.Application/ProductTagCQ/Commands/DeleteProductTag/DeleteProductTagCommand.cs b/src/BackOffice.BFF.Application/ProductTagCQ/Commands/DeleteProductTag/DeleteProductTagCommand.cs
new file mode 100644
index 0000000..2c39edf
--- /dev/null
+++ b/src/BackOffice.BFF.Application/ProductTagCQ/Commands/DeleteProductTag/DeleteProductTagCommand.cs
@@ -0,0 +1,6 @@
+namespace BackOffice.BFF.Application.ProductTagCQ.Commands.DeleteProductTag;
+
+public record DeleteProductTagCommand : IRequest
+{
+ public long Id { get; init; }
+}
diff --git a/src/BackOffice.BFF.Application/ProductTagCQ/Commands/DeleteProductTag/DeleteProductTagCommandHandler.cs b/src/BackOffice.BFF.Application/ProductTagCQ/Commands/DeleteProductTag/DeleteProductTagCommandHandler.cs
new file mode 100644
index 0000000..22ff6a4
--- /dev/null
+++ b/src/BackOffice.BFF.Application/ProductTagCQ/Commands/DeleteProductTag/DeleteProductTagCommandHandler.cs
@@ -0,0 +1,25 @@
+using CMSMicroservice.Protobuf.Protos.ProductTag;
+
+namespace BackOffice.BFF.Application.ProductTagCQ.Commands.DeleteProductTag;
+
+public class DeleteProductTagCommandHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public DeleteProductTagCommandHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(DeleteProductTagCommand request, CancellationToken cancellationToken)
+ {
+ await _context.ProductTags.DeleteProductTagAsync(
+ new DeleteProductTagRequest
+ {
+ Id = request.Id
+ },
+ cancellationToken: cancellationToken);
+
+ return Unit.Value;
+ }
+}
diff --git a/src/BackOffice.BFF.Application/ProductTagCQ/Commands/UpdateProductTag/UpdateProductTagCommand.cs b/src/BackOffice.BFF.Application/ProductTagCQ/Commands/UpdateProductTag/UpdateProductTagCommand.cs
new file mode 100644
index 0000000..e4e425c
--- /dev/null
+++ b/src/BackOffice.BFF.Application/ProductTagCQ/Commands/UpdateProductTag/UpdateProductTagCommand.cs
@@ -0,0 +1,8 @@
+namespace BackOffice.BFF.Application.ProductTagCQ.Commands.UpdateProductTag;
+
+public record UpdateProductTagCommand : IRequest
+{
+ public long Id { get; init; }
+ public long ProductId { get; init; }
+ public long TagId { get; init; }
+}
diff --git a/src/BackOffice.BFF.Application/ProductTagCQ/Commands/UpdateProductTag/UpdateProductTagCommandHandler.cs b/src/BackOffice.BFF.Application/ProductTagCQ/Commands/UpdateProductTag/UpdateProductTagCommandHandler.cs
new file mode 100644
index 0000000..cbd9edd
--- /dev/null
+++ b/src/BackOffice.BFF.Application/ProductTagCQ/Commands/UpdateProductTag/UpdateProductTagCommandHandler.cs
@@ -0,0 +1,27 @@
+using CMSMicroservice.Protobuf.Protos.ProductTag;
+
+namespace BackOffice.BFF.Application.ProductTagCQ.Commands.UpdateProductTag;
+
+public class UpdateProductTagCommandHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public UpdateProductTagCommandHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(UpdateProductTagCommand request, CancellationToken cancellationToken)
+ {
+ await _context.ProductTags.UpdateProductTagAsync(
+ new UpdateProductTagRequest
+ {
+ Id = request.Id,
+ ProductId = request.ProductId,
+ TagId = request.TagId
+ },
+ cancellationToken: cancellationToken);
+
+ return Unit.Value;
+ }
+}
diff --git a/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetAllProductTags/GetAllProductTagsQuery.cs b/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetAllProductTags/GetAllProductTagsQuery.cs
new file mode 100644
index 0000000..915ec0f
--- /dev/null
+++ b/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetAllProductTags/GetAllProductTagsQuery.cs
@@ -0,0 +1,23 @@
+namespace BackOffice.BFF.Application.ProductTagCQ.Queries.GetAllProductTags;
+
+public record GetAllProductTagsQuery : IRequest
+{
+ public int PageNumber { get; init; } = 1;
+ public int PageSize { get; init; } = 10;
+ public string? SortBy { get; init; }
+ public long? ProductId { get; init; }
+ public long? TagId { get; init; }
+}
+
+public record GetAllProductTagsResponseDto
+{
+ public MetaData MetaData { get; init; } = default!;
+ public List Items { get; init; } = new();
+}
+
+public record ProductTagItemDto
+{
+ public long Id { get; init; }
+ public long ProductId { get; init; }
+ public long TagId { get; init; }
+}
diff --git a/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetAllProductTags/GetAllProductTagsQueryHandler.cs b/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetAllProductTags/GetAllProductTagsQueryHandler.cs
new file mode 100644
index 0000000..a46d702
--- /dev/null
+++ b/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetAllProductTags/GetAllProductTagsQueryHandler.cs
@@ -0,0 +1,51 @@
+using CMSMicroservice.Protobuf.Protos.ProductTag;
+using CmsPaginationState = CMSMicroservice.Protobuf.Protos.PaginationState;
+
+namespace BackOffice.BFF.Application.ProductTagCQ.Queries.GetAllProductTags;
+
+public class GetAllProductTagsQueryHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public GetAllProductTagsQueryHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(GetAllProductTagsQuery request, CancellationToken cancellationToken)
+ {
+ var response = await _context.ProductTags.GetAllProductTagByFilterAsync(
+ new GetAllProductTagByFilterRequest
+ {
+ PaginationState = new CmsPaginationState
+ {
+ PageNumber = request.PageNumber,
+ PageSize = request.PageSize
+ },
+ SortBy = request.SortBy ?? "",
+ Filter = new GetAllProductTagByFilterFilter
+ {
+ ProductId = request.ProductId ?? 0,
+ TagId = request.TagId ?? 0
+ }
+ },
+ cancellationToken: cancellationToken);
+
+ return new GetAllProductTagsResponseDto
+ {
+ MetaData = new MetaData
+ {
+ CurrentPage = response.MetaData.CurrentPage,
+ PageSize = response.MetaData.PageSize,
+ TotalCount = response.MetaData.TotalCount,
+ TotalPage = response.MetaData.TotalPage
+ },
+ Items = response.Models.Select(pt => new ProductTagItemDto
+ {
+ Id = pt.Id,
+ ProductId = pt.ProductId,
+ TagId = pt.TagId
+ }).ToList()
+ };
+ }
+}
diff --git a/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetProductTag/GetProductTagQuery.cs b/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetProductTag/GetProductTagQuery.cs
new file mode 100644
index 0000000..f1161ff
--- /dev/null
+++ b/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetProductTag/GetProductTagQuery.cs
@@ -0,0 +1,13 @@
+namespace BackOffice.BFF.Application.ProductTagCQ.Queries.GetProductTag;
+
+public record GetProductTagQuery : IRequest
+{
+ public long Id { get; init; }
+}
+
+public record GetProductTagResponseDto
+{
+ public long Id { get; init; }
+ public long ProductId { get; init; }
+ public long TagId { get; init; }
+}
diff --git a/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetProductTag/GetProductTagQueryHandler.cs b/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetProductTag/GetProductTagQueryHandler.cs
new file mode 100644
index 0000000..ca4737f
--- /dev/null
+++ b/src/BackOffice.BFF.Application/ProductTagCQ/Queries/GetProductTag/GetProductTagQueryHandler.cs
@@ -0,0 +1,30 @@
+using CMSMicroservice.Protobuf.Protos.ProductTag;
+
+namespace BackOffice.BFF.Application.ProductTagCQ.Queries.GetProductTag;
+
+public class GetProductTagQueryHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+
+ public GetProductTagQueryHandler(IApplicationContractContext context)
+ {
+ _context = context;
+ }
+
+ public async Task Handle(GetProductTagQuery request, CancellationToken cancellationToken)
+ {
+ var response = await _context.ProductTags.GetProductTagAsync(
+ new GetProductTagRequest
+ {
+ Id = request.Id
+ },
+ cancellationToken: cancellationToken);
+
+ return new GetProductTagResponseDto
+ {
+ Id = response.Id,
+ ProductId = response.ProductId,
+ TagId = response.TagId
+ };
+ }
+}
diff --git a/src/BackOffice.BFF.Domain/BackOffice.BFF.Domain.csproj b/src/BackOffice.BFF.Domain/BackOffice.BFF.Domain.csproj
index 35db127..a1e62ee 100644
--- a/src/BackOffice.BFF.Domain/BackOffice.BFF.Domain.csproj
+++ b/src/BackOffice.BFF.Domain/BackOffice.BFF.Domain.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/src/BackOffice.BFF.WebApi/BackOffice.BFF.WebApi.csproj b/src/BackOffice.BFF.WebApi/BackOffice.BFF.WebApi.csproj
index 795a1dc..6ac4fec 100644
--- a/src/BackOffice.BFF.WebApi/BackOffice.BFF.WebApi.csproj
+++ b/src/BackOffice.BFF.WebApi/BackOffice.BFF.WebApi.csproj
@@ -42,6 +42,12 @@
+
+
+
+
+
+
diff --git a/src/BackOffice.BFF.WebApi/Services/DiscountCategoryService.cs b/src/BackOffice.BFF.WebApi/Services/DiscountCategoryService.cs
new file mode 100644
index 0000000..4a26056
--- /dev/null
+++ b/src/BackOffice.BFF.WebApi/Services/DiscountCategoryService.cs
@@ -0,0 +1,38 @@
+using BackOffice.BFF.DiscountCategory.Protobuf.Protos.DiscountCategory;
+using BackOffice.BFF.WebApi.Common.Services;
+using BackOffice.BFF.Application.DiscountCategoryCQ.Commands.CreateDiscountCategory;
+using BackOffice.BFF.Application.DiscountCategoryCQ.Commands.UpdateDiscountCategory;
+using BackOffice.BFF.Application.DiscountCategoryCQ.Commands.DeleteDiscountCategory;
+using BackOffice.BFF.Application.DiscountCategoryCQ.Queries.GetDiscountCategories;
+
+namespace BackOffice.BFF.WebApi.Services;
+
+public class DiscountCategoryService : DiscountCategoryContract.DiscountCategoryContractBase
+{
+ private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
+
+ public DiscountCategoryService(IDispatchRequestToCQRS dispatchRequestToCQRS)
+ {
+ _dispatchRequestToCQRS = dispatchRequestToCQRS;
+ }
+
+ public override async Task CreateDiscountCategory(CreateDiscountCategoryRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task UpdateDiscountCategory(UpdateDiscountCategoryRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task DeleteDiscountCategory(DeleteDiscountCategoryRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetDiscountCategories(GetDiscountCategoriesRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+}
diff --git a/src/BackOffice.BFF.WebApi/Services/DiscountOrderService.cs b/src/BackOffice.BFF.WebApi/Services/DiscountOrderService.cs
new file mode 100644
index 0000000..a89ff8b
--- /dev/null
+++ b/src/BackOffice.BFF.WebApi/Services/DiscountOrderService.cs
@@ -0,0 +1,59 @@
+using BackOffice.BFF.DiscountOrder.Protobuf.Protos.DiscountOrder;
+using BackOffice.BFF.WebApi.Common.Services;
+using BackOffice.BFF.Application.DiscountOrderCQ.Commands.PlaceOrder;
+using BackOffice.BFF.Application.DiscountOrderCQ.Commands.CompleteOrderPayment;
+using BackOffice.BFF.Application.DiscountOrderCQ.Commands.UpdateOrderStatus;
+using BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetOrderById;
+using BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetUserOrders;
+using BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetAllDiscountOrders;
+using BackOffice.BFF.Application.DiscountOrderCQ.Queries.GetDiscountSalesReport;
+
+namespace BackOffice.BFF.WebApi.Services;
+
+public class DiscountOrderService : DiscountOrderContract.DiscountOrderContractBase
+{
+ private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
+
+ public DiscountOrderService(IDispatchRequestToCQRS dispatchRequestToCQRS)
+ {
+ _dispatchRequestToCQRS = dispatchRequestToCQRS;
+ }
+
+ // Order Management
+ public override async Task PlaceOrder(PlaceOrderRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task CompleteOrderPayment(CompleteOrderPaymentRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task UpdateOrderStatus(UpdateOrderStatusRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ // Order Queries
+ public override async Task GetOrderById(GetOrderByIdRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetUserOrders(GetUserOrdersRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ // Admin APIs
+ public override async Task GetAllDiscountOrders(GetAllDiscountOrdersRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetDiscountSalesReport(GetDiscountSalesReportRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+}
diff --git a/src/BackOffice.BFF.WebApi/Services/DiscountProductService.cs b/src/BackOffice.BFF.WebApi/Services/DiscountProductService.cs
new file mode 100644
index 0000000..b13208e
--- /dev/null
+++ b/src/BackOffice.BFF.WebApi/Services/DiscountProductService.cs
@@ -0,0 +1,76 @@
+using BackOffice.BFF.DiscountProduct.Protobuf.Protos.DiscountProduct;
+using BackOffice.BFF.WebApi.Common.Services;
+using BackOffice.BFF.Application.DiscountProductCQ.Commands.CreateDiscountProduct;
+using BackOffice.BFF.Application.DiscountProductCQ.Commands.UpdateDiscountProduct;
+using BackOffice.BFF.Application.DiscountProductCQ.Commands.DeleteDiscountProduct;
+using BackOffice.BFF.Application.DiscountProductCQ.Commands.AddDiscountProductImage;
+using BackOffice.BFF.Application.DiscountProductCQ.Commands.UpdateDiscountProductImage;
+using BackOffice.BFF.Application.DiscountProductCQ.Commands.DeleteDiscountProductImage;
+using BackOffice.BFF.Application.DiscountProductCQ.Commands.ReorderDiscountProductImages;
+using BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProductById;
+using BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProducts;
+using BackOffice.BFF.Application.DiscountProductCQ.Queries.GetDiscountProductImages;
+
+namespace BackOffice.BFF.WebApi.Services;
+
+public class DiscountProductService : DiscountProductContract.DiscountProductContractBase
+{
+ private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
+
+ public DiscountProductService(IDispatchRequestToCQRS dispatchRequestToCQRS)
+ {
+ _dispatchRequestToCQRS = dispatchRequestToCQRS;
+ }
+
+ // Product CRUD
+ public override async Task CreateDiscountProduct(CreateDiscountProductRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task UpdateDiscountProduct(UpdateDiscountProductRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task DeleteDiscountProduct(DeleteDiscountProductRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetDiscountProductById(GetDiscountProductByIdRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetDiscountProducts(GetDiscountProductsRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ // Product Image Gallery
+ public override async Task AddDiscountProductImage(AddDiscountProductImageRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task UpdateDiscountProductImage(UpdateDiscountProductImageRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task DeleteDiscountProductImage(DeleteDiscountProductImageRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task ReorderDiscountProductImages(ReorderDiscountProductImagesRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetDiscountProductImages(GetDiscountProductImagesRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+}
diff --git a/src/BackOffice.BFF.WebApi/Services/DiscountShoppingCartService.cs b/src/BackOffice.BFF.WebApi/Services/DiscountShoppingCartService.cs
new file mode 100644
index 0000000..65e12bd
--- /dev/null
+++ b/src/BackOffice.BFF.WebApi/Services/DiscountShoppingCartService.cs
@@ -0,0 +1,44 @@
+using BackOffice.BFF.DiscountShoppingCart.Protobuf.Protos.DiscountShoppingCart;
+using BackOffice.BFF.WebApi.Common.Services;
+using BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.AddToCart;
+using BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.RemoveFromCart;
+using BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.UpdateCartItemCount;
+using BackOffice.BFF.Application.DiscountShoppingCartCQ.Commands.ClearCart;
+using BackOffice.BFF.Application.DiscountShoppingCartCQ.Queries.GetUserCart;
+
+namespace BackOffice.BFF.WebApi.Services;
+
+public class DiscountShoppingCartService : DiscountShoppingCartContract.DiscountShoppingCartContractBase
+{
+ private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
+
+ public DiscountShoppingCartService(IDispatchRequestToCQRS dispatchRequestToCQRS)
+ {
+ _dispatchRequestToCQRS = dispatchRequestToCQRS;
+ }
+
+ public override async Task AddToCart(AddToCartRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task RemoveFromCart(RemoveFromCartRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task UpdateCartItemCount(UpdateCartItemCountRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetUserCart(GetUserCartRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task ClearCart(ClearCartRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+}
diff --git a/src/BackOffice.BFF.WebApi/Services/ProductTagService.cs b/src/BackOffice.BFF.WebApi/Services/ProductTagService.cs
new file mode 100644
index 0000000..9abde67
--- /dev/null
+++ b/src/BackOffice.BFF.WebApi/Services/ProductTagService.cs
@@ -0,0 +1,44 @@
+using BackOffice.BFF.ProductTag.Protobuf.Protos.ProductTag;
+using BackOffice.BFF.WebApi.Common.Services;
+using BackOffice.BFF.Application.ProductTagCQ.Commands.AssignTagToProduct;
+using BackOffice.BFF.Application.ProductTagCQ.Commands.UpdateProductTag;
+using BackOffice.BFF.Application.ProductTagCQ.Commands.DeleteProductTag;
+using BackOffice.BFF.Application.ProductTagCQ.Queries.GetProductTag;
+using BackOffice.BFF.Application.ProductTagCQ.Queries.GetAllProductTags;
+
+namespace BackOffice.BFF.WebApi.Services;
+
+public class ProductTagService : ProductTagContract.ProductTagContractBase
+{
+ private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
+
+ public ProductTagService(IDispatchRequestToCQRS dispatchRequestToCQRS)
+ {
+ _dispatchRequestToCQRS = dispatchRequestToCQRS;
+ }
+
+ public override async Task CreateNewProductTag(CreateNewProductTagRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task UpdateProductTag(UpdateProductTagRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task DeleteProductTag(DeleteProductTagRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetProductTag(GetProductTagRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetAllProductTagByFilter(GetAllProductTagByFilterRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+}
diff --git a/src/BackOffice.BFF.WebApi/Services/TagService.cs b/src/BackOffice.BFF.WebApi/Services/TagService.cs
new file mode 100644
index 0000000..54b0ffe
--- /dev/null
+++ b/src/BackOffice.BFF.WebApi/Services/TagService.cs
@@ -0,0 +1,50 @@
+using BackOffice.BFF.Tag.Protobuf.Protos.Tag;
+using BackOffice.BFF.WebApi.Common.Services;
+using BackOffice.BFF.Application.TagCQ.Commands.CreateTag;
+using BackOffice.BFF.Application.TagCQ.Commands.UpdateTag;
+using BackOffice.BFF.Application.TagCQ.Commands.DeleteTag;
+using BackOffice.BFF.Application.TagCQ.Queries.GetTag;
+using BackOffice.BFF.Application.TagCQ.Queries.GetAllTags;
+using BackOffice.BFF.Application.TagCQ.Queries.GetProductsByTag;
+
+namespace BackOffice.BFF.WebApi.Services;
+
+public class TagService : TagContract.TagContractBase
+{
+ private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
+
+ public TagService(IDispatchRequestToCQRS dispatchRequestToCQRS)
+ {
+ _dispatchRequestToCQRS = dispatchRequestToCQRS;
+ }
+
+ public override async Task CreateNewTag(CreateNewTagRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task UpdateTag(UpdateTagRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task DeleteTag(DeleteTagRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetTag(GetTagRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetAllTagByFilter(GetAllTagByFilterRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+
+ public override async Task GetProductsByTag(GetProductsByTagRequest request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+}
diff --git a/src/Protobufs/BackOffice.BFF.DiscountCategory.Protobuf/BackOffice.BFF.DiscountCategory.Protobuf.csproj b/src/Protobufs/BackOffice.BFF.DiscountCategory.Protobuf/BackOffice.BFF.DiscountCategory.Protobuf.csproj
index 7dbc522..3197da1 100644
--- a/src/Protobufs/BackOffice.BFF.DiscountCategory.Protobuf/BackOffice.BFF.DiscountCategory.Protobuf.csproj
+++ b/src/Protobufs/BackOffice.BFF.DiscountCategory.Protobuf/BackOffice.BFF.DiscountCategory.Protobuf.csproj
@@ -4,7 +4,7 @@
net9.0
enable
enable
- 0.0.3
+ 0.0.4
None
False
False
@@ -23,7 +23,7 @@
-
+
diff --git a/src/Protobufs/BackOffice.BFF.DiscountOrder.Protobuf/BackOffice.BFF.DiscountOrder.Protobuf.csproj b/src/Protobufs/BackOffice.BFF.DiscountOrder.Protobuf/BackOffice.BFF.DiscountOrder.Protobuf.csproj
index 8a3a42b..9ee5ea2 100644
--- a/src/Protobufs/BackOffice.BFF.DiscountOrder.Protobuf/BackOffice.BFF.DiscountOrder.Protobuf.csproj
+++ b/src/Protobufs/BackOffice.BFF.DiscountOrder.Protobuf/BackOffice.BFF.DiscountOrder.Protobuf.csproj
@@ -4,7 +4,7 @@
net9.0
enable
enable
- 0.0.3
+ 0.0.4
None
False
False
@@ -23,7 +23,7 @@
-
+
diff --git a/src/Protobufs/BackOffice.BFF.DiscountOrder.Protobuf/Protos/discountorder.proto b/src/Protobufs/BackOffice.BFF.DiscountOrder.Protobuf/Protos/discountorder.proto
index 5739e9d..aa8aa8d 100644
--- a/src/Protobufs/BackOffice.BFF.DiscountOrder.Protobuf/Protos/discountorder.proto
+++ b/src/Protobufs/BackOffice.BFF.DiscountOrder.Protobuf/Protos/discountorder.proto
@@ -40,6 +40,20 @@ service DiscountOrderContract
get: "/GetUserOrders"
};
};
+
+ // Admin: Get All Discount Orders with filters
+ rpc GetAllDiscountOrders(GetAllDiscountOrdersRequest) returns (GetAllDiscountOrdersResponse){
+ option (google.api.http) = {
+ get: "/GetAllDiscountOrders"
+ };
+ };
+
+ // Admin: Get Sales Report
+ rpc GetDiscountSalesReport(GetDiscountSalesReportRequest) returns (GetDiscountSalesReportResponse){
+ option (google.api.http) = {
+ get: "/GetDiscountSalesReport"
+ };
+ };
}
// Place Order (Initial Step - Create Order)
@@ -175,3 +189,118 @@ message OrderSummaryDto
int32 items_count = 9;
google.protobuf.Timestamp created = 10;
}
+
+// ===== Admin: Get All Discount Orders =====
+
+message GetAllDiscountOrdersRequest
+{
+ google.protobuf.Int64Value user_id = 1;
+ google.protobuf.Int32Value payment_status = 2;
+ google.protobuf.Int32Value delivery_status = 3;
+ google.protobuf.StringValue user_mobile = 4;
+ google.protobuf.StringValue tracking_code = 5;
+ google.protobuf.Timestamp from_date = 6;
+ google.protobuf.Timestamp to_date = 7;
+ google.protobuf.Int64Value min_amount = 8;
+ google.protobuf.Int64Value max_amount = 9;
+ int32 page_number = 10;
+ int32 page_size = 11;
+}
+
+message GetAllDiscountOrdersResponse
+{
+ messages.MetaData meta_data = 1;
+ repeated AdminOrderDto models = 2;
+}
+
+message AdminOrderDto
+{
+ int64 id = 1;
+ int64 user_id = 2;
+ string user_full_name = 3;
+ string user_mobile = 4;
+ int64 total_amount = 5;
+ int64 discount_balance_used = 6;
+ int64 gateway_amount_paid = 7;
+ int64 vat_amount = 8;
+ PaymentStatus payment_status = 9;
+ google.protobuf.Timestamp payment_date = 10;
+ DeliveryStatus delivery_status = 11;
+ google.protobuf.Timestamp delivery_date = 12;
+ google.protobuf.StringValue shipping_address = 13;
+ google.protobuf.StringValue receiver_name = 14;
+ google.protobuf.StringValue receiver_mobile = 15;
+ google.protobuf.StringValue tracking_code = 16;
+ google.protobuf.StringValue admin_note = 17;
+ google.protobuf.Timestamp created = 18;
+ google.protobuf.Timestamp last_modified = 19;
+ int32 items_count = 20;
+}
+
+enum PaymentStatus
+{
+ PAYMENT_PENDING = 0;
+ PAYMENT_COMPLETED = 1;
+ PAYMENT_FAILED = 2;
+ PAYMENT_REFUNDED = 3;
+}
+
+// ===== Sales Report Messages =====
+
+enum SalesReportType
+{
+ REPORT_SUMMARY = 0;
+ REPORT_DAILY = 1;
+ REPORT_WEEKLY = 2;
+ REPORT_MONTHLY = 3;
+}
+
+message GetDiscountSalesReportRequest
+{
+ google.protobuf.Timestamp from_date = 1;
+ google.protobuf.Timestamp to_date = 2;
+ SalesReportType report_type = 3;
+}
+
+message GetDiscountSalesReportResponse
+{
+ SalesSummary summary = 1;
+ repeated SalesPeriodDto periods = 2;
+ repeated TopSellingProductDto top_products = 3;
+}
+
+message SalesSummary
+{
+ int32 total_orders = 1;
+ int32 completed_orders = 2;
+ int32 pending_orders = 3;
+ int32 cancelled_orders = 4;
+ int64 total_sales_amount = 5;
+ int64 total_discount_used = 6;
+ int64 total_gateway_paid = 7;
+ int64 total_vat_amount = 8;
+ int64 average_order_value = 9;
+ int32 unique_customers = 10;
+ int32 total_products_sold = 11;
+}
+
+message SalesPeriodDto
+{
+ string period_label = 1;
+ google.protobuf.Timestamp period_start = 2;
+ google.protobuf.Timestamp period_end = 3;
+ int32 orders_count = 4;
+ int64 total_amount = 5;
+ int64 discount_used = 6;
+ int64 gateway_paid = 7;
+}
+
+message TopSellingProductDto
+{
+ int64 product_id = 1;
+ string product_title = 2;
+ google.protobuf.StringValue image_path = 3;
+ int32 quantity_sold = 4;
+ int64 total_revenue = 5;
+ int32 orders_count = 6;
+}
diff --git a/src/Protobufs/BackOffice.BFF.DiscountProduct.Protobuf/BackOffice.BFF.DiscountProduct.Protobuf.csproj b/src/Protobufs/BackOffice.BFF.DiscountProduct.Protobuf/BackOffice.BFF.DiscountProduct.Protobuf.csproj
index dcd57ad..39c585c 100644
--- a/src/Protobufs/BackOffice.BFF.DiscountProduct.Protobuf/BackOffice.BFF.DiscountProduct.Protobuf.csproj
+++ b/src/Protobufs/BackOffice.BFF.DiscountProduct.Protobuf/BackOffice.BFF.DiscountProduct.Protobuf.csproj
@@ -4,7 +4,7 @@
net9.0
enable
enable
- 0.0.3
+ 0.0.4
None
False
False
@@ -23,7 +23,7 @@
-
+
diff --git a/src/Protobufs/BackOffice.BFF.DiscountProduct.Protobuf/Protos/discountproduct.proto b/src/Protobufs/BackOffice.BFF.DiscountProduct.Protobuf/Protos/discountproduct.proto
index b513a12..98d3a31 100644
--- a/src/Protobufs/BackOffice.BFF.DiscountProduct.Protobuf/Protos/discountproduct.proto
+++ b/src/Protobufs/BackOffice.BFF.DiscountProduct.Protobuf/Protos/discountproduct.proto
@@ -40,6 +40,37 @@ service DiscountProductContract
get: "/GetDiscountProducts"
};
};
+
+ // Product Image Gallery Operations
+ rpc AddDiscountProductImage(AddDiscountProductImageRequest) returns (AddDiscountProductImageResponse){
+ option (google.api.http) = {
+ post: "/AddDiscountProductImage"
+ body: "*"
+ };
+ };
+ rpc UpdateDiscountProductImage(UpdateDiscountProductImageRequest) returns (google.protobuf.Empty){
+ option (google.api.http) = {
+ put: "/UpdateDiscountProductImage"
+ body: "*"
+ };
+ };
+ rpc DeleteDiscountProductImage(DeleteDiscountProductImageRequest) returns (google.protobuf.Empty){
+ option (google.api.http) = {
+ delete: "/DeleteDiscountProductImage"
+ body: "*"
+ };
+ };
+ rpc ReorderDiscountProductImages(ReorderDiscountProductImagesRequest) returns (google.protobuf.Empty){
+ option (google.api.http) = {
+ put: "/ReorderDiscountProductImages"
+ body: "*"
+ };
+ };
+ rpc GetDiscountProductImages(GetDiscountProductImagesRequest) returns (GetDiscountProductImagesResponse){
+ option (google.api.http) = {
+ get: "/GetDiscountProductImages"
+ };
+ };
}
// Create Product
@@ -150,3 +181,68 @@ message DiscountProductDto
bool is_active = 10;
google.protobuf.Timestamp created = 11;
}
+
+// ===== Product Image Gallery Messages =====
+
+// Add Product Image
+message AddDiscountProductImageRequest
+{
+ int64 discount_product_id = 1;
+ string image_path = 2;
+ string thumbnail_path = 3;
+ google.protobuf.StringValue title = 4;
+ google.protobuf.StringValue alt_text = 5;
+}
+
+message AddDiscountProductImageResponse
+{
+ int64 image_id = 1;
+}
+
+// Update Product Image
+message UpdateDiscountProductImageRequest
+{
+ int64 id = 1;
+ string image_path = 2;
+ string thumbnail_path = 3;
+ google.protobuf.StringValue title = 4;
+ google.protobuf.StringValue alt_text = 5;
+ bool is_active = 6;
+}
+
+// Delete Product Image
+message DeleteDiscountProductImageRequest
+{
+ int64 id = 1;
+}
+
+// Reorder Product Images
+message ReorderDiscountProductImagesRequest
+{
+ int64 discount_product_id = 1;
+ repeated int64 image_ids = 2;
+}
+
+// Get Product Images
+message GetDiscountProductImagesRequest
+{
+ int64 discount_product_id = 1;
+ bool only_active = 2;
+}
+
+message GetDiscountProductImagesResponse
+{
+ repeated DiscountProductImageDto images = 1;
+}
+
+message DiscountProductImageDto
+{
+ int64 id = 1;
+ int64 discount_product_id = 2;
+ string image_path = 3;
+ string thumbnail_path = 4;
+ google.protobuf.StringValue title = 5;
+ google.protobuf.StringValue alt_text = 6;
+ int32 sort_order = 7;
+ bool is_active = 8;
+}
diff --git a/src/Protobufs/BackOffice.BFF.DiscountShoppingCart.Protobuf/BackOffice.BFF.DiscountShoppingCart.Protobuf.csproj b/src/Protobufs/BackOffice.BFF.DiscountShoppingCart.Protobuf/BackOffice.BFF.DiscountShoppingCart.Protobuf.csproj
index 456a1bf..e8ab89b 100644
--- a/src/Protobufs/BackOffice.BFF.DiscountShoppingCart.Protobuf/BackOffice.BFF.DiscountShoppingCart.Protobuf.csproj
+++ b/src/Protobufs/BackOffice.BFF.DiscountShoppingCart.Protobuf/BackOffice.BFF.DiscountShoppingCart.Protobuf.csproj
@@ -4,7 +4,7 @@
net9.0
enable
enable
- 0.0.3
+ 0.0.4
None
False
False
@@ -23,7 +23,7 @@
-
+
diff --git a/src/Protobufs/BackOffice.BFF.ProductTag.Protobuf/BackOffice.BFF.ProductTag.Protobuf.csproj b/src/Protobufs/BackOffice.BFF.ProductTag.Protobuf/BackOffice.BFF.ProductTag.Protobuf.csproj
index b0beca3..87fbe5b 100644
--- a/src/Protobufs/BackOffice.BFF.ProductTag.Protobuf/BackOffice.BFF.ProductTag.Protobuf.csproj
+++ b/src/Protobufs/BackOffice.BFF.ProductTag.Protobuf/BackOffice.BFF.ProductTag.Protobuf.csproj
@@ -4,7 +4,7 @@
net9.0
enable
enable
- 0.0.3
+ 0.0.4
None
False
False
@@ -23,7 +23,7 @@
-
+
diff --git a/src/Protobufs/BackOffice.BFF.Tag.Protobuf/BackOffice.BFF.Tag.Protobuf.csproj b/src/Protobufs/BackOffice.BFF.Tag.Protobuf/BackOffice.BFF.Tag.Protobuf.csproj
index 5376490..7188d16 100644
--- a/src/Protobufs/BackOffice.BFF.Tag.Protobuf/BackOffice.BFF.Tag.Protobuf.csproj
+++ b/src/Protobufs/BackOffice.BFF.Tag.Protobuf/BackOffice.BFF.Tag.Protobuf.csproj
@@ -4,7 +4,7 @@
net9.0
enable
enable
- 0.0.4
+ 0.0.5
None
False
False
@@ -23,7 +23,7 @@
-
+