fix:修复注释错误
This commit is contained in:
@@ -23,10 +23,10 @@ public sealed class CancelBillingCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.NotFound, "账单不存在");
|
||||
}
|
||||
|
||||
// 2. (空行后) 取消账单(领域规则校验在实体方法内)
|
||||
// 2. 取消账单(领域规则校验在实体方法内)
|
||||
billing.Cancel(request.Reason);
|
||||
|
||||
// 3. (空行后) 持久化
|
||||
// 3. 持久化
|
||||
await billingRepository.UpdateAsync(billing, cancellationToken);
|
||||
await billingRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
|
||||
@@ -30,14 +30,14 @@ public sealed class ConfirmPaymentCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.Unauthorized, "未登录或无效的操作者身份");
|
||||
}
|
||||
|
||||
// 2. (空行后) 查询账单
|
||||
// 2. 查询账单
|
||||
var billing = await billingRepository.FindByIdAsync(request.BillingId, cancellationToken);
|
||||
if (billing is null)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.NotFound, "账单不存在");
|
||||
}
|
||||
|
||||
// 3. (空行后) 业务规则检查
|
||||
// 3. 业务规则检查
|
||||
if (billing.Status == TenantBillingStatus.Paid)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.BusinessError, "已支付账单不允许重复收款");
|
||||
@@ -48,7 +48,7 @@ public sealed class ConfirmPaymentCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.BusinessError, "已取消账单不允许收款");
|
||||
}
|
||||
|
||||
// 4. (空行后) 金额边界:不允许超过剩余应收(与前端校验保持一致)
|
||||
// 4. 金额边界:不允许超过剩余应收(与前端校验保持一致)
|
||||
var totalAmount = billing.CalculateTotalAmount();
|
||||
var remainingAmount = totalAmount - billing.AmountPaid;
|
||||
if (request.Amount > remainingAmount)
|
||||
@@ -56,7 +56,7 @@ public sealed class ConfirmPaymentCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.BadRequest, "支付金额不能超过剩余应收");
|
||||
}
|
||||
|
||||
// 5. (空行后) 幂等校验:交易号唯一
|
||||
// 5. 幂等校验:交易号唯一
|
||||
if (!string.IsNullOrWhiteSpace(request.TransactionNo))
|
||||
{
|
||||
var exists = await paymentRepository.GetByTransactionNoAsync(request.TransactionNo.Trim(), cancellationToken);
|
||||
@@ -66,7 +66,7 @@ public sealed class ConfirmPaymentCommandHandler(
|
||||
}
|
||||
}
|
||||
|
||||
// 6. (空行后) 构建支付记录并立即审核通过
|
||||
// 6. 构建支付记录并立即审核通过
|
||||
var now = DateTime.UtcNow;
|
||||
var payment = new TenantPayment
|
||||
{
|
||||
@@ -84,15 +84,15 @@ public sealed class ConfirmPaymentCommandHandler(
|
||||
|
||||
payment.Verify(currentUserAccessor.UserId);
|
||||
|
||||
// 7. (空行后) 同步更新账单已收金额/状态(支持分次收款)
|
||||
// 7. 同步更新账单已收金额/状态(支持分次收款)
|
||||
billing.MarkAsPaid(payment.Amount, payment.TransactionNo ?? string.Empty);
|
||||
|
||||
// 8. (空行后) 持久化变更(同一 DbContext 下单次 SaveChanges 可提交两张表)
|
||||
// 8. 持久化变更(同一 DbContext 下单次 SaveChanges 可提交两张表)
|
||||
await paymentRepository.AddAsync(payment, cancellationToken);
|
||||
await billingRepository.UpdateAsync(billing, cancellationToken);
|
||||
await paymentRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 9. (空行后) 返回 DTO
|
||||
// 9. 返回 DTO
|
||||
return payment.ToPaymentRecordDto();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public sealed class CreateBillingCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.NotFound, "租户不存在");
|
||||
}
|
||||
|
||||
// 2. (空行后) 构建账单实体
|
||||
// 2. 构建账单实体
|
||||
var now = DateTime.UtcNow;
|
||||
var statementNo = $"BIL-{now:yyyyMMdd}-{idGenerator.NextId()}";
|
||||
var lineItemsJson = JsonSerializer.Serialize(request.LineItems);
|
||||
@@ -54,11 +54,11 @@ public sealed class CreateBillingCommandHandler(
|
||||
Notes = request.Notes
|
||||
};
|
||||
|
||||
// 3. (空行后) 持久化账单
|
||||
// 3. 持久化账单
|
||||
await billingRepository.AddAsync(billing, cancellationToken);
|
||||
await billingRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 4. (空行后) 返回详情 DTO
|
||||
// 4. 返回详情 DTO
|
||||
return billing.ToBillingDetailDto([], tenant.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@ public sealed class ExportBillingsQueryHandler(
|
||||
throw new BusinessException(ErrorCodes.BadRequest, "账单 ID 列表不能为空");
|
||||
}
|
||||
|
||||
// 2. (空行后) 查询账单数据
|
||||
// 2. 查询账单数据
|
||||
var billings = await billingRepository.GetByIdsAsync(request.BillingIds, cancellationToken);
|
||||
if (billings.Count == 0)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.NotFound, "未找到任何匹配的账单");
|
||||
}
|
||||
|
||||
// 3. (空行后) 根据格式导出
|
||||
// 3. 根据格式导出
|
||||
var format = (request.Format ?? string.Empty).Trim().ToLowerInvariant();
|
||||
return format switch
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ public sealed class GenerateSubscriptionBillingCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.NotFound, "订阅不存在");
|
||||
}
|
||||
|
||||
// 2. (空行后) 校验套餐价格信息
|
||||
// 2. 校验套餐价格信息
|
||||
var subscription = detail.Subscription;
|
||||
var package = detail.Package;
|
||||
if (package is null)
|
||||
@@ -38,7 +38,7 @@ public sealed class GenerateSubscriptionBillingCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.BusinessError, "订阅未关联有效套餐,无法生成账单");
|
||||
}
|
||||
|
||||
// 3. (空行后) 按订阅周期选择价格(简化规则:优先按年/按月)
|
||||
// 3. 按订阅周期选择价格(简化规则:优先按年/按月)
|
||||
var billingPeriodDays = (subscription.EffectiveTo - subscription.EffectiveFrom).TotalDays;
|
||||
var amountDue = billingPeriodDays >= 300
|
||||
? package.YearlyPrice
|
||||
@@ -49,14 +49,14 @@ public sealed class GenerateSubscriptionBillingCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.BusinessError, "套餐价格未配置,无法生成账单");
|
||||
}
|
||||
|
||||
// 4. (空行后) 幂等校验:同一周期开始时间仅允许存在一张未取消账单
|
||||
// 4. 幂等校验:同一周期开始时间仅允许存在一张未取消账单
|
||||
var exists = await billingRepository.ExistsNotCancelledByPeriodStartAsync(subscription.TenantId, subscription.EffectiveFrom, cancellationToken);
|
||||
if (exists)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Conflict, "该订阅周期的账单已存在");
|
||||
}
|
||||
|
||||
// 5. (空行后) 构建账单实体
|
||||
// 5. 构建账单实体
|
||||
var now = DateTime.UtcNow;
|
||||
var statementNo = $"BIL-{now:yyyyMMdd}-{idGenerator.NextId()}";
|
||||
var lineItems = new List<BillingLineItemDto>
|
||||
@@ -91,11 +91,11 @@ public sealed class GenerateSubscriptionBillingCommandHandler(
|
||||
Notes = subscription.Notes
|
||||
};
|
||||
|
||||
// 6. (空行后) 持久化账单
|
||||
// 6. 持久化账单
|
||||
await billingRepository.AddAsync(billing, cancellationToken);
|
||||
await billingRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 7. (空行后) 返回详情 DTO
|
||||
// 7. 返回详情 DTO
|
||||
return billing.ToBillingDetailDto([], detail.TenantName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public sealed class GetBillingDetailQueryHandler(
|
||||
throw new BusinessException(ErrorCodes.NotFound, "账单不存在");
|
||||
}
|
||||
|
||||
// 1.2 (空行后) 读取账单行数据到内存(释放 Reader,避免同连接并发执行命令)
|
||||
// 1.2 读取账单行数据到内存(释放 Reader,避免同连接并发执行命令)
|
||||
var billingId = billReader.GetInt64(0);
|
||||
var tenantId = billReader.GetInt64(1);
|
||||
var tenantName = billReader.IsDBNull(2) ? string.Empty : billReader.GetString(2);
|
||||
@@ -71,10 +71,10 @@ public sealed class GetBillingDetailQueryHandler(
|
||||
DateTime? updatedAt = billReader.IsDBNull(21) ? null : billReader.GetDateTime(21);
|
||||
long? updatedBy = billReader.IsDBNull(22) ? null : billReader.GetInt64(22);
|
||||
|
||||
// 1.3 (空行后) 主动释放账单 Reader,确保后续查询不会触发 Npgsql 并发命令异常
|
||||
// 1.3 主动释放账单 Reader,确保后续查询不会触发 Npgsql 并发命令异常
|
||||
await billReader.DisposeAsync();
|
||||
|
||||
// 1.4 (空行后) 反序列化账单明细
|
||||
// 1.4 反序列化账单明细
|
||||
var lineItems = new List<BillingLineItemDto>();
|
||||
if (!string.IsNullOrWhiteSpace(lineItemsJson))
|
||||
{
|
||||
@@ -88,7 +88,7 @@ public sealed class GetBillingDetailQueryHandler(
|
||||
}
|
||||
}
|
||||
|
||||
// 1.5 (空行后) 查询支付记录
|
||||
// 1.5 查询支付记录
|
||||
var payments = new List<PaymentRecordDto>();
|
||||
await using var paymentCommand = CreateCommand(
|
||||
connection,
|
||||
@@ -121,7 +121,7 @@ public sealed class GetBillingDetailQueryHandler(
|
||||
});
|
||||
}
|
||||
|
||||
// 1.6 (空行后) 组装详情 DTO
|
||||
// 1.6 组装详情 DTO
|
||||
var totalAmount = amountDue - discountAmount + taxAmount;
|
||||
|
||||
return new BillingDetailDto
|
||||
|
||||
@@ -33,13 +33,13 @@ public sealed class GetBillingListQueryHandler(
|
||||
var maxAmount = request.MaxAmount;
|
||||
var offset = (page - 1) * pageSize;
|
||||
|
||||
// 1.1 (空行后) 金额区间规范化(避免 min > max 导致结果为空)
|
||||
// 1.1 金额区间规范化(避免 min > max 导致结果为空)
|
||||
if (minAmount.HasValue && maxAmount.HasValue && minAmount.Value > maxAmount.Value)
|
||||
{
|
||||
(minAmount, maxAmount) = (maxAmount, minAmount);
|
||||
}
|
||||
|
||||
// 2. (空行后) 排序白名单(防 SQL 注入)
|
||||
// 2. 排序白名单(防 SQL 注入)
|
||||
var orderBy = request.SortBy?.Trim() switch
|
||||
{
|
||||
"DueDate" => "b.\"DueDate\"",
|
||||
@@ -50,7 +50,7 @@ public sealed class GetBillingListQueryHandler(
|
||||
_ => "b.\"CreatedAt\""
|
||||
};
|
||||
|
||||
// 3. (空行后) 查询总数 + 列表
|
||||
// 3. 查询总数 + 列表
|
||||
return await dapperExecutor.QueryAsync(
|
||||
DatabaseConstants.AppDataSource,
|
||||
DatabaseConnectionRole.Read,
|
||||
@@ -72,7 +72,7 @@ public sealed class GetBillingListQueryHandler(
|
||||
],
|
||||
token);
|
||||
|
||||
// 3.2 (空行后) 查询列表
|
||||
// 3.2 查询列表
|
||||
var listSql = BuildListSql(orderBy, request.SortDesc);
|
||||
await using var listCommand = CreateCommand(
|
||||
connection,
|
||||
@@ -102,7 +102,7 @@ public sealed class GetBillingListQueryHandler(
|
||||
var taxAmount = reader.GetDecimal(10);
|
||||
var totalAmount = amountDue - discountAmount + taxAmount;
|
||||
|
||||
// 3.2.1 (空行后) 逾期辅助字段
|
||||
// 3.2.1 逾期辅助字段
|
||||
var isOverdue = status is TenantBillingStatus.Overdue
|
||||
|| (status is TenantBillingStatus.Pending && dueDate < now);
|
||||
var overdueDays = dueDate < now ? (int)(now - dueDate).TotalDays : 0;
|
||||
@@ -132,7 +132,7 @@ public sealed class GetBillingListQueryHandler(
|
||||
});
|
||||
}
|
||||
|
||||
// 3.3 (空行后) 返回分页
|
||||
// 3.3 返回分页
|
||||
return new PagedResult<BillingListDto>(items, page, pageSize, total);
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
@@ -51,7 +51,7 @@ public sealed class GetBillingPaymentsQueryHandler(
|
||||
throw new BusinessException(ErrorCodes.NotFound, "账单不存在");
|
||||
}
|
||||
|
||||
// 1.2 (空行后) 查询支付记录
|
||||
// 1.2 查询支付记录
|
||||
await using var command = CreateCommand(
|
||||
connection,
|
||||
"""
|
||||
|
||||
@@ -29,7 +29,7 @@ public sealed class GetBillingStatisticsQueryHandler(
|
||||
var endDate = request.EndDate ?? DateTime.UtcNow;
|
||||
var groupBy = NormalizeGroupBy(request.GroupBy);
|
||||
|
||||
// 2. (空行后) 查询统计数据(总览 + 趋势)
|
||||
// 2. 查询统计数据(总览 + 趋势)
|
||||
return await dapperExecutor.QueryAsync(
|
||||
DatabaseConstants.AppDataSource,
|
||||
DatabaseConnectionRole.Read,
|
||||
@@ -59,7 +59,7 @@ public sealed class GetBillingStatisticsQueryHandler(
|
||||
var totalAmountUnpaid = summaryReader.IsDBNull(7) ? 0m : summaryReader.GetDecimal(7);
|
||||
var totalOverdueAmount = summaryReader.IsDBNull(8) ? 0m : summaryReader.GetDecimal(8);
|
||||
|
||||
// 2.2 (空行后) 趋势数据
|
||||
// 2.2 趋势数据
|
||||
await using var trendCommand = CreateCommand(
|
||||
connection,
|
||||
BuildTrendSql(groupBy),
|
||||
@@ -83,7 +83,7 @@ public sealed class GetBillingStatisticsQueryHandler(
|
||||
countTrend[key] = trendReader.IsDBNull(3) ? 0 : trendReader.GetInt32(3);
|
||||
}
|
||||
|
||||
// 2.3 (空行后) 组装 DTO
|
||||
// 2.3 组装 DTO
|
||||
return new BillingStatisticsDto
|
||||
{
|
||||
TenantId = request.TenantId,
|
||||
|
||||
@@ -31,7 +31,7 @@ public sealed class GetOverdueBillingsQueryHandler(
|
||||
var offset = (page - 1) * pageSize;
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
// 2. (空行后) 查询总数 + 列表
|
||||
// 2. 查询总数 + 列表
|
||||
return await dapperExecutor.QueryAsync(
|
||||
DatabaseConstants.AppDataSource,
|
||||
DatabaseConnectionRole.Read,
|
||||
@@ -46,7 +46,7 @@ public sealed class GetOverdueBillingsQueryHandler(
|
||||
],
|
||||
token);
|
||||
|
||||
// 2.2 (空行后) 查询列表
|
||||
// 2.2 查询列表
|
||||
await using var listCommand = CreateCommand(
|
||||
connection,
|
||||
BuildListSql(),
|
||||
@@ -93,7 +93,7 @@ public sealed class GetOverdueBillingsQueryHandler(
|
||||
});
|
||||
}
|
||||
|
||||
// 2.3 (空行后) 返回分页
|
||||
// 2.3 返回分页
|
||||
return new PagedResult<BillingListDto>(items, page, pageSize, total);
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
@@ -34,7 +34,7 @@ public sealed class RecordPaymentCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.NotFound, "账单不存在");
|
||||
}
|
||||
|
||||
// 2. (空行后) 业务规则检查
|
||||
// 2. 业务规则检查
|
||||
if (billing.Status == TenantBillingStatus.Paid)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.BusinessError, "已支付账单不允许重复收款");
|
||||
@@ -45,7 +45,7 @@ public sealed class RecordPaymentCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.BusinessError, "已取消账单不允许收款");
|
||||
}
|
||||
|
||||
// 3. (空行后) 幂等校验:交易号唯一
|
||||
// 3. 幂等校验:交易号唯一
|
||||
if (!string.IsNullOrWhiteSpace(request.TransactionNo))
|
||||
{
|
||||
var exists = await paymentRepository.GetByTransactionNoAsync(request.TransactionNo.Trim(), cancellationToken);
|
||||
@@ -55,7 +55,7 @@ public sealed class RecordPaymentCommandHandler(
|
||||
}
|
||||
}
|
||||
|
||||
// 4. (空行后) 构建支付记录(默认待审核)
|
||||
// 4. 构建支付记录(默认待审核)
|
||||
var now = DateTime.UtcNow;
|
||||
var payment = new TenantPayment
|
||||
{
|
||||
@@ -71,11 +71,11 @@ public sealed class RecordPaymentCommandHandler(
|
||||
Notes = request.Notes
|
||||
};
|
||||
|
||||
// 5. (空行后) 持久化变更
|
||||
// 5. 持久化变更
|
||||
await paymentRepository.AddAsync(payment, cancellationToken);
|
||||
await paymentRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 6. (空行后) 返回 DTO
|
||||
// 6. 返回 DTO
|
||||
return payment.ToPaymentRecordDto();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed class UpdateBillingStatusCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.NotFound, "账单不存在");
|
||||
}
|
||||
|
||||
// 2. (空行后) 状态转换规则校验
|
||||
// 2. 状态转换规则校验
|
||||
if (billing.Status == TenantBillingStatus.Paid && request.NewStatus != TenantBillingStatus.Paid)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.BusinessError, "已支付账单不允许改为其他状态");
|
||||
@@ -35,7 +35,7 @@ public sealed class UpdateBillingStatusCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.BusinessError, "已取消账单不允许变更状态");
|
||||
}
|
||||
|
||||
// 3. (空行后) 更新状态与备注
|
||||
// 3. 更新状态与备注
|
||||
billing.Status = request.NewStatus;
|
||||
if (!string.IsNullOrWhiteSpace(request.Notes))
|
||||
{
|
||||
@@ -44,7 +44,7 @@ public sealed class UpdateBillingStatusCommandHandler(
|
||||
: $"{billing.Notes}\n[状态变更] {request.Notes}";
|
||||
}
|
||||
|
||||
// 4. (空行后) 持久化
|
||||
// 4. 持久化
|
||||
await billingRepository.UpdateAsync(billing, cancellationToken);
|
||||
await billingRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
|
||||
@@ -26,24 +26,24 @@ public sealed class VerifyPaymentCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.Unauthorized, "未登录或无效的操作者身份");
|
||||
}
|
||||
|
||||
// 2. (空行后) 查询支付记录
|
||||
// 2. 查询支付记录
|
||||
var payment = await paymentRepository.FindByIdAsync(request.PaymentId, cancellationToken);
|
||||
if (payment is null)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.NotFound, "支付记录不存在");
|
||||
}
|
||||
|
||||
// 3. (空行后) 查询关联账单
|
||||
// 3. 查询关联账单
|
||||
var billing = await billingRepository.FindByIdAsync(payment.BillingStatementId, cancellationToken);
|
||||
if (billing is null)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.NotFound, "关联账单不存在");
|
||||
}
|
||||
|
||||
// 4. (空行后) 归一化审核备注
|
||||
// 4. 归一化审核备注
|
||||
var normalizedNotes = string.IsNullOrWhiteSpace(request.Notes) ? null : request.Notes.Trim();
|
||||
|
||||
// 5. (空行后) 根据审核结果更新支付与账单状态
|
||||
// 5. 根据审核结果更新支付与账单状态
|
||||
if (request.Approved)
|
||||
{
|
||||
payment.Verify(currentUserAccessor.UserId);
|
||||
@@ -57,17 +57,17 @@ public sealed class VerifyPaymentCommandHandler(
|
||||
payment.Notes = normalizedNotes;
|
||||
}
|
||||
|
||||
// 6. (空行后) 持久化更新状态
|
||||
// 6. 持久化更新状态
|
||||
await paymentRepository.UpdateAsync(payment, cancellationToken);
|
||||
if (request.Approved)
|
||||
{
|
||||
await billingRepository.UpdateAsync(billing, cancellationToken);
|
||||
}
|
||||
|
||||
// 7. (空行后) 保存数据库更改
|
||||
// 7. 保存数据库更改
|
||||
await paymentRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 8. (空行后) 返回 DTO
|
||||
// 8. 返回 DTO
|
||||
return payment.ToPaymentRecordDto();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,32 +15,32 @@ public sealed class ConfirmPaymentCommandValidator : AbstractValidator<ConfirmPa
|
||||
.GreaterThan(0)
|
||||
.WithMessage("账单 ID 必须大于 0");
|
||||
|
||||
// 2. (空行后) 支付金额必须大于 0
|
||||
// 2. 支付金额必须大于 0
|
||||
RuleFor(x => x.Amount)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("支付金额必须大于 0")
|
||||
.LessThanOrEqualTo(1_000_000_000)
|
||||
.WithMessage("支付金额不能超过 10 亿");
|
||||
|
||||
// 3. (空行后) 支付方式必填
|
||||
// 3. 支付方式必填
|
||||
RuleFor(x => x.Method)
|
||||
.IsInEnum()
|
||||
.WithMessage("支付方式无效");
|
||||
|
||||
// 4. (空行后) 交易号必填
|
||||
// 4. 交易号必填
|
||||
RuleFor(x => x.TransactionNo)
|
||||
.NotEmpty()
|
||||
.WithMessage("交易号不能为空")
|
||||
.MaximumLength(64)
|
||||
.WithMessage("交易号不能超过 64 个字符");
|
||||
|
||||
// 5. (空行后) 支付凭证 URL(可选)
|
||||
// 5. 支付凭证 URL(可选)
|
||||
RuleFor(x => x.ProofUrl)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("支付凭证 URL 不能超过 500 个字符")
|
||||
.When(x => !string.IsNullOrWhiteSpace(x.ProofUrl));
|
||||
|
||||
// 6. (空行后) 备注(可选)
|
||||
// 6. 备注(可选)
|
||||
RuleFor(x => x.Notes)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("备注不能超过 500 个字符")
|
||||
|
||||
@@ -15,27 +15,27 @@ public sealed class CreateBillingCommandValidator : AbstractValidator<CreateBill
|
||||
.GreaterThan(0)
|
||||
.WithMessage("租户 ID 必须大于 0");
|
||||
|
||||
// 2. (空行后) 账单类型必填
|
||||
// 2. 账单类型必填
|
||||
RuleFor(x => x.BillingType)
|
||||
.IsInEnum()
|
||||
.WithMessage("账单类型无效");
|
||||
|
||||
// 3. (空行后) 应付金额必须大于 0
|
||||
// 3. 应付金额必须大于 0
|
||||
RuleFor(x => x.AmountDue)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("应付金额必须大于 0");
|
||||
|
||||
// 4. (空行后) 到期日必须是未来时间
|
||||
// 4. 到期日必须是未来时间
|
||||
RuleFor(x => x.DueDate)
|
||||
.GreaterThan(DateTime.UtcNow)
|
||||
.WithMessage("到期日必须是未来时间");
|
||||
|
||||
// 5. (空行后) 账单明细至少包含一项
|
||||
// 5. 账单明细至少包含一项
|
||||
RuleFor(x => x.LineItems)
|
||||
.NotEmpty()
|
||||
.WithMessage("账单明细不能为空");
|
||||
|
||||
// 6. (空行后) 账单明细项验证
|
||||
// 6. 账单明细项验证
|
||||
RuleForEach(x => x.LineItems)
|
||||
.ChildRules(lineItem =>
|
||||
{
|
||||
@@ -64,7 +64,7 @@ public sealed class CreateBillingCommandValidator : AbstractValidator<CreateBill
|
||||
.WithMessage("账单明细金额不能为负数");
|
||||
});
|
||||
|
||||
// 7. (空行后) 备注长度限制(可选)
|
||||
// 7. 备注长度限制(可选)
|
||||
RuleFor(x => x.Notes)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("备注不能超过 500 个字符")
|
||||
|
||||
@@ -15,32 +15,32 @@ public sealed class RecordPaymentCommandValidator : AbstractValidator<RecordPaym
|
||||
.GreaterThan(0)
|
||||
.WithMessage("账单 ID 必须大于 0");
|
||||
|
||||
// 2. (空行后) 支付金额必须大于 0
|
||||
// 2. 支付金额必须大于 0
|
||||
RuleFor(x => x.Amount)
|
||||
.GreaterThan(0)
|
||||
.WithMessage("支付金额必须大于 0")
|
||||
.LessThanOrEqualTo(1_000_000_000)
|
||||
.WithMessage("支付金额不能超过 10 亿");
|
||||
|
||||
// 3. (空行后) 支付方式必填
|
||||
// 3. 支付方式必填
|
||||
RuleFor(x => x.Method)
|
||||
.IsInEnum()
|
||||
.WithMessage("支付方式无效");
|
||||
|
||||
// 4. (空行后) 交易号必填
|
||||
// 4. 交易号必填
|
||||
RuleFor(x => x.TransactionNo)
|
||||
.NotEmpty()
|
||||
.WithMessage("交易号不能为空")
|
||||
.MaximumLength(64)
|
||||
.WithMessage("交易号不能超过 64 个字符");
|
||||
|
||||
// 5. (空行后) 支付凭证 URL(可选)
|
||||
// 5. 支付凭证 URL(可选)
|
||||
RuleFor(x => x.ProofUrl)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("支付凭证 URL 不能超过 500 个字符")
|
||||
.When(x => !string.IsNullOrWhiteSpace(x.ProofUrl));
|
||||
|
||||
// 6. (空行后) 备注(可选)
|
||||
// 6. 备注(可选)
|
||||
RuleFor(x => x.Notes)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("备注不能超过 500 个字符")
|
||||
|
||||
@@ -15,12 +15,12 @@ public sealed class UpdateBillingStatusCommandValidator : AbstractValidator<Upda
|
||||
.GreaterThan(0)
|
||||
.WithMessage("账单 ID 必须大于 0");
|
||||
|
||||
// 2. (空行后) 状态枚举校验
|
||||
// 2. 状态枚举校验
|
||||
RuleFor(x => x.NewStatus)
|
||||
.IsInEnum()
|
||||
.WithMessage("新状态无效");
|
||||
|
||||
// 3. (空行后) 备注长度限制(可选)
|
||||
// 3. 备注长度限制(可选)
|
||||
RuleFor(x => x.Notes)
|
||||
.MaximumLength(500)
|
||||
.WithMessage("备注不能超过 500 个字符")
|
||||
|
||||
Reference in New Issue
Block a user