feat: 套餐使用统计增加MRR与ARR
This commit is contained in:
@@ -24,5 +24,14 @@ public sealed class TenantPackageUsageDto
|
|||||||
/// 历史总订阅记录数量(不含软删)。
|
/// 历史总订阅记录数量(不含软删)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int TotalSubscriptionCount { get; init; }
|
public int TotalSubscriptionCount { get; init; }
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MRR(Monthly Recurring Revenue)粗看:按“当前有效订阅数 × 套餐月付等效价”估算。
|
||||||
|
/// </summary>
|
||||||
|
public decimal Mrr { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ARR(Annual Recurring Revenue)粗看:按“当前有效订阅数 × 套餐年付等效价”估算。
|
||||||
|
/// </summary>
|
||||||
|
public decimal Arr { get; init; }
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,7 +45,9 @@ public sealed class GetTenantPackageUsagesQueryHandler(IDapperExecutor dapperExe
|
|||||||
TenantPackageId = reader.GetInt64(0),
|
TenantPackageId = reader.GetInt64(0),
|
||||||
ActiveSubscriptionCount = reader.GetInt32(1),
|
ActiveSubscriptionCount = reader.GetInt32(1),
|
||||||
ActiveTenantCount = reader.GetInt32(2),
|
ActiveTenantCount = reader.GetInt32(2),
|
||||||
TotalSubscriptionCount = reader.GetInt32(3)
|
TotalSubscriptionCount = reader.GetInt32(3),
|
||||||
|
Mrr = reader.IsDBNull(4) ? 0m : reader.GetDecimal(4),
|
||||||
|
Arr = reader.IsDBNull(5) ? 0m : reader.GetDecimal(5)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,16 +58,17 @@ public sealed class GetTenantPackageUsagesQueryHandler(IDapperExecutor dapperExe
|
|||||||
|
|
||||||
private static string BuildSql(long[]? ids, out (string Name, object? Value)[] parameters, DateTime now)
|
private static string BuildSql(long[]? ids, out (string Name, object? Value)[] parameters, DateTime now)
|
||||||
{
|
{
|
||||||
// 1. 基础查询
|
// 1. 基础查询:先按订阅表聚合,再回连套餐表计算 MRR/ARR
|
||||||
var builder = new System.Text.StringBuilder();
|
var builder = new System.Text.StringBuilder();
|
||||||
builder.AppendLine("""
|
builder.AppendLine("""
|
||||||
select
|
with stats as (
|
||||||
"TenantPackageId" as "TenantPackageId",
|
select
|
||||||
count(*) filter (where "Status" = 1 and "EffectiveFrom" <= @now and "EffectiveTo" >= @now) as "ActiveSubscriptionCount",
|
"TenantPackageId" as "TenantPackageId",
|
||||||
count(distinct "TenantId") filter (where "Status" = 1 and "EffectiveFrom" <= @now and "EffectiveTo" >= @now) as "ActiveTenantCount",
|
count(*) filter (where "Status" = 1 and "EffectiveFrom" <= @now and "EffectiveTo" >= @now) as "ActiveSubscriptionCount",
|
||||||
count(*) as "TotalSubscriptionCount"
|
count(distinct "TenantId") filter (where "Status" = 1 and "EffectiveFrom" <= @now and "EffectiveTo" >= @now) as "ActiveTenantCount",
|
||||||
from public.tenant_subscriptions
|
count(*) as "TotalSubscriptionCount"
|
||||||
where "DeletedAt" is null
|
from public.tenant_subscriptions
|
||||||
|
where "DeletedAt" is null
|
||||||
""");
|
""");
|
||||||
|
|
||||||
var list = new List<(string Name, object? Value)>
|
var list = new List<(string Name, object? Value)>
|
||||||
@@ -92,8 +95,20 @@ public sealed class GetTenantPackageUsagesQueryHandler(IDapperExecutor dapperExe
|
|||||||
builder.AppendLine(")");
|
builder.AppendLine(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. (空行后) 分组
|
// 3. (空行后) 分组与回连套餐表
|
||||||
builder.AppendLine("group by \"TenantPackageId\";");
|
builder.AppendLine("""
|
||||||
|
group by "TenantPackageId"
|
||||||
|
)
|
||||||
|
select
|
||||||
|
s."TenantPackageId" as "TenantPackageId",
|
||||||
|
s."ActiveSubscriptionCount" as "ActiveSubscriptionCount",
|
||||||
|
s."ActiveTenantCount" as "ActiveTenantCount",
|
||||||
|
s."TotalSubscriptionCount" as "TotalSubscriptionCount",
|
||||||
|
(s."ActiveSubscriptionCount"::numeric * coalesce(p."MonthlyPrice", (p."YearlyPrice" / 12.0), 0))::numeric(18, 2) as "Mrr",
|
||||||
|
(s."ActiveSubscriptionCount"::numeric * coalesce(p."YearlyPrice", (p."MonthlyPrice" * 12), 0))::numeric(18, 2) as "Arr"
|
||||||
|
from stats s
|
||||||
|
left join public.tenant_packages p on p."Id" = s."TenantPackageId" and p."DeletedAt" is null;
|
||||||
|
""");
|
||||||
|
|
||||||
parameters = list.ToArray();
|
parameters = list.ToArray();
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
|
|||||||
Reference in New Issue
Block a user