using TakeoutSaaS.Domain.Tenants.Entities; using TakeoutSaaS.Domain.Tenants.Enums; namespace TakeoutSaaS.Domain.Tenants.Repositories; /// /// 租户账单仓储。 /// public interface ITenantBillingRepository { /// /// 查询账单列表,按状态与时间范围筛选。 /// /// 租户 ID。 /// 账单状态。 /// 开始时间(UTC)。 /// 结束时间(UTC)。 /// 取消标记。 /// 账单集合。 Task> SearchAsync( long tenantId, TenantBillingStatus? status, DateTime? from, DateTime? to, CancellationToken cancellationToken = default); /// /// 按 ID 获取账单。 /// /// 租户 ID。 /// 账单 ID。 /// 取消标记。 /// 账单实体或 null。 Task FindByIdAsync(long tenantId, long billingId, CancellationToken cancellationToken = default); /// /// 按账单编号获取账单。 /// /// 租户 ID。 /// 账单编号。 /// 取消标记。 /// 账单实体或 null。 Task FindByStatementNoAsync(long tenantId, string statementNo, CancellationToken cancellationToken = default); /// /// 按账单编号获取账单(不限租户,管理员端使用)。 /// /// 账单编号。 /// 取消标记。 /// 账单实体或 null。 Task GetByStatementNoAsync(string statementNo, CancellationToken cancellationToken = default); /// /// 判断是否已存在指定周期开始时间的未取消账单(用于自动续费幂等)。 /// /// 租户 ID。 /// 账单周期开始时间(UTC)。 /// 取消标记。 /// 存在返回 true,否则 false。 Task ExistsNotCancelledByPeriodStartAsync( long tenantId, DateTime periodStart, CancellationToken cancellationToken = default); /// /// 获取逾期账单列表(已过到期日且未支付)。 /// /// 取消标记。 /// 逾期账单集合。 Task> GetOverdueBillingsAsync(CancellationToken cancellationToken = default); /// /// 获取即将到期的账单列表(未来 N 天内到期且未支付)。 /// /// 提前天数。 /// 取消标记。 /// 即将到期的账单集合。 Task> GetBillingsDueSoonAsync(int daysAhead, CancellationToken cancellationToken = default); /// /// 按租户 ID 获取账单列表。 /// /// 租户 ID。 /// 取消标记。 /// 账单集合。 Task> GetByTenantIdAsync(long tenantId, CancellationToken cancellationToken = default); /// /// 按 ID 列表批量获取账单(管理员端/批量操作场景)。 /// /// 账单 ID 列表。 /// 取消标记。 /// 账单实体列表。 Task> GetByIdsAsync( IReadOnlyCollection billingIds, CancellationToken cancellationToken = default); /// /// 新增账单。 /// /// 账单实体。 /// 取消标记。 /// 异步任务。 Task AddAsync(TenantBillingStatement bill, CancellationToken cancellationToken = default); /// /// 更新账单。 /// /// 账单实体。 /// 取消标记。 /// 异步任务。 Task UpdateAsync(TenantBillingStatement bill, CancellationToken cancellationToken = default); /// /// 保存变更。 /// /// 取消标记。 /// 异步任务。 Task SaveChangesAsync(CancellationToken cancellationToken = default); /// /// 管理员端分页查询账单列表(跨租户)。 /// /// 租户 ID 筛选(可选)。 /// 账单状态筛选(可选)。 /// 开始时间(UTC,可选)。 /// 结束时间(UTC,可选)。 /// 最小应付金额筛选(包含,可选)。 /// 最大应付金额筛选(包含,可选)。 /// 关键词搜索(账单号或租户名)。 /// 页码(从 1 开始)。 /// 页大小。 /// 取消标记。 /// 账单集合与总数。 Task<(IReadOnlyList Items, int Total)> SearchPagedAsync( long? tenantId, TenantBillingStatus? status, DateTime? from, DateTime? to, decimal? minAmount, decimal? maxAmount, string? keyword, int pageNumber, int pageSize, CancellationToken cancellationToken = default); /// /// 获取账单统计数据(用于报表与仪表盘)。 /// /// 租户 ID(可选,管理员可查询所有租户)。 /// 统计开始时间(UTC)。 /// 统计结束时间(UTC)。 /// 分组方式(Day/Week/Month)。 /// 取消标记。 /// 统计结果。 Task GetStatisticsAsync( long? tenantId, DateTime startDate, DateTime endDate, string groupBy, CancellationToken cancellationToken = default); /// /// 按 ID 获取账单(不限租户,管理员端使用)。 /// /// 账单 ID。 /// 取消标记。 /// 账单实体或 null。 Task FindByIdAsync(long billingId, CancellationToken cancellationToken = default); } /// /// 账单统计结果。 /// public sealed record TenantBillingStatistics { /// /// 总账单金额(统计区间内)。 /// public decimal TotalAmount { get; init; } /// /// 已支付金额(统计区间内)。 /// public decimal PaidAmount { get; init; } /// /// 未支付金额(统计区间内)。 /// public decimal UnpaidAmount { get; init; } /// /// 逾期金额(统计区间内)。 /// public decimal OverdueAmount { get; init; } /// /// 总账单数量(统计区间内)。 /// public int TotalCount { get; init; } /// /// 已支付账单数量(统计区间内)。 /// public int PaidCount { get; init; } /// /// 未支付账单数量(统计区间内)。 /// public int UnpaidCount { get; init; } /// /// 逾期账单数量(统计区间内)。 /// public int OverdueCount { get; init; } /// /// 趋势数据(按 groupBy 聚合)。 /// public IReadOnlyList TrendData { get; init; } = []; } /// /// 账单趋势统计点。 /// public sealed record TenantBillingTrendDataPoint { /// /// 分组时间点(Day/Week/Month 的代表日期,UTC)。 /// public DateTime Period { get; init; } /// /// 账单数量。 /// public int Count { get; init; } /// /// 总金额。 /// public decimal TotalAmount { get; init; } /// /// 已支付金额。 /// public decimal PaidAmount { get; init; } }