feat: Implement user permission checks and manual payment functionalities

- Added CheckUserPermissionQuery and CheckUserPermissionQueryHandler for permission validation.
- Introduced GetUserRolesQuery and GetUserRolesQueryHandler to retrieve user roles.
- Created IPermissionService interface and its implementation in PermissionService.
- Defined permission and role constants in PermissionDefinitions.
- Developed SetDefaultVatPercentageCommand and its handler for VAT configuration.
- Implemented GetCurrentVatPercentageQuery and handler to fetch current VAT settings.
- Added manual payment commands: CreateManualPayment, ApproveManualPayment, and RejectManualPayment with respective handlers and validators.
- Created GetManualPaymentsQuery and handler for retrieving manual payment records.
- Integrated gRPC services for manual payments with appropriate permission checks.
- Established Protobuf definitions for manual payment operations and metadata.
This commit is contained in:
masoodafar-web
2025-12-05 17:27:38 +03:30
parent 67b43fea7a
commit 4aa9f28f6e
51 changed files with 1294 additions and 107 deletions
@@ -0,0 +1,10 @@
namespace BackOffice.BFF.Application.ConfigurationCQ.Commands.SetDefaultVatPercentage;
public record SetDefaultVatPercentageCommand : IRequest<Unit>
{
/// <summary>
/// درصد VAT جدید (مثلاً 10 به معنای 10٪)
/// </summary>
public int VatPercentage { get; init; }
}
@@ -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<SetDefaultVatPercentageCommand, Unit>
{
private const string VatConfigurationKey = "DefaultVatPercentage";
private readonly IApplicationContractContext _context;
private readonly ILogger<SetDefaultVatPercentageCommandHandler> _logger;
public SetDefaultVatPercentageCommandHandler(
IApplicationContractContext context,
ILogger<SetDefaultVatPercentageCommandHandler> logger)
{
_context = context;
_logger = logger;
}
public async Task<Unit> 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;
}
}
@@ -0,0 +1,14 @@
using FluentValidation;
namespace BackOffice.BFF.Application.ConfigurationCQ.Commands.SetDefaultVatPercentage;
public class SetDefaultVatPercentageCommandValidator : AbstractValidator<SetDefaultVatPercentageCommand>
{
public SetDefaultVatPercentageCommandValidator()
{
RuleFor(x => x.VatPercentage)
.InclusiveBetween(0, 100)
.WithMessage("درصد VAT باید بین 0 تا 100 باشد.");
}
}
@@ -0,0 +1,17 @@
namespace BackOffice.BFF.Application.ConfigurationCQ.Queries.GetCurrentVatPercentage;
public record GetCurrentVatPercentageQuery : IRequest<GetCurrentVatPercentageResponse>;
public class GetCurrentVatPercentageResponse
{
/// <summary>
/// درصد VAT فعلی (مثلاً 10 به معنای 10٪)
/// </summary>
public int VatPercentage { get; set; }
/// <summary>
/// آیا مقدار از تنظیمات خوانده شده (true) یا مقدار پیش‌فرض استفاده شده (false)
/// </summary>
public bool IsConfigured { get; set; }
}
@@ -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<GetCurrentVatPercentageQuery, GetCurrentVatPercentageResponse>
{
private const string VatConfigurationKey = "DefaultVatPercentage";
private readonly IApplicationContractContext _context;
private readonly ILogger<GetCurrentVatPercentageQueryHandler> _logger;
public GetCurrentVatPercentageQueryHandler(
IApplicationContractContext context,
ILogger<GetCurrentVatPercentageQueryHandler> logger)
{
_context = context;
_logger = logger;
}
public async Task<GetCurrentVatPercentageResponse> 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
};
}
}
}