- wallet-service: IPaymentGateway abstraction + VN Pay implementation (HMAC-SHA512, sandbox), Payment aggregate root, PaymentsController with create/callback/query endpoints - order-service: PosHub SignalR hub with Redis backplane + MessagePack, strongly-typed clients, 3 group types (shop/kds/pos), integrated into Create/Pay/Complete/Cancel order handlers - fnb-engine + inventory-service: Kitchen→Inventory auto-deduction via domain events, HTTP with Polly retry + circuit breaker, idempotency check, graceful degradation on insufficient stock - order-service: Enhanced PayOrderCommand with 3 flows (cash/card/online), PaymentPending status, WalletServiceClient, CompleteOrderPaymentCommand for gateway callbacks - POS frontend: Cash/Card/QR payment components wired to real backend, BFF proxy updated - infra: Traefik routes for fnb-engine, inventory-service, and SignalR WebSocket hub - ROADMAP.md: Updated with Phase 1 progress tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
100 lines
3.1 KiB
C#
100 lines
3.1 KiB
C#
namespace WalletService.API.Application.Queries.Payments;
|
|
|
|
using MediatR;
|
|
using WalletService.Domain.AggregatesModel.PaymentAggregate;
|
|
|
|
/// <summary>
|
|
/// EN: Handler for GetPaymentByOrderIdQuery.
|
|
/// VI: Handler cho GetPaymentByOrderIdQuery.
|
|
/// </summary>
|
|
public class GetPaymentByOrderIdQueryHandler : IRequestHandler<GetPaymentByOrderIdQuery, PaymentDto?>
|
|
{
|
|
private readonly IPaymentRepository _paymentRepository;
|
|
private readonly ILogger<GetPaymentByOrderIdQueryHandler> _logger;
|
|
|
|
public GetPaymentByOrderIdQueryHandler(
|
|
IPaymentRepository paymentRepository,
|
|
ILogger<GetPaymentByOrderIdQueryHandler> logger)
|
|
{
|
|
_paymentRepository = paymentRepository;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<PaymentDto?> Handle(
|
|
GetPaymentByOrderIdQuery request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
_logger.LogInformation(
|
|
"EN: Getting payment for order {OrderId} / " +
|
|
"VI: Lay thanh toan cho don hang {OrderId}",
|
|
request.OrderId);
|
|
|
|
var payment = await _paymentRepository.GetByOrderIdAsync(request.OrderId);
|
|
|
|
return payment == null ? null : MapToDto(payment);
|
|
}
|
|
|
|
private static PaymentDto MapToDto(Payment payment)
|
|
{
|
|
return new PaymentDto(
|
|
payment.Id,
|
|
payment.OrderId,
|
|
payment.Amount,
|
|
payment.Currency,
|
|
payment.GatewayName,
|
|
payment.TransactionId,
|
|
payment.PaymentUrl,
|
|
payment.Status.Name,
|
|
payment.ErrorCode,
|
|
payment.ErrorMessage,
|
|
payment.CreatedAt,
|
|
payment.CompletedAt);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// EN: Handler for GetPaymentByTransactionIdQuery.
|
|
/// VI: Handler cho GetPaymentByTransactionIdQuery.
|
|
/// </summary>
|
|
public class GetPaymentByTransactionIdQueryHandler : IRequestHandler<GetPaymentByTransactionIdQuery, PaymentDto?>
|
|
{
|
|
private readonly IPaymentRepository _paymentRepository;
|
|
private readonly ILogger<GetPaymentByTransactionIdQueryHandler> _logger;
|
|
|
|
public GetPaymentByTransactionIdQueryHandler(
|
|
IPaymentRepository paymentRepository,
|
|
ILogger<GetPaymentByTransactionIdQueryHandler> logger)
|
|
{
|
|
_paymentRepository = paymentRepository;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<PaymentDto?> Handle(
|
|
GetPaymentByTransactionIdQuery request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
_logger.LogInformation(
|
|
"EN: Getting payment by transaction ID {TransactionId} / " +
|
|
"VI: Lay thanh toan theo ma giao dich {TransactionId}",
|
|
request.TransactionId);
|
|
|
|
var payment = await _paymentRepository.GetByTransactionIdAsync(request.TransactionId);
|
|
|
|
if (payment == null) return null;
|
|
|
|
return new PaymentDto(
|
|
payment.Id,
|
|
payment.OrderId,
|
|
payment.Amount,
|
|
payment.Currency,
|
|
payment.GatewayName,
|
|
payment.TransactionId,
|
|
payment.PaymentUrl,
|
|
payment.Status.Name,
|
|
payment.ErrorCode,
|
|
payment.ErrorMessage,
|
|
payment.CreatedAt,
|
|
payment.CompletedAt);
|
|
}
|
|
}
|