Files
TakeoutSaaS.TenantApi/src/Application/TakeoutSaaS.Application/App/Billings/Handlers/CreateBillingCommandHandler.cs
2026-01-04 21:22:26 +08:00

66 lines
2.2 KiB
C#

using MediatR;
using System.Text.Json;
using TakeoutSaaS.Application.App.Billings.Commands;
using TakeoutSaaS.Application.App.Billings.Dto;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Ids;
namespace TakeoutSaaS.Application.App.Billings.Handlers;
/// <summary>
/// 创建账单命令处理器。
/// </summary>
public sealed class CreateBillingCommandHandler(
ITenantRepository tenantRepository,
ITenantBillingRepository billingRepository,
IIdGenerator idGenerator)
: IRequestHandler<CreateBillingCommand, BillingDetailDto>
{
/// <inheritdoc />
public async Task<BillingDetailDto> Handle(CreateBillingCommand request, CancellationToken cancellationToken)
{
// 1. 校验租户存在
var tenant = await tenantRepository.FindByIdAsync(request.TenantId, cancellationToken);
if (tenant is null)
{
throw new BusinessException(ErrorCodes.NotFound, "租户不存在");
}
// 2. 构建账单实体
var now = DateTime.UtcNow;
var statementNo = $"BIL-{now:yyyyMMdd}-{idGenerator.NextId()}";
var lineItemsJson = JsonSerializer.Serialize(request.LineItems);
var billing = new TenantBillingStatement
{
TenantId = request.TenantId,
StatementNo = statementNo,
BillingType = request.BillingType,
SubscriptionId = null,
PeriodStart = now,
PeriodEnd = now,
AmountDue = request.AmountDue,
DiscountAmount = 0m,
TaxAmount = 0m,
AmountPaid = 0m,
Currency = "CNY",
Status = TenantBillingStatus.Pending,
DueDate = request.DueDate,
LineItemsJson = lineItemsJson,
Notes = request.Notes
};
// 3. 持久化账单
await billingRepository.AddAsync(billing, cancellationToken);
await billingRepository.SaveChangesAsync(cancellationToken);
// 4. 返回详情 DTO
return billing.ToBillingDetailDto([], tenant.Name);
}
}