diff --git a/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/CheckUserPermission/CheckUserPermissionQuery.cs b/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/CheckUserPermission/CheckUserPermissionQuery.cs new file mode 100644 index 0000000..e61daba --- /dev/null +++ b/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/CheckUserPermission/CheckUserPermissionQuery.cs @@ -0,0 +1,6 @@ +using MediatR; + +namespace BackOffice.BFF.Application.AuthorizationCQ.Queries.CheckUserPermission; + +public record CheckUserPermissionQuery(string Permission) : IRequest; + diff --git a/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/CheckUserPermission/CheckUserPermissionQueryHandler.cs b/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/CheckUserPermission/CheckUserPermissionQueryHandler.cs new file mode 100644 index 0000000..27b5cd0 --- /dev/null +++ b/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/CheckUserPermission/CheckUserPermissionQueryHandler.cs @@ -0,0 +1,27 @@ +using System.Threading; +using System.Threading.Tasks; +using BackOffice.BFF.Application.Common.Interfaces; +using MediatR; + +namespace BackOffice.BFF.Application.AuthorizationCQ.Queries.CheckUserPermission; + +public class CheckUserPermissionQueryHandler : IRequestHandler +{ + private readonly IPermissionService _permissionService; + + public CheckUserPermissionQueryHandler(IPermissionService permissionService) + { + _permissionService = permissionService; + } + + public async Task Handle(CheckUserPermissionQuery request, CancellationToken cancellationToken) + { + if (string.IsNullOrWhiteSpace(request.Permission)) + { + return true; + } + + return await _permissionService.HasPermissionAsync(request.Permission, cancellationToken); + } +} + diff --git a/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/GetUserRoles/GetUserRolesQuery.cs b/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/GetUserRoles/GetUserRolesQuery.cs new file mode 100644 index 0000000..54ea52b --- /dev/null +++ b/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/GetUserRoles/GetUserRolesQuery.cs @@ -0,0 +1,7 @@ +using System.Collections.Generic; +using MediatR; + +namespace BackOffice.BFF.Application.AuthorizationCQ.Queries.GetUserRoles; + +public record GetUserRolesQuery : IRequest>; + diff --git a/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/GetUserRoles/GetUserRolesQueryHandler.cs b/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/GetUserRoles/GetUserRolesQueryHandler.cs new file mode 100644 index 0000000..ade9ef9 --- /dev/null +++ b/src/BackOffice.BFF.Application/AuthorizationCQ/Queries/GetUserRoles/GetUserRolesQueryHandler.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using BackOffice.BFF.Application.Common.Interfaces; +using MediatR; + +namespace BackOffice.BFF.Application.AuthorizationCQ.Queries.GetUserRoles; + +public class GetUserRolesQueryHandler : IRequestHandler> +{ + private readonly IPermissionService _permissionService; + + public GetUserRolesQueryHandler(IPermissionService permissionService) + { + _permissionService = permissionService; + } + + public async Task> Handle(GetUserRolesQuery request, CancellationToken cancellationToken) + { + return await _permissionService.GetUserRolesAsync(cancellationToken); + } +} + diff --git a/src/BackOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs b/src/BackOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs index 0544ac8..35c3db0 100644 --- a/src/BackOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs +++ b/src/BackOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs @@ -61,5 +61,8 @@ public interface IApplicationContractContext // Public Messages PublicMessageContract.PublicMessageContractClient PublicMessages { get; } + // Manual Payments (Admin) - CMS gRPC + CMSMicroservice.Protobuf.Protos.ManualPayment.ManualPaymentContract.ManualPaymentContractClient ManualPayments { get; } + #endregion } diff --git a/src/BackOffice.BFF.Application/Common/Interfaces/IPermissionService.cs b/src/BackOffice.BFF.Application/Common/Interfaces/IPermissionService.cs new file mode 100644 index 0000000..b9e0058 --- /dev/null +++ b/src/BackOffice.BFF.Application/Common/Interfaces/IPermissionService.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace BackOffice.BFF.Application.Common.Interfaces; + +public interface IPermissionService +{ + Task> GetUserRolesAsync(CancellationToken cancellationToken); + + Task HasPermissionAsync(string permission, CancellationToken cancellationToken); +} + diff --git a/src/BackOffice.BFF.Application/Common/Mappings/UserOrderProfile.cs b/src/BackOffice.BFF.Application/Common/Mappings/UserOrderProfile.cs index eb32982..95d6915 100644 --- a/src/BackOffice.BFF.Application/Common/Mappings/UserOrderProfile.cs +++ b/src/BackOffice.BFF.Application/Common/Mappings/UserOrderProfile.cs @@ -7,6 +7,8 @@ using CmsUserOrderFilter = CMSMicroservice.Protobuf.Protos.UserOrder.GetAllUserO using CmsUserOrderRequest = CMSMicroservice.Protobuf.Protos.UserOrder.GetAllUserOrderByFilterRequest; using GetAllUserOrderByFilterFilter = BackOffice.BFF.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter.GetAllUserOrderByFilterFilter; using GetAllUserOrderByFilterResponseModel = BackOffice.BFF.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter.GetAllUserOrderByFilterResponseModel; +using CmsGetUserOrderResponse = CMSMicroservice.Protobuf.Protos.UserOrder.GetUserOrderResponse; +using BffGetUserOrderResponseDto = BackOffice.BFF.Application.UserOrderCQ.Queries.GetUserOrder.GetUserOrderResponseDto; namespace BackOffice.BFF.Application.Common.Mappings; @@ -26,11 +28,13 @@ public class UserOrderProfile : IRegister .IgnoreIf((src, dest) => src.Filter.PaymentStatus==null,dest => dest.Filter.PaymentStatus) .Map(dest => dest.Filter, src => src.Filter == null || IsEmptyFilter(src.Filter) ? null : BuildFilter(src.Filter)); - // config.NewConfig< CMSMicroservice.Protobuf.Protos.UserOrder.GetAllUserOrderByFilterResponseModel, GetAllUserOrderByFilterResponseModel>() - // - // .Map(dest => dest.p, src => src.PaymentMethod); - - + // Map VAT information from CMS GetUserOrderResponse (VatInfo) to flattened DTO fields + config.NewConfig() + .Map(dest => dest.VatBaseAmount, src => src.VatInfo != null ? src.VatInfo.BaseAmount : 0) + .Map(dest => dest.VatAmount, src => src.VatInfo != null ? src.VatInfo.VatAmount : 0) + .Map(dest => dest.VatTotalAmount, + src => src.VatInfo != null ? src.VatInfo.TotalAmount : src.Amount) + .Map(dest => dest.VatPercentage, src => src.VatInfo != null ? src.VatInfo.VatRate * 100 : 0); } private static bool IsEmptyFilter(GetAllUserOrderByFilterFilter src) diff --git a/src/BackOffice.BFF.Application/Common/Models/PermissionDefinitions.cs b/src/BackOffice.BFF.Application/Common/Models/PermissionDefinitions.cs new file mode 100644 index 0000000..271d8b1 --- /dev/null +++ b/src/BackOffice.BFF.Application/Common/Models/PermissionDefinitions.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BackOffice.BFF.Application.Common.Models; + +public static class RoleNames +{ + public const string SuperAdmin = "SuperAdmin"; + public const string Admin = "Admin"; + public const string Inspector = "Inspector"; +} + +public static class PermissionNames +{ + // Dashboard + public const string DashboardView = "dashboard.view"; + + // Orders + public const string OrdersView = "orders.view"; + public const string OrdersCreate = "orders.create"; + public const string OrdersUpdate = "orders.update"; + public const string OrdersDelete = "orders.delete"; + public const string OrdersCancel = "orders.cancel"; + public const string OrdersApprove = "orders.approve"; + + // Products + public const string ProductsView = "products.view"; + public const string ProductsCreate = "products.create"; + public const string ProductsUpdate = "products.update"; + public const string ProductsDelete = "products.delete"; + + // Users + public const string UsersView = "users.view"; + public const string UsersUpdate = "users.update"; + public const string UsersDelete = "users.delete"; + + // Commission / Withdrawal + public const string CommissionView = "commission.view"; + public const string CommissionApproveWithdrawal = "commission.approve_withdrawal"; + + // Public Messages + public const string PublicMessagesView = "publicmessages.view"; + public const string PublicMessagesCreate = "publicmessages.create"; + public const string PublicMessagesUpdate = "publicmessages.update"; + public const string PublicMessagesPublish = "publicmessages.publish"; + + // Manual Payments + public const string ManualPaymentsView = "manualpayments.view"; + public const string ManualPaymentsCreate = "manualpayments.create"; + public const string ManualPaymentsApprove = "manualpayments.approve"; + + // Settings / Configuration / VAT + public const string SettingsView = "settings.view"; + public const string SettingsManageConfiguration = "settings.manage_configuration"; + public const string SettingsManageVat = "settings.manage_vat"; + + // Reports + public const string ReportsView = "reports.view"; +} + +public static class RolePermissionConfig +{ + private static readonly IReadOnlyDictionary RolePermissions = + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + // SuperAdmin: full access (wildcard) + [RoleNames.SuperAdmin] = new[] { "*" }, + + // Admin: مدیریت سفارش‌ها، محصولات، بخشی از کمیسیون و پیام‌ها + [RoleNames.Admin] = new[] + { + PermissionNames.DashboardView, + + PermissionNames.OrdersView, + PermissionNames.OrdersCreate, + PermissionNames.OrdersUpdate, + PermissionNames.OrdersCancel, + + PermissionNames.ProductsView, + PermissionNames.ProductsCreate, + PermissionNames.ProductsUpdate, + PermissionNames.ProductsDelete, + + PermissionNames.UsersView, + PermissionNames.UsersUpdate, + + PermissionNames.CommissionView, + PermissionNames.CommissionApproveWithdrawal, + + PermissionNames.PublicMessagesView, + PermissionNames.PublicMessagesCreate, + PermissionNames.PublicMessagesUpdate, + PermissionNames.PublicMessagesPublish, + + PermissionNames.ManualPaymentsView, + PermissionNames.ManualPaymentsCreate, + + PermissionNames.ReportsView + }, + + // Inspector: فقط مشاهده + [RoleNames.Inspector] = new[] + { + PermissionNames.DashboardView, + PermissionNames.OrdersView, + PermissionNames.UsersView, + PermissionNames.CommissionView, + PermissionNames.PublicMessagesView, + PermissionNames.ReportsView + } + }; + + public static bool HasPermission(string role, string permission) + { + if (string.IsNullOrWhiteSpace(role) || string.IsNullOrWhiteSpace(permission)) + { + return false; + } + + if (!RolePermissions.TryGetValue(role, out var permissions)) + { + return false; + } + + if (permissions.Contains("*", StringComparer.OrdinalIgnoreCase)) + { + return true; + } + + return permissions.Contains(permission, StringComparer.OrdinalIgnoreCase); + } +} diff --git a/src/BackOffice.BFF.Application/ConfigurationCQ/Commands/SetDefaultVatPercentage/SetDefaultVatPercentageCommand.cs b/src/BackOffice.BFF.Application/ConfigurationCQ/Commands/SetDefaultVatPercentage/SetDefaultVatPercentageCommand.cs new file mode 100644 index 0000000..56eb1d6 --- /dev/null +++ b/src/BackOffice.BFF.Application/ConfigurationCQ/Commands/SetDefaultVatPercentage/SetDefaultVatPercentageCommand.cs @@ -0,0 +1,10 @@ +namespace BackOffice.BFF.Application.ConfigurationCQ.Commands.SetDefaultVatPercentage; + +public record SetDefaultVatPercentageCommand : IRequest +{ + /// + /// درصد VAT جدید (مثلاً 10 به معنای 10٪) + /// + public int VatPercentage { get; init; } +} + diff --git a/src/BackOffice.BFF.Application/ConfigurationCQ/Commands/SetDefaultVatPercentage/SetDefaultVatPercentageCommandHandler.cs b/src/BackOffice.BFF.Application/ConfigurationCQ/Commands/SetDefaultVatPercentage/SetDefaultVatPercentageCommandHandler.cs new file mode 100644 index 0000000..042e499 --- /dev/null +++ b/src/BackOffice.BFF.Application/ConfigurationCQ/Commands/SetDefaultVatPercentage/SetDefaultVatPercentageCommandHandler.cs @@ -0,0 +1,43 @@ +using BackOffice.BFF.Application.Common.Interfaces; +using BackOffice.BFF.Configuration.Protobuf; +using Google.Protobuf.WellKnownTypes; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace BackOffice.BFF.Application.ConfigurationCQ.Commands.SetDefaultVatPercentage; + +public class SetDefaultVatPercentageCommandHandler : IRequestHandler +{ + private const string VatConfigurationKey = "DefaultVatPercentage"; + private readonly IApplicationContractContext _context; + private readonly ILogger _logger; + + public SetDefaultVatPercentageCommandHandler( + IApplicationContractContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(SetDefaultVatPercentageCommand request, CancellationToken cancellationToken) + { + var grpcRequest = new CreateOrUpdateConfigurationRequest + { + Key = VatConfigurationKey, + Value = request.VatPercentage.ToString(), + Scope = 0, // System scope + Description = new StringValue + { + Value = "درصد پیش‌فرض مالیات بر ارزش افزوده سفارش‌ها" + } + }; + + await _context.Configurations.CreateOrUpdateConfigurationAsync(grpcRequest, cancellationToken: cancellationToken); + + _logger.LogInformation("Default VAT percentage updated to {VatPercentage}%.", request.VatPercentage); + + return Unit.Value; + } +} + diff --git a/src/BackOffice.BFF.Application/ConfigurationCQ/Commands/SetDefaultVatPercentage/SetDefaultVatPercentageCommandValidator.cs b/src/BackOffice.BFF.Application/ConfigurationCQ/Commands/SetDefaultVatPercentage/SetDefaultVatPercentageCommandValidator.cs new file mode 100644 index 0000000..8c7c462 --- /dev/null +++ b/src/BackOffice.BFF.Application/ConfigurationCQ/Commands/SetDefaultVatPercentage/SetDefaultVatPercentageCommandValidator.cs @@ -0,0 +1,14 @@ +using FluentValidation; + +namespace BackOffice.BFF.Application.ConfigurationCQ.Commands.SetDefaultVatPercentage; + +public class SetDefaultVatPercentageCommandValidator : AbstractValidator +{ + public SetDefaultVatPercentageCommandValidator() + { + RuleFor(x => x.VatPercentage) + .InclusiveBetween(0, 100) + .WithMessage("درصد VAT باید بین 0 تا 100 باشد."); + } +} + diff --git a/src/BackOffice.BFF.Application/ConfigurationCQ/Queries/GetCurrentVatPercentage/GetCurrentVatPercentageQuery.cs b/src/BackOffice.BFF.Application/ConfigurationCQ/Queries/GetCurrentVatPercentage/GetCurrentVatPercentageQuery.cs new file mode 100644 index 0000000..2db3a96 --- /dev/null +++ b/src/BackOffice.BFF.Application/ConfigurationCQ/Queries/GetCurrentVatPercentage/GetCurrentVatPercentageQuery.cs @@ -0,0 +1,17 @@ +namespace BackOffice.BFF.Application.ConfigurationCQ.Queries.GetCurrentVatPercentage; + +public record GetCurrentVatPercentageQuery : IRequest; + +public class GetCurrentVatPercentageResponse +{ + /// + /// درصد VAT فعلی (مثلاً 10 به معنای 10٪) + /// + public int VatPercentage { get; set; } + + /// + /// آیا مقدار از تنظیمات خوانده شده (true) یا مقدار پیش‌فرض استفاده شده (false) + /// + public bool IsConfigured { get; set; } +} + diff --git a/src/BackOffice.BFF.Application/ConfigurationCQ/Queries/GetCurrentVatPercentage/GetCurrentVatPercentageQueryHandler.cs b/src/BackOffice.BFF.Application/ConfigurationCQ/Queries/GetCurrentVatPercentage/GetCurrentVatPercentageQueryHandler.cs new file mode 100644 index 0000000..4cce633 --- /dev/null +++ b/src/BackOffice.BFF.Application/ConfigurationCQ/Queries/GetCurrentVatPercentage/GetCurrentVatPercentageQueryHandler.cs @@ -0,0 +1,70 @@ +using BackOffice.BFF.Application.Common.Interfaces; +using BackOffice.BFF.Configuration.Protobuf; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace BackOffice.BFF.Application.ConfigurationCQ.Queries.GetCurrentVatPercentage; + +public class GetCurrentVatPercentageQueryHandler : IRequestHandler +{ + private const string VatConfigurationKey = "DefaultVatPercentage"; + private readonly IApplicationContractContext _context; + private readonly ILogger _logger; + + public GetCurrentVatPercentageQueryHandler( + IApplicationContractContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(GetCurrentVatPercentageQuery request, CancellationToken cancellationToken) + { + try + { + var grpcRequest = new GetConfigurationByKeyRequest + { + Key = VatConfigurationKey + }; + + var response = await _context.Configurations.GetConfigurationByKeyAsync(grpcRequest, cancellationToken: cancellationToken); + + if (response == null || string.IsNullOrWhiteSpace(response.Value)) + { + _logger.LogInformation("VAT configuration not found. Using default value 10%."); + return new GetCurrentVatPercentageResponse + { + VatPercentage = 10, + IsConfigured = false + }; + } + + if (!int.TryParse(response.Value, out var vat) || vat < 0) + { + _logger.LogWarning("Invalid VAT configuration value '{Value}'. Falling back to default 10%.", response.Value); + return new GetCurrentVatPercentageResponse + { + VatPercentage = 10, + IsConfigured = false + }; + } + + return new GetCurrentVatPercentageResponse + { + VatPercentage = vat, + IsConfigured = true + }; + } + catch (Exception ex) + { + _logger.LogError(ex, "Error while reading VAT configuration. Falling back to default value 10%."); + return new GetCurrentVatPercentageResponse + { + VatPercentage = 10, + IsConfigured = false + }; + } + } +} + diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/ApproveManualPayment/ApproveManualPaymentCommand.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/ApproveManualPayment/ApproveManualPaymentCommand.cs new file mode 100644 index 0000000..60649ce --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/ApproveManualPayment/ApproveManualPaymentCommand.cs @@ -0,0 +1,10 @@ +using MediatR; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Commands.ApproveManualPayment; + +public class ApproveManualPaymentCommand : IRequest +{ + public long ManualPaymentId { get; set; } + public string? ApprovalNote { get; set; } +} + diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/ApproveManualPayment/ApproveManualPaymentCommandHandler.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/ApproveManualPayment/ApproveManualPaymentCommandHandler.cs new file mode 100644 index 0000000..493c32d --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/ApproveManualPayment/ApproveManualPaymentCommandHandler.cs @@ -0,0 +1,41 @@ +using BackOffice.BFF.Application.Common.Interfaces; +using CMSMicroservice.Protobuf.Protos.ManualPayment; +using Google.Protobuf.WellKnownTypes; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Commands.ApproveManualPayment; + +public class ApproveManualPaymentCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + private readonly ILogger _logger; + + public ApproveManualPaymentCommandHandler( + IApplicationContractContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(ApproveManualPaymentCommand request, CancellationToken cancellationToken) + { + _logger.LogInformation("Approving manual payment via BFF. Id: {Id}", request.ManualPaymentId); + + var grpcRequest = new ApproveManualPaymentRequest + { + ManualPaymentId = request.ManualPaymentId + }; + + if (!string.IsNullOrWhiteSpace(request.ApprovalNote)) + { + grpcRequest.ApprovalNote = new StringValue { Value = request.ApprovalNote }; + } + + await _context.ManualPayments.ApproveManualPaymentAsync(grpcRequest, cancellationToken: cancellationToken); + + return true; + } +} + diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/ApproveManualPayment/ApproveManualPaymentCommandValidator.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/ApproveManualPayment/ApproveManualPaymentCommandValidator.cs new file mode 100644 index 0000000..4934e89 --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/ApproveManualPayment/ApproveManualPaymentCommandValidator.cs @@ -0,0 +1,14 @@ +using FluentValidation; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Commands.ApproveManualPayment; + +public class ApproveManualPaymentCommandValidator : AbstractValidator +{ + public ApproveManualPaymentCommandValidator() + { + RuleFor(x => x.ManualPaymentId) + .GreaterThan(0) + .WithMessage("شناسه پرداخت دستی نامعتبر است."); + } +} + diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommand.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommand.cs new file mode 100644 index 0000000..9258039 --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommand.cs @@ -0,0 +1,18 @@ +using MediatR; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Commands.CreateManualPayment; + +public class CreateManualPaymentCommand : IRequest +{ + public long UserId { get; set; } + public long Amount { get; set; } + public int Type { get; set; } + public string Description { get; set; } = string.Empty; + public string? ReferenceNumber { get; set; } +} + +public class CreateManualPaymentResponseDto +{ + public long Id { get; set; } +} + diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandHandler.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandHandler.cs new file mode 100644 index 0000000..d7d1baf --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandHandler.cs @@ -0,0 +1,51 @@ +using BackOffice.BFF.Application.Common.Interfaces; +using CMSMicroservice.Protobuf.Protos.ManualPayment; +using Google.Protobuf.WellKnownTypes; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Commands.CreateManualPayment; + +public class CreateManualPaymentCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + private readonly ILogger _logger; + + public CreateManualPaymentCommandHandler( + IApplicationContractContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(CreateManualPaymentCommand request, CancellationToken cancellationToken) + { + _logger.LogInformation( + "Creating manual payment via BFF for UserId {UserId}, Amount {Amount}, Type {Type}", + request.UserId, + request.Amount, + request.Type); + + var grpcRequest = new CreateManualPaymentRequest + { + UserId = request.UserId, + Amount = request.Amount, + Type = (ManualPaymentType)request.Type, + Description = request.Description + }; + + if (!string.IsNullOrWhiteSpace(request.ReferenceNumber)) + { + grpcRequest.ReferenceNumber = new StringValue { Value = request.ReferenceNumber }; + } + + var response = await _context.ManualPayments.CreateManualPaymentAsync(grpcRequest, cancellationToken: cancellationToken); + + return new CreateManualPaymentResponseDto + { + Id = response.Id + }; + } +} + diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandValidator.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandValidator.cs new file mode 100644 index 0000000..a0319ad --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandValidator.cs @@ -0,0 +1,26 @@ +using FluentValidation; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Commands.CreateManualPayment; + +public class CreateManualPaymentCommandValidator : AbstractValidator +{ + public CreateManualPaymentCommandValidator() + { + RuleFor(x => x.UserId) + .GreaterThan(0) + .WithMessage("شناسه کاربر باید بزرگتر از صفر باشد."); + + RuleFor(x => x.Amount) + .GreaterThan(0) + .WithMessage("مبلغ باید بزرگتر از صفر باشد."); + + RuleFor(x => x.Description) + .NotEmpty() + .WithMessage("توضیحات الزامی است."); + + RuleFor(x => x.Type) + .GreaterThan(0) + .WithMessage("نوع پرداخت دستی نامعتبر است."); + } +} + diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/RejectManualPayment/RejectManualPaymentCommand.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/RejectManualPayment/RejectManualPaymentCommand.cs new file mode 100644 index 0000000..d50c455 --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/RejectManualPayment/RejectManualPaymentCommand.cs @@ -0,0 +1,10 @@ +using MediatR; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Commands.RejectManualPayment; + +public class RejectManualPaymentCommand : IRequest +{ + public long ManualPaymentId { get; set; } + public string RejectionReason { get; set; } = string.Empty; +} + diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/RejectManualPayment/RejectManualPaymentCommandHandler.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/RejectManualPayment/RejectManualPaymentCommandHandler.cs new file mode 100644 index 0000000..581747e --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/RejectManualPayment/RejectManualPaymentCommandHandler.cs @@ -0,0 +1,36 @@ +using BackOffice.BFF.Application.Common.Interfaces; +using CMSMicroservice.Protobuf.Protos.ManualPayment; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Commands.RejectManualPayment; + +public class RejectManualPaymentCommandHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + private readonly ILogger _logger; + + public RejectManualPaymentCommandHandler( + IApplicationContractContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(RejectManualPaymentCommand request, CancellationToken cancellationToken) + { + _logger.LogInformation("Rejecting manual payment via BFF. Id: {Id}", request.ManualPaymentId); + + var grpcRequest = new RejectManualPaymentRequest + { + ManualPaymentId = request.ManualPaymentId, + RejectionReason = request.RejectionReason + }; + + await _context.ManualPayments.RejectManualPaymentAsync(grpcRequest, cancellationToken: cancellationToken); + + return true; + } +} + diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/RejectManualPayment/RejectManualPaymentCommandValidator.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/RejectManualPayment/RejectManualPaymentCommandValidator.cs new file mode 100644 index 0000000..49bb1bf --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Commands/RejectManualPayment/RejectManualPaymentCommandValidator.cs @@ -0,0 +1,18 @@ +using FluentValidation; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Commands.RejectManualPayment; + +public class RejectManualPaymentCommandValidator : AbstractValidator +{ + public RejectManualPaymentCommandValidator() + { + RuleFor(x => x.ManualPaymentId) + .GreaterThan(0) + .WithMessage("شناسه پرداخت دستی نامعتبر است."); + + RuleFor(x => x.RejectionReason) + .NotEmpty() + .WithMessage("دلیل رد الزامی است."); + } +} + diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Queries/GetManualPayments/GetManualPaymentsQuery.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Queries/GetManualPayments/GetManualPaymentsQuery.cs new file mode 100644 index 0000000..623a736 --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Queries/GetManualPayments/GetManualPaymentsQuery.cs @@ -0,0 +1,15 @@ +using MediatR; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Queries.GetManualPayments; + +public class GetManualPaymentsQuery : IRequest +{ + public int PageNumber { get; set; } = 1; + public int PageSize { get; set; } = 10; + public long? UserId { get; set; } + public int? Status { get; set; } + public int? Type { get; set; } + public long? RequestedBy { get; set; } + public bool OrderByDescending { get; set; } = true; + public string? ReferenceNumber { get; set; } +} diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Queries/GetManualPayments/GetManualPaymentsQueryHandler.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Queries/GetManualPayments/GetManualPaymentsQueryHandler.cs new file mode 100644 index 0000000..d784115 --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Queries/GetManualPayments/GetManualPaymentsQueryHandler.cs @@ -0,0 +1,114 @@ +using BackOffice.BFF.Application.Common.Interfaces; +using BackOffice.BFF.Application.Common.Models; +using CMSMicroservice.Protobuf.Protos.ManualPayment; +using Google.Protobuf.WellKnownTypes; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Queries.GetManualPayments; + +public class GetManualPaymentsQueryHandler : IRequestHandler +{ + private readonly IApplicationContractContext _context; + private readonly ILogger _logger; + + public GetManualPaymentsQueryHandler( + IApplicationContractContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(GetManualPaymentsQuery request, CancellationToken cancellationToken) + { + _logger.LogInformation( + "Getting manual payments via BFF. Page: {Page}, PageSize: {PageSize}, Status: {Status}, Type: {Type}", + request.PageNumber, + request.PageSize, + request.Status, + request.Type); + + var grpcRequest = new GetAllManualPaymentsRequest + { + PageNumber = request.PageNumber, + PageSize = request.PageSize + }; + + if (request.UserId.HasValue) + { + grpcRequest.UserId = new Int64Value { Value = request.UserId.Value }; + } + + if (request.Status.HasValue) + { + grpcRequest.Status = new Int32Value { Value = request.Status.Value }; + } + + if (request.Type.HasValue) + { + grpcRequest.Type = new Int32Value { Value = request.Type.Value }; + } + + if (request.RequestedBy.HasValue) + { + grpcRequest.RequestedBy = new Int64Value { Value = request.RequestedBy.Value }; + } + + grpcRequest.OrderByDescending = new BoolValue { Value = request.OrderByDescending }; + + var response = await _context.ManualPayments.GetAllManualPaymentsAsync(grpcRequest, cancellationToken: cancellationToken); + + var meta = response.MetaData; + + var models = response.Models? + .Select(m => new ManualPaymentModel + { + Id = m.Id, + UserId = m.UserId, + UserFullName = m.UserFullName, + UserMobile = m.UserMobile, + Amount = m.Amount, + Type = (int)m.Type, + TypeDisplay = m.TypeDisplay, + Description = m.Description, + ReferenceNumber = m.ReferenceNumber, + Status = (int)m.Status, + StatusDisplay = m.StatusDisplay, + RequestedBy = m.RequestedBy, + RequestedByName = m.RequestedByName, + ApprovedBy = m.ApprovedBy?.Value, + ApprovedByName = m.ApprovedByName, + ApprovedAt = m.ApprovedAt?.ToDateTime(), + RejectionReason = m.RejectionReason, + TransactionId = m.TransactionId?.Value, + Created = m.Created.ToDateTime() + }) + .ToList() + ?? new List(); + + if (!string.IsNullOrWhiteSpace(request.ReferenceNumber)) + { + models = models + .Where(m => !string.IsNullOrWhiteSpace(m.ReferenceNumber) && + m.ReferenceNumber.Contains(request.ReferenceNumber!, StringComparison.OrdinalIgnoreCase)) + .ToList(); + } + + var result = new GetManualPaymentsResponseDto + { + MetaData = new MetaData + { + CurrentPage = meta.CurrentPage, + TotalPage = meta.TotalPage, + PageSize = meta.PageSize, + TotalCount = meta.TotalCount, + HasPrevious = meta.HasPrevious, + HasNext = meta.HasNext + }, + Models = models + }; + + return result; + } +} diff --git a/src/BackOffice.BFF.Application/ManualPaymentCQ/Queries/GetManualPayments/GetManualPaymentsResponseDto.cs b/src/BackOffice.BFF.Application/ManualPaymentCQ/Queries/GetManualPayments/GetManualPaymentsResponseDto.cs new file mode 100644 index 0000000..6029c76 --- /dev/null +++ b/src/BackOffice.BFF.Application/ManualPaymentCQ/Queries/GetManualPayments/GetManualPaymentsResponseDto.cs @@ -0,0 +1,33 @@ +using BackOffice.BFF.Application.Common.Models; + +namespace BackOffice.BFF.Application.ManualPaymentCQ.Queries.GetManualPayments; + +public class GetManualPaymentsResponseDto +{ + public MetaData MetaData { get; set; } = new(); + public List? Models { get; set; } +} + +public class ManualPaymentModel +{ + 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 Amount { get; set; } + public int Type { get; set; } + public string TypeDisplay { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string? ReferenceNumber { get; set; } + public int Status { get; set; } + public string StatusDisplay { get; set; } = string.Empty; + public long RequestedBy { get; set; } + public string RequestedByName { get; set; } = string.Empty; + public long? ApprovedBy { get; set; } + public string? ApprovedByName { get; set; } + public DateTime? ApprovedAt { get; set; } + public string? RejectionReason { get; set; } + public long? TransactionId { get; set; } + public DateTime Created { get; set; } +} + diff --git a/src/BackOffice.BFF.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryHandler.cs b/src/BackOffice.BFF.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryHandler.cs index 0d47ecf..6830b95 100644 --- a/src/BackOffice.BFF.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryHandler.cs +++ b/src/BackOffice.BFF.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryHandler.cs @@ -1,12 +1,12 @@ using BackOffice.BFF.Application.Common.Interfaces; -using BackOffice.BFF.Package.Protobuf.Protos.Package; -using CMSMicroservice.Protobuf.Protos.Package; using MediatR; using Microsoft.Extensions.Logging; +using BffPackage = BackOffice.BFF.Package.Protobuf.Protos.Package; +using CmsPackage = CMSMicroservice.Protobuf.Protos.Package; namespace BackOffice.BFF.Application.PackageCQ.Queries.GetUserPackageStatus; -public class GetUserPackageStatusQueryHandler : IRequestHandler +public class GetUserPackageStatusQueryHandler : IRequestHandler { private readonly IApplicationContractContext _context; private readonly ILogger _logger; @@ -19,9 +19,9 @@ public class GetUserPackageStatusQueryHandler : IRequestHandler Handle(GetUserPackageStatusQuery request, CancellationToken cancellationToken) + public async Task Handle(GetUserPackageStatusQuery request, CancellationToken cancellationToken) { - var grpcRequest = new GetUserPackageStatusRequest + var grpcRequest = new CmsPackage.GetUserPackageStatusRequest { UserId = request.UserId }; @@ -30,7 +30,7 @@ public class GetUserPackageStatusQueryHandler : IRequestHandler +public class ArchiveMessageCommand : IRequest +{ + public long MessageId { get; set; } +} + +public class ArchiveMessageCommandHandler : IRequestHandler { private readonly IApplicationContractContext _context; @@ -13,9 +18,9 @@ public class ArchiveMessageCommandHandler : IRequestHandler Handle(ArchiveMessageRequest request, CancellationToken cancellationToken) + public async Task Handle(ArchiveMessageCommand request, CancellationToken cancellationToken) { - var cmsRequest = new ArchiveMessageRequest + var cmsRequest = new CmsProto.ArchiveMessageRequest { MessageId = request.MessageId }; @@ -24,7 +29,7 @@ public class ArchiveMessageCommandHandler : IRequestHandler +public class CreatePublicMessageCommandHandler : IRequestHandler { private readonly IApplicationContractContext _context; @@ -14,9 +14,9 @@ public class CreatePublicMessageCommandHandler : IRequestHandler Handle(CreatePublicMessageRequest request, CancellationToken cancellationToken) + public async Task Handle(BffProto.CreatePublicMessageRequest request, CancellationToken cancellationToken) { - var cmsRequest = new CreatePublicMessageRequest + var cmsRequest = new CmsProto.CreatePublicMessageRequest { Title = request.Title, Content = request.Content, @@ -30,7 +30,7 @@ public class CreatePublicMessageCommandHandler : IRequestHandler +public class DeletePublicMessageCommandHandler : IRequestHandler { private readonly IApplicationContractContext _context; @@ -13,9 +14,9 @@ public class DeletePublicMessageCommandHandler : IRequestHandler Handle(DeletePublicMessageRequest request, CancellationToken cancellationToken) + public async Task Handle(BffProto.DeletePublicMessageRequest request, CancellationToken cancellationToken) { - var cmsRequest = new DeletePublicMessageRequest + var cmsRequest = new CmsProto.DeletePublicMessageRequest { MessageId = request.MessageId }; diff --git a/src/BackOffice.BFF.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandHandler.cs b/src/BackOffice.BFF.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandHandler.cs index 438f420..7b1889b 100644 --- a/src/BackOffice.BFF.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandHandler.cs +++ b/src/BackOffice.BFF.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandHandler.cs @@ -1,10 +1,11 @@ using BackOffice.BFF.Application.Common.Interfaces; -using BackOffice.BFF.PublicMessage.Protobuf; -using CMSMicroservice.Protobuf.Protos; +using MediatR; +using BffProto = BackOffice.BFF.PublicMessage.Protobuf; +using CmsProto = CMSMicroservice.Protobuf.Protos; namespace BackOffice.BFF.Application.PublicMessageCQ.Commands.PublishMessage; -public class PublishMessageCommandHandler : IRequestHandler +public class PublishMessageCommandHandler : IRequestHandler { private readonly IApplicationContractContext _context; @@ -13,9 +14,9 @@ public class PublishMessageCommandHandler : IRequestHandler Handle(PublishMessageRequest request, CancellationToken cancellationToken) + public async Task Handle(BffProto.PublishMessageRequest request, CancellationToken cancellationToken) { - var cmsRequest = new PublishMessageRequest + var cmsRequest = new CmsProto.PublishMessageRequest { MessageId = request.MessageId }; @@ -24,7 +25,7 @@ public class PublishMessageCommandHandler : IRequestHandler +public class UpdatePublicMessageCommandHandler : IRequestHandler { private readonly IApplicationContractContext _context; @@ -14,9 +15,9 @@ public class UpdatePublicMessageCommandHandler : IRequestHandler Handle(UpdatePublicMessageRequest request, CancellationToken cancellationToken) + public async Task Handle(BffProto.UpdatePublicMessageRequest request, CancellationToken cancellationToken) { - var cmsRequest = new UpdatePublicMessageRequest + var cmsRequest = new CmsProto.UpdatePublicMessageRequest { Id = request.MessageId, Title = request.Title, diff --git a/src/BackOffice.BFF.Application/PublicMessageCQ/Queries/GetActiveMessages/GetActiveMessagesQuery.cs b/src/BackOffice.BFF.Application/PublicMessageCQ/Queries/GetActiveMessages/GetActiveMessagesQuery.cs index 85da603..1ec91dc 100644 --- a/src/BackOffice.BFF.Application/PublicMessageCQ/Queries/GetActiveMessages/GetActiveMessagesQuery.cs +++ b/src/BackOffice.BFF.Application/PublicMessageCQ/Queries/GetActiveMessages/GetActiveMessagesQuery.cs @@ -1,19 +1,18 @@ // GetActiveMessages - Public view using BackOffice.BFF.Application.Common.Interfaces; -using BackOffice.BFF.PublicMessage.Protobuf; -using CMSMicroservice.Protobuf.Protos; -using Google.Protobuf.WellKnownTypes; using MediatR; +using BffProto = BackOffice.BFF.PublicMessage.Protobuf; +using CmsProto = CMSMicroservice.Protobuf.Protos; namespace BackOffice.BFF.Application.PublicMessageCQ.Queries.GetActiveMessages; -public record GetActiveMessagesQuery : IRequest +public record GetActiveMessagesQuery : IRequest { public int? MessageType { get; init; } public string? TargetAudience { get; init; } } -public class GetActiveMessagesQueryHandler : IRequestHandler +public class GetActiveMessagesQueryHandler : IRequestHandler { private readonly IApplicationContractContext _context; @@ -22,18 +21,18 @@ public class GetActiveMessagesQueryHandler : IRequestHandler Handle(GetActiveMessagesQuery request, CancellationToken cancellationToken) + public async Task Handle(GetActiveMessagesQuery request, CancellationToken cancellationToken) { - var cmsRequest = new GetActiveMessagesRequest(); + var cmsRequest = new CmsProto.GetActiveMessagesRequest(); // نسخه فعلی CMS فیلدی برای فیلتر ندارد؛ در صورت اضافه شدن، اینجا مپ می‌شود. var cmsResponse = await _context.PublicMessages.GetActiveMessagesAsync(cmsRequest, cancellationToken: cancellationToken); - var result = new GetActiveMessagesResponse(); + var result = new BffProto.GetActiveMessagesResponse(); foreach (var message in cmsResponse.Messages) { - result.Messages.Add(new PublicMessageDto + result.Messages.Add(new BffProto.PublicMessageDto { MessageId = message.Id, Title = message.Title, diff --git a/src/BackOffice.BFF.Application/PublicMessageCQ/Queries/GetAllMessages/GetAllMessagesQuery.cs b/src/BackOffice.BFF.Application/PublicMessageCQ/Queries/GetAllMessages/GetAllMessagesQuery.cs index 49dd28d..8eb0def 100644 --- a/src/BackOffice.BFF.Application/PublicMessageCQ/Queries/GetAllMessages/GetAllMessagesQuery.cs +++ b/src/BackOffice.BFF.Application/PublicMessageCQ/Queries/GetAllMessages/GetAllMessagesQuery.cs @@ -1,13 +1,13 @@ // GetAllMessages - Admin view using BackOffice.BFF.Application.Common.Interfaces; -using BackOffice.BFF.PublicMessage.Protobuf; -using CMSMicroservice.Protobuf.Protos; using Google.Protobuf.WellKnownTypes; using MediatR; +using BffProto = BackOffice.BFF.PublicMessage.Protobuf; +using CmsProto = CMSMicroservice.Protobuf.Protos; namespace BackOffice.BFF.Application.PublicMessageCQ.Queries.GetAllMessages; -public record GetAllMessagesQuery : IRequest +public record GetAllMessagesQuery : IRequest { public int? Status { get; init; } public int? MessageType { get; init; } @@ -15,7 +15,7 @@ public record GetAllMessagesQuery : IRequest public int PageSize { get; init; } } -public class GetAllMessagesQueryHandler : IRequestHandler +public class GetAllMessagesQueryHandler : IRequestHandler { private readonly IApplicationContractContext _context; @@ -24,9 +24,9 @@ public class GetAllMessagesQueryHandler : IRequestHandler Handle(GetAllMessagesQuery request, CancellationToken cancellationToken) + public async Task Handle(GetAllMessagesQuery request, CancellationToken cancellationToken) { - var cmsRequest = new GetAllMessagesRequest + var cmsRequest = new CmsProto.GetAllMessagesRequest { PageNumber = request.PageNumber, PageSize = request.PageSize @@ -44,7 +44,7 @@ public class GetAllMessagesQueryHandler : IRequestHandler .WithMessage("دلیل لغو سفارش الزامی است"); } } - -*** Add File: BackOffice.BFF/src/BackOffice.BFF.Application/UserOrderCQ/Commands/CancelOrder/CancelOrderCommandHandler.cs -using BackOffice.BFF.Application.Common.Interfaces; -using BackOffice.BFF.UserOrder.Protobuf.Protos.UserOrder; -using CMSMicroservice.Protobuf.Protos.UserOrder; -using MediatR; -using Microsoft.Extensions.Logging; - -namespace BackOffice.BFF.Application.UserOrderCQ.Commands.CancelOrder; - -public class CancelOrderCommandHandler : IRequestHandler -{ - private readonly IApplicationContractContext _context; - private readonly ILogger _logger; - - public CancelOrderCommandHandler( - IApplicationContractContext context, - ILogger logger) - { - _context = context; - _logger = logger; - } - - public async Task Handle(CancelOrderCommand request, CancellationToken cancellationToken) - { - var grpcRequest = new CMSMicroservice.Protobuf.Protos.UserOrder.CancelOrderRequest - { - OrderId = request.OrderId, - CancelReason = request.CancelReason ?? string.Empty, - RefundPayment = request.RefundPayment - }; - - var response = await _context.UserOrders.CancelOrderAsync(grpcRequest, cancellationToken: cancellationToken); - - _logger.LogInformation( - "Cancelled order {OrderId}. Status={Status} RefundProcessed={RefundProcessed}", - response.OrderId, - response.Status, - response.RefundProcessed); - - return new CancelOrderResponse - { - OrderId = response.OrderId, - Status = (int)response.Status, - Message = response.Message, - RefundProcessed = response.RefundProcessed - }; - } -} - diff --git a/src/BackOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs b/src/BackOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs index 9576a88..fd2182c 100644 --- a/src/BackOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs +++ b/src/BackOffice.BFF.Application/UserOrderCQ/Queries/GetAllUserOrderByFilter/GetAllUserOrderByFilterResponseDto.cs @@ -43,4 +43,8 @@ public class GetAllUserOrderByFilterResponseModel public string? UserNationalCode { get; set; } // روش پرداخت (0=IPG,1=Wallet) public int PaymentMethod { get; set; } + // مبلغ مالیات بر ارزش افزوده (ریال) + public long VatAmount { get; set; } + // درصد مالیات بر ارزش افزوده (مثلاً 9 برای 9٪) + public double VatPercentage { get; set; } } diff --git a/src/BackOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs b/src/BackOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs index 78a2cd2..1f561a5 100644 --- a/src/BackOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs +++ b/src/BackOffice.BFF.Application/UserOrderCQ/Queries/GetUserOrder/GetUserOrderResponseDto.cs @@ -36,6 +36,14 @@ public class GetUserOrderResponseDto public string? UserFullName { get; set; } // کدملی کاربر public string? UserNationalCode { get; set; } + // مبلغ پایه (قبل از مالیات) + public long VatBaseAmount { get; set; } + // مبلغ مالیات بر ارزش افزوده (ریال) + public long VatAmount { get; set; } + // مبلغ نهایی (شامل مالیات) + public long VatTotalAmount { get; set; } + // درصد مالیات بر ارزش افزوده (مثلاً 9 برای 9٪) + public double VatPercentage { get; set; } } public class GetUserOrderResponseFactorDetail diff --git a/src/BackOffice.BFF.Infrastructure/ConfigureServices.cs b/src/BackOffice.BFF.Infrastructure/ConfigureServices.cs index e549cb2..7760ed1 100644 --- a/src/BackOffice.BFF.Infrastructure/ConfigureServices.cs +++ b/src/BackOffice.BFF.Infrastructure/ConfigureServices.cs @@ -14,6 +14,7 @@ public static class ConfigureServices { services.AddSingleton(); services.AddSingleton(); + services.AddScoped(); services.AddInfrastructureGrpcServices(configuration); #region AddAuthentication @@ -89,4 +90,4 @@ public static class ConfigureServices return services; } -} \ No newline at end of file +} diff --git a/src/BackOffice.BFF.Infrastructure/Services/ApplicationContractContext.cs b/src/BackOffice.BFF.Infrastructure/Services/ApplicationContractContext.cs index 2066cd4..34957fa 100644 --- a/src/BackOffice.BFF.Infrastructure/Services/ApplicationContractContext.cs +++ b/src/BackOffice.BFF.Infrastructure/Services/ApplicationContractContext.cs @@ -22,6 +22,7 @@ using CMSMicroservice.Protobuf.Protos.DiscountOrder; using CMSMicroservice.Protobuf.Protos.Tag; using CMSMicroservice.Protobuf.Protos.ProductTag; using CMSMicroservice.Protobuf.Protos; +using CMSMicroservice.Protobuf.Protos.ManualPayment; using Microsoft.Extensions.DependencyInjection; namespace BackOffice.BFF.Infrastructure.Services; @@ -84,5 +85,8 @@ public class ApplicationContractContext : IApplicationContractContext // Public Messages public PublicMessageContract.PublicMessageContractClient PublicMessages => GetService(); + + // Manual Payments (Admin) + public ManualPaymentContract.ManualPaymentContractClient ManualPayments => GetService(); #endregion } diff --git a/src/BackOffice.BFF.Infrastructure/Services/PermissionService.cs b/src/BackOffice.BFF.Infrastructure/Services/PermissionService.cs new file mode 100644 index 0000000..a9f11b7 --- /dev/null +++ b/src/BackOffice.BFF.Infrastructure/Services/PermissionService.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using BackOffice.BFF.Application.Common.Interfaces; +using BackOffice.BFF.Application.Common.Models; +using Microsoft.AspNetCore.Http; + +namespace BackOffice.BFF.Infrastructure.Services; + +public class PermissionService : IPermissionService +{ + private readonly IHttpContextAccessor _httpContextAccessor; + + public PermissionService(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public Task> GetUserRolesAsync(CancellationToken cancellationToken) + { + var httpContext = _httpContextAccessor.HttpContext; + var user = httpContext?.User; + + if (user?.Identity is not { IsAuthenticated: true }) + { + return Task.FromResult>(Array.Empty()); + } + + var roles = user.Claims + .Where(c => c.Type == ClaimTypes.Role || string.Equals(c.Type, "role", StringComparison.OrdinalIgnoreCase)) + .Select(c => c.Value) + .Where(v => !string.IsNullOrWhiteSpace(v)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + return Task.FromResult>(roles); + } + + public async Task HasPermissionAsync(string permission, CancellationToken cancellationToken) + { + if (string.IsNullOrWhiteSpace(permission)) + { + return true; + } + + var roles = await GetUserRolesAsync(cancellationToken); + if (roles.Count == 0) + { + return false; + } + + foreach (var role in roles) + { + if (RolePermissionConfig.HasPermission(role, permission)) + { + return true; + } + } + + return false; + } +} + diff --git a/src/BackOffice.BFF.WebApi/BackOffice.BFF.WebApi.csproj b/src/BackOffice.BFF.WebApi/BackOffice.BFF.WebApi.csproj index 6a614dd..ac7473c 100644 --- a/src/BackOffice.BFF.WebApi/BackOffice.BFF.WebApi.csproj +++ b/src/BackOffice.BFF.WebApi/BackOffice.BFF.WebApi.csproj @@ -31,5 +31,6 @@ + diff --git a/src/BackOffice.BFF.WebApi/Common/Authorization/PermissionInterceptor.cs b/src/BackOffice.BFF.WebApi/Common/Authorization/PermissionInterceptor.cs new file mode 100644 index 0000000..4f1902f --- /dev/null +++ b/src/BackOffice.BFF.WebApi/Common/Authorization/PermissionInterceptor.cs @@ -0,0 +1,79 @@ +using System; +using System.Threading.Tasks; +using BackOffice.BFF.Application.Common.Interfaces; +using Grpc.AspNetCore.Server; +using Grpc.Core; +using Grpc.Core.Interceptors; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace BackOffice.BFF.WebApi.Common.Authorization; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] +public sealed class RequiresPermissionAttribute : Attribute +{ + public RequiresPermissionAttribute(string permission) + { + Permission = permission ?? throw new ArgumentNullException(nameof(permission)); + } + + public string Permission { get; } +} + +public class PermissionInterceptor : Interceptor +{ + private readonly IPermissionService _permissionService; + private readonly ILogger _logger; + private readonly IHttpContextAccessor _httpContextAccessor; + + public PermissionInterceptor( + IPermissionService permissionService, + ILogger logger, + IHttpContextAccessor httpContextAccessor) + { + _permissionService = permissionService; + _logger = logger; + _httpContextAccessor = httpContextAccessor; + } + + public override async Task UnaryServerHandler( + TRequest request, + ServerCallContext context, + UnaryServerMethod continuation) + { + await EnsureHasPermissionAsync(context); + return await continuation(request, context); + } + + private async Task EnsureHasPermissionAsync(ServerCallContext context) + { + var httpContext = context.GetHttpContext() ?? _httpContextAccessor.HttpContext; + if (httpContext == null) + { + return; + } + + var endpoint = httpContext.GetEndpoint(); + if (endpoint == null) + { + return; + } + + var permissionAttributes = endpoint.Metadata.GetOrderedMetadata(); + if (permissionAttributes == null || permissionAttributes.Count == 0) + { + return; + } + + foreach (var attribute in permissionAttributes) + { + var hasPermission = await _permissionService.HasPermissionAsync(attribute.Permission, httpContext.RequestAborted); + if (!hasPermission) + { + _logger.LogWarning("Permission denied for permission {Permission}", attribute.Permission); + throw new RpcException(new Status(StatusCode.PermissionDenied, "Permission denied")); + } + } + } +} + diff --git a/src/BackOffice.BFF.WebApi/GlobalUsings.cs b/src/BackOffice.BFF.WebApi/GlobalUsings.cs index f566ed2..c72000a 100644 --- a/src/BackOffice.BFF.WebApi/GlobalUsings.cs +++ b/src/BackOffice.BFF.WebApi/GlobalUsings.cs @@ -9,3 +9,5 @@ global using Microsoft.AspNetCore.Builder; global using System; global using Microsoft.AspNetCore.Routing; global using System.Linq; +global using BackOffice.BFF.WebApi.Common.Authorization; +global using BackOffice.BFF.Application.Common.Models; diff --git a/src/BackOffice.BFF.WebApi/Program.cs b/src/BackOffice.BFF.WebApi/Program.cs index 4e3852f..1dc3c11 100644 --- a/src/BackOffice.BFF.WebApi/Program.cs +++ b/src/BackOffice.BFF.WebApi/Program.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core; using Serilog; using Serilog.Core; using Microsoft.OpenApi.Models; +using BackOffice.BFF.WebApi.Common.Authorization; var builder = WebApplication.CreateBuilder(args); if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) @@ -37,6 +38,7 @@ builder.Services.AddGrpc(options => options.EnableDetailedErrors = true; options.MaxReceiveMessageSize = 1000 * 1024 * 1024; // 1 GB options.MaxSendMessageSize = 1000 * 1024 * 1024; // 1 GB + options.Interceptors.Add(); }).AddJsonTranscoding(); builder.Services.AddInfrastructureServices(builder.Configuration); builder.Services.AddApplicationServices(); diff --git a/src/BackOffice.BFF.WebApi/Services/ConfigurationService.cs b/src/BackOffice.BFF.WebApi/Services/ConfigurationService.cs index 09c874e..cd078b3 100644 --- a/src/BackOffice.BFF.WebApi/Services/ConfigurationService.cs +++ b/src/BackOffice.BFF.WebApi/Services/ConfigurationService.cs @@ -21,6 +21,7 @@ public class ConfigurationService : ConfigurationContract.ConfigurationContractB _dispatchRequestToCQRS = dispatchRequestToCQRS; } + [RequiresPermission(PermissionNames.SettingsManageConfiguration)] public override async Task CreateOrUpdateConfiguration( CreateOrUpdateConfigurationRequest request, ServerCallContext context) @@ -30,6 +31,7 @@ public class ConfigurationService : ConfigurationContract.ConfigurationContractB context); } + [RequiresPermission(PermissionNames.SettingsManageConfiguration)] public override async Task DeactivateConfiguration( DeactivateConfigurationRequest request, ServerCallContext context) @@ -39,6 +41,7 @@ public class ConfigurationService : ConfigurationContract.ConfigurationContractB context); } + [RequiresPermission(PermissionNames.SettingsView)] public override async Task GetAllConfigurations( GetAllConfigurationsRequest request, ServerCallContext context) diff --git a/src/BackOffice.BFF.WebApi/Services/ManualPaymentService.cs b/src/BackOffice.BFF.WebApi/Services/ManualPaymentService.cs new file mode 100644 index 0000000..31fdcaf --- /dev/null +++ b/src/BackOffice.BFF.WebApi/Services/ManualPaymentService.cs @@ -0,0 +1,76 @@ +using BackOffice.BFF.ManualPayment.Protobuf; +using BackOffice.BFF.WebApi.Common.Services; +using BackOffice.BFF.Application.ManualPaymentCQ.Commands.CreateManualPayment; +using BackOffice.BFF.Application.ManualPaymentCQ.Commands.ApproveManualPayment; +using BackOffice.BFF.Application.ManualPaymentCQ.Commands.RejectManualPayment; +using BackOffice.BFF.Application.ManualPaymentCQ.Queries.GetManualPayments; +using Google.Protobuf.WellKnownTypes; +using Mapster; +using MediatR; + +namespace BackOffice.BFF.WebApi.Services; + +public class ManualPaymentService : ManualPaymentContract.ManualPaymentContractBase +{ + private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; + private readonly ISender _sender; + + public ManualPaymentService( + IDispatchRequestToCQRS dispatchRequestToCQRS, + ISender sender) + { + _dispatchRequestToCQRS = dispatchRequestToCQRS; + _sender = sender; + } + + [RequiresPermission(PermissionNames.ManualPaymentsCreate)] + public override async Task CreateManualPayment( + CreateManualPaymentRequest request, + ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle( + request, + context); + } + + [RequiresPermission(PermissionNames.ManualPaymentsApprove)] + public override async Task ApproveManualPayment( + ApproveManualPaymentRequest request, + ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle( + request, + context); + } + + [RequiresPermission(PermissionNames.ManualPaymentsApprove)] + public override async Task RejectManualPayment( + RejectManualPaymentRequest request, + ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle( + request, + context); + } + + [RequiresPermission(PermissionNames.ManualPaymentsView)] + public override async Task GetManualPayments( + GetManualPaymentsRequest request, + ServerCallContext context) + { + var query = new GetManualPaymentsQuery + { + PageNumber = request.PageNumber, + PageSize = request.PageSize, + UserId = request.UserId?.Value, + Status = request.Status?.Value, + Type = request.Type?.Value, + ReferenceNumber = request.ReferenceNumber?.Value, + // RequestedBy و OrderByDescending در این نسخه از UI ارسال نمی‌شود + }; + + var result = await _sender.Send(query, context.CancellationToken); + + return result.Adapt(); + } +} diff --git a/src/BackOffice.BFF.WebApi/Services/UserOrderService.cs b/src/BackOffice.BFF.WebApi/Services/UserOrderService.cs index 16d877b..e4e2850 100644 --- a/src/BackOffice.BFF.WebApi/Services/UserOrderService.cs +++ b/src/BackOffice.BFF.WebApi/Services/UserOrderService.cs @@ -19,47 +19,62 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase { _dispatchRequestToCQRS = dispatchRequestToCQRS; } + + [RequiresPermission(PermissionNames.OrdersCreate)] public override async Task CreateNewUserOrder(CreateNewUserOrderRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } + + [RequiresPermission(PermissionNames.OrdersUpdate)] public override async Task UpdateUserOrder(UpdateUserOrderRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } + + [RequiresPermission(PermissionNames.OrdersDelete)] public override async Task DeleteUserOrder(DeleteUserOrderRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } + + [RequiresPermission(PermissionNames.OrdersView)] public override async Task GetUserOrder(GetUserOrderRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } + + [RequiresPermission(PermissionNames.OrdersView)] public override async Task GetAllUserOrderByFilter(GetAllUserOrderByFilterRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } + [RequiresPermission(PermissionNames.OrdersUpdate)] public override async Task UpdateOrderStatus(UpdateOrderStatusRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } + [RequiresPermission(PermissionNames.ReportsView)] public override async Task GetOrdersByDateRange(GetOrdersByDateRangeRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } + [RequiresPermission(PermissionNames.OrdersUpdate)] public override async Task ApplyDiscountToOrder(ApplyDiscountToOrderRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } + [RequiresPermission(PermissionNames.OrdersView)] public override async Task CalculateOrderPV(CalculateOrderPVRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } + [RequiresPermission(PermissionNames.OrdersCancel)] public override async Task CancelOrder(CancelOrderRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); diff --git a/src/BackOffice.BFF.sln b/src/BackOffice.BFF.sln index a6b4337..59e983c 100644 --- a/src/BackOffice.BFF.sln +++ b/src/BackOffice.BFF.sln @@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackOffice.BFF.Commission.P EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackOffice.BFF.Common.Protobuf", "Protobufs\BackOffice.BFF.Common.Protobuf\BackOffice.BFF.Common.Protobuf.csproj", "{9911D6BE-3022-44F6-B93B-B3D62A14FBCA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackOffice.BFF.ManualPayment.Protobuf", "Protobufs\BackOffice.BFF.ManualPayment.Protobuf\BackOffice.BFF.ManualPayment.Protobuf.csproj", "{389D8C44-E796-41EE-BBF2-7A058735EA50}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -267,6 +269,18 @@ Global {9911D6BE-3022-44F6-B93B-B3D62A14FBCA}.Release|x64.Build.0 = Release|Any CPU {9911D6BE-3022-44F6-B93B-B3D62A14FBCA}.Release|x86.ActiveCfg = Release|Any CPU {9911D6BE-3022-44F6-B93B-B3D62A14FBCA}.Release|x86.Build.0 = Release|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Debug|Any CPU.Build.0 = Debug|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Debug|x64.ActiveCfg = Debug|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Debug|x64.Build.0 = Debug|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Debug|x86.ActiveCfg = Debug|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Debug|x86.Build.0 = Debug|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Release|Any CPU.ActiveCfg = Release|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Release|Any CPU.Build.0 = Release|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Release|x64.ActiveCfg = Release|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Release|x64.Build.0 = Release|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Release|x86.ActiveCfg = Release|Any CPU + {389D8C44-E796-41EE-BBF2-7A058735EA50}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -286,6 +300,7 @@ Global {CA0F6C82-227A-41E4-A59F-B45EF68411A1} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {3B7514DE-1C2F-4BB1-BBD5-C57BEEC6843E} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {9911D6BE-3022-44F6-B93B-B3D62A14FBCA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {389D8C44-E796-41EE-BBF2-7A058735EA50} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0AE1AB4A-3C91-4853-93C2-C2476E79F845} diff --git a/src/Protobufs/BackOffice.BFF.ManualPayment.Protobuf/BackOffice.BFF.ManualPayment.Protobuf.csproj b/src/Protobufs/BackOffice.BFF.ManualPayment.Protobuf/BackOffice.BFF.ManualPayment.Protobuf.csproj new file mode 100644 index 0000000..5c47d31 --- /dev/null +++ b/src/Protobufs/BackOffice.BFF.ManualPayment.Protobuf/BackOffice.BFF.ManualPayment.Protobuf.csproj @@ -0,0 +1,36 @@ + + + + net9.0 + enable + enable + 0.0.1 + None + False + False + Foursat.BackOffice.BFF.ManualPayment.Protobuf + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + + + diff --git a/src/Protobufs/BackOffice.BFF.ManualPayment.Protobuf/Protos/manualpayment.proto b/src/Protobufs/BackOffice.BFF.ManualPayment.Protobuf/Protos/manualpayment.proto new file mode 100644 index 0000000..565b8c4 --- /dev/null +++ b/src/Protobufs/BackOffice.BFF.ManualPayment.Protobuf/Protos/manualpayment.proto @@ -0,0 +1,84 @@ +syntax = "proto3"; + +package manualpayment; + +import "public_messages.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "BackOffice.BFF.ManualPayment.Protobuf"; + +service ManualPaymentContract +{ + rpc CreateManualPayment(CreateManualPaymentRequest) returns (CreateManualPaymentResponse); + rpc ApproveManualPayment(ApproveManualPaymentRequest) returns (google.protobuf.Empty); + rpc RejectManualPayment(RejectManualPaymentRequest) returns (google.protobuf.Empty); + rpc GetManualPayments(GetManualPaymentsRequest) returns (GetManualPaymentsResponse); +} + +message GetManualPaymentsRequest +{ + int32 page_number = 1; + int32 page_size = 2; + google.protobuf.Int64Value user_id = 3; + google.protobuf.Int32Value status = 4; + google.protobuf.Int32Value type = 5; + google.protobuf.StringValue reference_number = 6; +} + +message GetManualPaymentsResponse +{ + messages.MetaData meta_data = 1; + repeated ManualPaymentModel models = 2; +} + +message ManualPaymentModel +{ + int64 id = 1; + int64 user_id = 2; + string user_full_name = 3; + string user_mobile = 4; + int64 amount = 5; + int32 type = 6; + string type_display = 7; + string description = 8; + string reference_number = 9; + int32 status = 10; + string status_display = 11; + int64 requested_by = 12; + string requested_by_name = 13; + google.protobuf.Int64Value approved_by = 14; + google.protobuf.StringValue approved_by_name = 15; + google.protobuf.Timestamp approved_at = 16; + string rejection_reason = 17; + google.protobuf.Int64Value transaction_id = 18; + google.protobuf.Timestamp created = 19; +} + +message CreateManualPaymentRequest +{ + int64 user_id = 1; + int64 amount = 2; + int32 type = 3; + string description = 4; + google.protobuf.StringValue reference_number = 5; +} + +message CreateManualPaymentResponse +{ + int64 id = 1; +} + +message ApproveManualPaymentRequest +{ + int64 manual_payment_id = 1; + google.protobuf.StringValue approval_note = 2; +} + +message RejectManualPaymentRequest +{ + int64 manual_payment_id = 1; + string rejection_reason = 2; +} + diff --git a/src/Protobufs/BackOffice.BFF.ManualPayment.Protobuf/Protos/public_messages.proto b/src/Protobufs/BackOffice.BFF.ManualPayment.Protobuf/Protos/public_messages.proto new file mode 100644 index 0000000..c78db04 --- /dev/null +++ b/src/Protobufs/BackOffice.BFF.ManualPayment.Protobuf/Protos/public_messages.proto @@ -0,0 +1,70 @@ +syntax = "proto3"; + +package messages; + +option csharp_namespace = "CMSMicroservice.Protobuf.Protos"; +service PublicMessageContract{} +message PaginationState +{ + int32 page_number = 1; + + int32 page_size = 2; +} +message MetaData +{ + int64 current_page = 1; + + int64 total_page = 2; + + int64 page_size = 3; + + int64 total_count = 4; + + bool has_previous = 5; + + bool has_next = 6; +} +message DecimalValue +{ + + int64 units = 1; + + sfixed32 nanos = 2; +} +enum PaymentStatus +{ + Success = 0; + Reject = 1; + Pending = 2; +} +// وضعیت ارسال سفارش +enum DeliveryStatus +{ + // نامشخص / نیاز به ارسال ندارد (مثلا سفارش پکیج) + DeliveryStatus_None = 0; + // ثبت شده و در انتظار آماده‌سازی/ارسال + DeliveryStatus_Pending = 1; + // تحویل پست/حمل‌ونقل شده است + DeliveryStatus_InTransit = 2; + // توسط مشتری دریافت شده است + DeliveryStatus_Delivered = 3; + // مرجوع شده + DeliveryStatus_Returned = 4; +} +enum TransactionType +{ + Buy = 0; + DepositIpg = 1; + DepositExternal1 = 2; + Withdraw = 3; +} +enum ContractType +{ + Main = 0; + CMS = 1; +} +enum PaymentMethod +{ + IPG = 0; + Wallet = 1; +} diff --git a/src/Protobufs/BackOffice.BFF.UserOrder.Protobuf/Protos/userorder.proto b/src/Protobufs/BackOffice.BFF.UserOrder.Protobuf/Protos/userorder.proto index 7c64da6..cb3a8b4 100644 --- a/src/Protobufs/BackOffice.BFF.UserOrder.Protobuf/Protos/userorder.proto +++ b/src/Protobufs/BackOffice.BFF.UserOrder.Protobuf/Protos/userorder.proto @@ -165,6 +165,11 @@ message GetUserOrderResponse { PaymentMethod payment_method = 16; } + // اطلاعات مالیات بر ارزش افزوده + int64 vat_amount = 17; + double vat_percentage = 18; + int64 vat_base_amount = 19; + int64 vat_total_amount = 20; } message GetAllUserOrderByFilterRequest { @@ -226,6 +231,9 @@ message GetAllUserOrderByFilterResponseModel { PaymentMethod payment_method = 15; } + // مبلغ و درصد مالیات بر ارزش افزوده + int64 vat_amount = 16; + double vat_percentage = 17; } // جزئیات فاکتور سفارش