feat: Implement Cancel Order functionality with command, handler, and validation
This commit is contained in:
@@ -21,4 +21,9 @@ public record GetWithdrawalRequestsQuery : IRequest<GetWithdrawalRequestsRespons
|
|||||||
/// فیلتر شناسه کاربر (اختیاری)
|
/// فیلتر شناسه کاربر (اختیاری)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public long? UserId { get; init; }
|
public long? UserId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// فیلتر شماره شبا / IBAN (اختیاری)
|
||||||
|
/// </summary>
|
||||||
|
public string? IbanNumber { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ public class GetWithdrawalRequestsQueryHandler : IRequestHandler<GetWithdrawalRe
|
|||||||
grpcRequest.UserId = request.UserId.Value;
|
grpcRequest.UserId = request.UserId.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.IbanNumber))
|
||||||
|
{
|
||||||
|
grpcRequest.IbanNumber = request.IbanNumber;
|
||||||
|
}
|
||||||
|
|
||||||
var response = await _context.Commissions.GetWithdrawalRequestsAsync(grpcRequest, cancellationToken: cancellationToken);
|
var response = await _context.Commissions.GetWithdrawalRequestsAsync(grpcRequest, cancellationToken: cancellationToken);
|
||||||
return response.Adapt<GetWithdrawalRequestsResponseDto>();
|
return response.Adapt<GetWithdrawalRequestsResponseDto>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ public record WithdrawalRequestDto
|
|||||||
public string Method { get; init; } = "Bank";
|
public string Method { get; init; } = "Bank";
|
||||||
public string? BankAccount { get; init; }
|
public string? BankAccount { get; init; }
|
||||||
public string? BankName { get; init; }
|
public string? BankName { get; init; }
|
||||||
|
public string? BankReferenceId { get; init; }
|
||||||
|
public string? BankTrackingCode { get; init; }
|
||||||
|
public string? PaymentFailureReason { get; init; }
|
||||||
public DateTime RequestDate { get; init; }
|
public DateTime RequestDate { get; init; }
|
||||||
public DateTime? ProcessedDate { get; init; }
|
public DateTime? ProcessedDate { get; init; }
|
||||||
public string? AdminNote { get; init; }
|
public string? AdminNote { get; init; }
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using BackOffice.BFF.Application.ProductTagCQ.Queries.GetProductTagsByProduct;
|
||||||
|
|
||||||
|
namespace BackOffice.BFF.Application.ProductTagCQ.Queries.GetProductTagsByProduct;
|
||||||
|
|
||||||
|
public record GetProductTagsByProductQuery : IRequest<GetProductTagsByProductResponseDto>
|
||||||
|
{
|
||||||
|
public long ProductId { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record ProductTagItemDto
|
||||||
|
{
|
||||||
|
public long Id { get; init; }
|
||||||
|
public long TagId { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record GetProductTagsByProductResponseDto
|
||||||
|
{
|
||||||
|
public List<ProductTagItemDto> Items { get; init; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using BackOffice.BFF.Application.Common.Interfaces;
|
||||||
|
using CMSMicroservice.Protobuf.Protos.ProductTag;
|
||||||
|
|
||||||
|
namespace BackOffice.BFF.Application.ProductTagCQ.Queries.GetProductTagsByProduct;
|
||||||
|
|
||||||
|
public class GetProductTagsByProductQueryHandler : IRequestHandler<GetProductTagsByProductQuery, GetProductTagsByProductResponseDto>
|
||||||
|
{
|
||||||
|
private readonly IApplicationContractContext _context;
|
||||||
|
|
||||||
|
public GetProductTagsByProductQueryHandler(IApplicationContractContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GetProductTagsByProductResponseDto> Handle(GetProductTagsByProductQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var grpcRequest = new GetAllProductTagByFilterRequest
|
||||||
|
{
|
||||||
|
PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
|
||||||
|
{
|
||||||
|
PageNumber = 1,
|
||||||
|
PageSize = 100
|
||||||
|
},
|
||||||
|
Filter = new GetAllProductTagByFilterFilter
|
||||||
|
{
|
||||||
|
ProductId = request.ProductId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await _context.ProductTags.GetAllProductTagByFilterAsync(grpcRequest, cancellationToken: cancellationToken);
|
||||||
|
|
||||||
|
var dto = new GetProductTagsByProductResponseDto
|
||||||
|
{
|
||||||
|
Items = response.Models
|
||||||
|
.Select(m => new ProductTagItemDto
|
||||||
|
{
|
||||||
|
Id = m.Id,
|
||||||
|
TagId = m.TagId
|
||||||
|
})
|
||||||
|
.ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using BackOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace BackOffice.BFF.Application.UserOrderCQ.Commands.CancelOrder;
|
||||||
|
|
||||||
|
public record CancelOrderCommand : IRequest<CancelOrderResponse>
|
||||||
|
{
|
||||||
|
public long OrderId { get; init; }
|
||||||
|
public string CancelReason { get; init; } = string.Empty;
|
||||||
|
public bool RefundPayment { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
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<CancelOrderCommand, CancelOrderResponse>
|
||||||
|
{
|
||||||
|
private readonly IApplicationContractContext _context;
|
||||||
|
private readonly ILogger<CancelOrderCommandHandler> _logger;
|
||||||
|
|
||||||
|
public CancelOrderCommandHandler(
|
||||||
|
IApplicationContractContext context,
|
||||||
|
ILogger<CancelOrderCommandHandler> logger)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<CancelOrderResponse> 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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
|
||||||
|
namespace BackOffice.BFF.Application.UserOrderCQ.Commands.CancelOrder;
|
||||||
|
|
||||||
|
public class CancelOrderCommandValidator : AbstractValidator<CancelOrderCommand>
|
||||||
|
{
|
||||||
|
public CancelOrderCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.OrderId)
|
||||||
|
.GreaterThan(0)
|
||||||
|
.WithMessage("شناسه سفارش باید بزرگتر از 0 باشد");
|
||||||
|
|
||||||
|
RuleFor(x => x.CancelReason)
|
||||||
|
.NotEmpty()
|
||||||
|
.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<CancelOrderCommand, CancelOrderResponse>
|
||||||
|
{
|
||||||
|
private readonly IApplicationContractContext _context;
|
||||||
|
private readonly ILogger<CancelOrderCommandHandler> _logger;
|
||||||
|
|
||||||
|
public CancelOrderCommandHandler(
|
||||||
|
IApplicationContractContext context,
|
||||||
|
ILogger<CancelOrderCommandHandler> logger)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<CancelOrderResponse> 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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ namespace BackOffice.BFF.WebApi.Common.Mappings;
|
|||||||
using BackOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
|
using BackOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
|
||||||
using BackOffice.BFF.Application.UserOrderCQ.Commands.UpdateOrderStatus;
|
using BackOffice.BFF.Application.UserOrderCQ.Commands.UpdateOrderStatus;
|
||||||
using BackOffice.BFF.Application.UserOrderCQ.Commands.ApplyDiscountToOrder;
|
using BackOffice.BFF.Application.UserOrderCQ.Commands.ApplyDiscountToOrder;
|
||||||
|
using BackOffice.BFF.Application.UserOrderCQ.Commands.CancelOrder;
|
||||||
using BackOffice.BFF.Application.UserOrderCQ.Queries.GetOrdersByDateRange;
|
using BackOffice.BFF.Application.UserOrderCQ.Queries.GetOrdersByDateRange;
|
||||||
using BackOffice.BFF.Application.UserOrderCQ.Queries.CalculateOrderPV;
|
using BackOffice.BFF.Application.UserOrderCQ.Queries.CalculateOrderPV;
|
||||||
using Google.Protobuf.WellKnownTypes;
|
using Google.Protobuf.WellKnownTypes;
|
||||||
@@ -74,6 +75,11 @@ public class UserOrderProfile : IRegister
|
|||||||
.Map(dest => dest.Quantity, src => src.Quantity)
|
.Map(dest => dest.Quantity, src => src.Quantity)
|
||||||
.Map(dest => dest.UnitPv, src => src.UnitPV)
|
.Map(dest => dest.UnitPv, src => src.UnitPV)
|
||||||
.Map(dest => dest.TotalPv, src => src.TotalPV);
|
.Map(dest => dest.TotalPv, src => src.TotalPV);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// CancelOrder mappings
|
||||||
|
config.NewConfig<CancelOrderRequest, CancelOrderCommand>()
|
||||||
|
.Map(dest => dest.OrderId, src => src.OrderId)
|
||||||
|
.Map(dest => dest.CancelReason, src => src.CancelReason)
|
||||||
|
.Map(dest => dest.RefundPayment, src => src.RefundPayment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using BackOffice.BFF.Application.UserOrderCQ.Queries.GetUserOrder;
|
|||||||
using BackOffice.BFF.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter;
|
using BackOffice.BFF.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter;
|
||||||
using BackOffice.BFF.Application.UserOrderCQ.Commands.UpdateOrderStatus;
|
using BackOffice.BFF.Application.UserOrderCQ.Commands.UpdateOrderStatus;
|
||||||
using BackOffice.BFF.Application.UserOrderCQ.Commands.ApplyDiscountToOrder;
|
using BackOffice.BFF.Application.UserOrderCQ.Commands.ApplyDiscountToOrder;
|
||||||
|
using BackOffice.BFF.Application.UserOrderCQ.Commands.CancelOrder;
|
||||||
using BackOffice.BFF.Application.UserOrderCQ.Queries.GetOrdersByDateRange;
|
using BackOffice.BFF.Application.UserOrderCQ.Queries.GetOrdersByDateRange;
|
||||||
using BackOffice.BFF.Application.UserOrderCQ.Queries.CalculateOrderPV;
|
using BackOffice.BFF.Application.UserOrderCQ.Queries.CalculateOrderPV;
|
||||||
namespace BackOffice.BFF.WebApi.Services;
|
namespace BackOffice.BFF.WebApi.Services;
|
||||||
@@ -58,4 +59,9 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase
|
|||||||
{
|
{
|
||||||
return await _dispatchRequestToCQRS.Handle<CalculateOrderPVRequest, CalculateOrderPVQuery, CalculateOrderPVResponse>(request, context);
|
return await _dispatchRequestToCQRS.Handle<CalculateOrderPVRequest, CalculateOrderPVQuery, CalculateOrderPVResponse>(request, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<CancelOrderResponse> CancelOrder(CancelOrderRequest request, ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<CancelOrderRequest, CancelOrderCommand, CancelOrderResponse>(request, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,6 +254,7 @@ message GetWithdrawalRequestsRequest
|
|||||||
google.protobuf.StringValue week_number = 3;
|
google.protobuf.StringValue week_number = 3;
|
||||||
int32 page_index = 4;
|
int32 page_index = 4;
|
||||||
int32 page_size = 5;
|
int32 page_size = 5;
|
||||||
|
string iban_number = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetWithdrawalRequestsResponse
|
message GetWithdrawalRequestsResponse
|
||||||
@@ -277,6 +278,9 @@ message WithdrawalRequestModel
|
|||||||
string processed_by = 11;
|
string processed_by = 11;
|
||||||
string reason = 12;
|
string reason = 12;
|
||||||
google.protobuf.Timestamp created = 13;
|
google.protobuf.Timestamp created = 13;
|
||||||
|
string bank_reference_id = 14;
|
||||||
|
string bank_tracking_code = 15;
|
||||||
|
string payment_failure_reason = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============ Worker Control APIs ============
|
// ============ Worker Control APIs ============
|
||||||
|
|||||||
@@ -64,6 +64,12 @@ service UserOrderContract
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Order Management
|
// Order Management
|
||||||
|
rpc CancelOrder(CancelOrderRequest) returns (CancelOrderResponse){
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/CancelOrder"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
};
|
||||||
rpc UpdateOrderStatus(UpdateOrderStatusRequest) returns (UpdateOrderStatusResponse){
|
rpc UpdateOrderStatus(UpdateOrderStatusRequest) returns (UpdateOrderStatusResponse){
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/UpdateOrderStatus"
|
post: "/UpdateOrderStatus"
|
||||||
@@ -342,3 +348,19 @@ message DecimalValue
|
|||||||
|
|
||||||
sfixed32 nanos = 2;
|
sfixed32 nanos = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CancelOrder Messages
|
||||||
|
message CancelOrderRequest
|
||||||
|
{
|
||||||
|
int64 order_id = 1;
|
||||||
|
string cancel_reason = 2;
|
||||||
|
bool refund_payment = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CancelOrderResponse
|
||||||
|
{
|
||||||
|
int64 order_id = 1;
|
||||||
|
int32 status = 2;
|
||||||
|
string message = 3;
|
||||||
|
bool refund_processed = 4;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user