merge: bring finance report api changes into dev
Some checks failed
Build and Deploy TenantApi + SkuWorker / build-and-deploy (push) Failing after 26s

This commit is contained in:
2026-03-04 22:03:57 +08:00
40 changed files with 14930 additions and 2 deletions

View File

@@ -103,6 +103,18 @@ public sealed class TakeoutAppDbContext(
/// </summary>
public DbSet<TenantInvoiceRecord> TenantInvoiceRecords => Set<TenantInvoiceRecord>();
/// <summary>
/// 经营报表快照。
/// </summary>
public DbSet<FinanceBusinessReportSnapshot> FinanceBusinessReportSnapshots => Set<FinanceBusinessReportSnapshot>();
/// <summary>
/// 成本配置。
/// </summary>
public DbSet<FinanceCostProfile> FinanceCostProfiles => Set<FinanceCostProfile>();
/// <summary>
/// 成本日覆盖。
/// </summary>
public DbSet<FinanceCostDailyOverride> FinanceCostDailyOverrides => Set<FinanceCostDailyOverride>();
/// <summary>
/// 成本录入汇总。
/// </summary>
public DbSet<FinanceCostEntry> FinanceCostEntries => Set<FinanceCostEntry>();
@@ -544,6 +556,9 @@ public sealed class TakeoutAppDbContext(
ConfigureTenantVisibilityRoleRule(modelBuilder.Entity<TenantVisibilityRoleRule>());
ConfigureTenantInvoiceSetting(modelBuilder.Entity<TenantInvoiceSetting>());
ConfigureTenantInvoiceRecord(modelBuilder.Entity<TenantInvoiceRecord>());
ConfigureFinanceBusinessReportSnapshot(modelBuilder.Entity<FinanceBusinessReportSnapshot>());
ConfigureFinanceCostProfile(modelBuilder.Entity<FinanceCostProfile>());
ConfigureFinanceCostDailyOverride(modelBuilder.Entity<FinanceCostDailyOverride>());
ConfigureFinanceCostEntry(modelBuilder.Entity<FinanceCostEntry>());
ConfigureFinanceCostEntryItem(modelBuilder.Entity<FinanceCostEntryItem>());
ConfigureQuotaPackage(modelBuilder.Entity<QuotaPackage>());
@@ -1109,6 +1124,68 @@ public sealed class TakeoutAppDbContext(
builder.HasIndex(x => new { x.TenantId, x.InvoiceType, x.AppliedAt });
}
private static void ConfigureFinanceBusinessReportSnapshot(EntityTypeBuilder<FinanceBusinessReportSnapshot> builder)
{
builder.ToTable("finance_business_report_snapshots");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.PeriodType).HasConversion<int>().IsRequired();
builder.Property(x => x.PeriodStartAt).IsRequired();
builder.Property(x => x.PeriodEndAt).IsRequired();
builder.Property(x => x.Status).HasConversion<int>().IsRequired();
builder.Property(x => x.RevenueAmount).HasPrecision(18, 2);
builder.Property(x => x.OrderCount).IsRequired();
builder.Property(x => x.AverageOrderValue).HasPrecision(18, 2);
builder.Property(x => x.RefundRate).HasPrecision(9, 4);
builder.Property(x => x.CostTotalAmount).HasPrecision(18, 2);
builder.Property(x => x.NetProfitAmount).HasPrecision(18, 2);
builder.Property(x => x.ProfitRate).HasPrecision(9, 4);
builder.Property(x => x.KpiComparisonJson).HasColumnType("text").IsRequired();
builder.Property(x => x.IncomeBreakdownJson).HasColumnType("text").IsRequired();
builder.Property(x => x.CostBreakdownJson).HasColumnType("text").IsRequired();
builder.Property(x => x.LastError).HasMaxLength(1024);
builder.Property(x => x.HangfireJobId).HasMaxLength(64);
builder.Property(x => x.RetryCount).HasDefaultValue(0);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.PeriodType, x.PeriodStartAt }).IsUnique();
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.PeriodType, x.Status, x.PeriodStartAt });
builder.HasIndex(x => new { x.TenantId, x.Status, x.CreatedAt });
}
private static void ConfigureFinanceCostProfile(EntityTypeBuilder<FinanceCostProfile> builder)
{
builder.ToTable("finance_cost_profiles");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.Category).HasConversion<int>().IsRequired();
builder.Property(x => x.CalcMode).HasConversion<int>().IsRequired();
builder.Property(x => x.Ratio).HasPrecision(9, 6).IsRequired();
builder.Property(x => x.FixedDailyAmount).HasPrecision(18, 2).IsRequired();
builder.Property(x => x.EffectiveFrom).IsRequired();
builder.Property(x => x.EffectiveTo);
builder.Property(x => x.IsEnabled).IsRequired();
builder.Property(x => x.SortOrder).HasDefaultValue(100);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.Category, x.EffectiveFrom, x.EffectiveTo });
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.IsEnabled, x.SortOrder });
}
private static void ConfigureFinanceCostDailyOverride(EntityTypeBuilder<FinanceCostDailyOverride> builder)
{
builder.ToTable("finance_cost_daily_overrides");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.BusinessDate).IsRequired();
builder.Property(x => x.Category).HasConversion<int>().IsRequired();
builder.Property(x => x.Amount).HasPrecision(18, 2).IsRequired();
builder.Property(x => x.Remark).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.BusinessDate, x.Category }).IsUnique();
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.BusinessDate });
}
private static void ConfigureFinanceCostEntry(EntityTypeBuilder<FinanceCostEntry> builder)
{
builder.ToTable("finance_cost_entries");