using MediatR;
using TakeoutSaaS.Application.App.Billings.Commands;
using TakeoutSaaS.Application.App.Billings.Contracts;
using TakeoutSaaS.Domain.Billings.Entities;
using TakeoutSaaS.Domain.Billings.Enums;
using TakeoutSaaS.Domain.Billings.Repositories;
using TakeoutSaaS.Shared.Abstractions.Security;
namespace TakeoutSaaS.Application.App.Billings.Handlers;
///
/// 确认收款命令处理器。
///
public sealed class ConfirmPaymentCommandHandler(
IBillingRepository billingRepository,
ICurrentUserAccessor currentUserAccessor)
: IRequestHandler
{
///
public async Task Handle(
ConfirmPaymentCommand request,
CancellationToken cancellationToken)
{
// 1. 获取账单(带跟踪)
var billing = await billingRepository.GetByIdForUpdateAsync(request.BillingId, cancellationToken);
// 2. 如果不存在,返回 null
if (billing is null)
{
return null;
}
// 3. 获取当前用户 ID
var currentUserId = currentUserAccessor.UserId;
var now = DateTime.UtcNow;
// 4. 创建支付记录(已审核通过状态)
var payment = new TenantPayment
{
TenantId = billing.TenantId,
BillingStatementId = billing.Id,
Amount = request.Amount,
Method = request.Method,
Status = TenantPaymentStatus.Success,
TransactionNo = request.TransactionNo,
ProofUrl = request.ProofUrl,
Notes = request.Notes,
PaidAt = now,
VerifiedBy = currentUserId,
VerifiedAt = now,
CreatedAt = now,
CreatedBy = currentUserId
};
// 5. 添加支付记录
await billingRepository.AddPaymentAsync(payment, cancellationToken);
// 6. 更新账单已付金额
billing.AmountPaid += request.Amount;
// 7. 如果已付金额 >= 应付金额,更新账单状态为已支付
if (billing.AmountPaid >= billing.AmountDue)
{
billing.Status = TenantBillingStatus.Paid;
}
// 8. 更新账单时间戳
billing.UpdatedAt = now;
// 9. 保存变更
await billingRepository.SaveChangesAsync(cancellationToken);
// 10. 返回支付记录 DTO
return new PaymentRecordDto
{
Id = payment.Id,
BillingStatementId = payment.BillingStatementId,
Amount = payment.Amount,
Method = (int)payment.Method,
Status = (int)payment.Status,
TransactionNo = payment.TransactionNo,
ProofUrl = payment.ProofUrl,
PaidAt = payment.PaidAt,
Notes = payment.Notes,
VerifiedBy = payment.VerifiedBy,
VerifiedAt = payment.VerifiedAt,
RefundReason = payment.RefundReason,
RefundedAt = payment.RefundedAt,
CreatedAt = payment.CreatedAt
};
}
}