🤖 每日自动备份 - 2026-04-25 08:00:01

This commit is contained in:
小溪 2026-04-25 08:00:01 +08:00
parent 96539da13f
commit ada8a8294f
4 changed files with 376 additions and 361 deletions

View File

@ -12,4 +12,4 @@ vala-component-practice-stat 8e768e2641019d27bd41f4647d2d90f24182a0554dad5ad9f41
cron-schedule e103cbb1806b28c891b9c856963325086ecaff32edec208f0a841865f26e8f3e cron-schedule e103cbb1806b28c891b9c856963325086ecaff32edec208f0a841865f26e8f3e
refund-user-learning-analysis 648fd4ae2b29167fd66eab4245bdaaef00242db3131f4919cc02f07ca2a9b59c refund-user-learning-analysis 648fd4ae2b29167fd66eab4245bdaaef00242db3131f4919cc02f07ca2a9b59c
phone-chapter-query ac429b4da5a89db16efdf1066edf4ecb1c050b93aff20dd4c652af5f5568e44f phone-chapter-query ac429b4da5a89db16efdf1066edf4ecb1c050b93aff20dd4c652af5f5568e44f
vala-order-amortization-stat 0f55a0c8d2d8bde498ac9781daa6f18cd4e4618d87f42263fe70e991a9980bea vala-order-amortization-stat 4f1facb78e3adb16af09cfab1578d3273bcaad1b4c1b409b9de2a97d0c63409b

View File

@ -1,6 +1,6 @@
# SKILL.md - vala-order-amortization-stat 订单均摊结算统计技能 # SKILL.md - vala-order-amortization-stat 订单均摊结算统计技能
## 技能描述 ## 技能描述
用于统计指定账期内的订单均摊收入、退费冲销,按天计算均摊金额,支持部分退费场景的剩余金额和周期自动计算。 用于统计指定账期内的订单均摊收入、退费冲销,按天计算均摊金额,支持部分退费场景的退后订单金额和周期自动计算。
## 触发场景 ## 触发场景
当用户提到以下关键词组合时激活本技能: 当用户提到以下关键词组合时激活本技能:
1. 订单均摊、按天均摊、收入均摊 1. 订单均摊、按天均摊、收入均摊
@ -66,7 +66,7 @@ vala-order-amortization-stat/
3. 账期前退费订单处理规则: 3. 账期前退费订单处理规则:
- 退费完成时间在账期起始日之前的订单,不会纳入本账期的冲销逻辑: - 退费完成时间在账期起始日之前的订单,不会纳入本账期的冲销逻辑:
- 全额退费订单:冲销动作已在退费发生的对应账期执行完毕,本账期完全不统计该订单的任何数据 - 全额退费订单:冲销动作已在退费发生的对应账期执行完毕,本账期完全不统计该订单的任何数据
- 部分退费订单:冲销动作、剩余金额/剩余周期调整已在退费发生的对应账期完成,本账期仅按调整后的剩余金额计算均摊,不产生额外冲销金额 - 部分退费订单:冲销动作、退后订单金额/剩余周期调整已在退费发生的对应账期完成,本账期仅按调整后的退后订单金额计算均摊,不产生额外冲销金额
### 步骤3核心计算逻辑 ### 步骤3核心计算逻辑
#### 3.1 周期计算 #### 3.1 周期计算
- 每个订单的总均摊周期 = bi_vala_seasonal_ticket中同一order_no下status != -1的不同id数量 × 90天 - 每个订单的总均摊周期 = bi_vala_seasonal_ticket中同一order_no下status != -1的不同id数量 × 90天
@ -76,13 +76,14 @@ vala-order-amortization-stat/
- 税率规则: - 税率规则:
- 订单下单时间在2026年5月1日之前税率1% - 订单下单时间在2026年5月1日之前税率1%
- 订单下单时间在2026年5月1日及之后税率6% - 订单下单时间在2026年5月1日及之后税率6%
- 订单税后金额 = (bi_vala_order.pay_amount_int / 100) × (1 - 税率)(单位:元) - 订单税后金额 = (bi_vala_order.pay_amount_int / 100) / (1 + 税率)(单位:元)
- 订单税费金额 = (bi_vala_order.pay_amount_int / 100) × 税率(单位:元) - 订单税费金额 = (bi_vala_order.pay_amount_int / 100) / (1 + 税率) × 税率(单位:元)
- **计税方式**:价外税,即订单金额为含税价,需先剥离税额再计算税后金额
- **均摊规则更新**:所有均摊计算均基于税后金额进行,含税金额和税费单独统计 - **均摊规则更新**:所有均摊计算均基于税后金额进行,含税金额和税费单独统计
- 日均摊金额(税后)= 订单税后金额 / 总均摊周期 - 日均摊金额(税后)= 订单税后金额 / 总均摊周期
- 🔹 周期最后一天补差规则:订单均摊周期的最后一天,均摊金额不按日均摊计算,采用补差方式确保总额完全匹配: - 🔹 周期最后一天补差规则:订单均摊周期的最后一天,均摊金额不按日均摊计算,采用补差方式确保总额完全匹配:
- 正常订单:最后一天均摊金额 = 订单税后总金额 - 前(总均摊周期-1天累计已均摊金额 - 正常订单:最后一天均摊金额 = 订单税后总金额 - 前(总均摊周期-1天累计已均摊金额
- 部分退费订单:最后一天均摊金额 = 订单剩余税后金额 - 剩余均摊周期前(剩余天数-1天累计已均摊金额 - 部分退费订单:最后一天均摊金额 = 退后订单税后金额 - 剩余均摊周期前(剩余天数-1天累计已均摊金额
避免浮点精度导致的金额尾差 避免浮点精度导致的金额尾差
#### 3.2 退费场景计算 #### 3.2 退费场景计算
所有退费冲销金额均为税后金额,税费同步对应冲销 所有退费冲销金额均为税后金额,税费同步对应冲销
@ -91,7 +92,7 @@ vala-order-amortization-stat/
- 历史退费订单冲销税费金额:上述历史均摊金额对应的税费(统一显示为负数,用于冲销) - 历史退费订单冲销税费金额:上述历史均摊金额对应的税费(统一显示为负数,用于冲销)
2. **全额退费bi_refund_order.refund_type = 2**:无需额外计算补充均摊,仅执行上述通用冲销逻辑 2. **全额退费bi_refund_order.refund_type = 2**:无需额外计算补充均摊,仅执行上述通用冲销逻辑
3. **部分退费bi_refund_order.refund_type = 3**:在通用冲销逻辑基础上,额外计算: 3. **部分退费bi_refund_order.refund_type = 3**:在通用冲销逻辑基础上,额外计算:
- 历史部分退费订单补充均摊金额:部分退费后剩余的待均摊税后金额,在本账期内产生的均摊收入 - 历史部分退费订单补充均摊金额:部分退费后的退后订单待均摊税后金额,在本账期内产生的均摊收入
- 历史部分退费订单补充税费金额:上述补充均摊金额对应的税费 - 历史部分退费订单补充税费金额:上述补充均摊金额对应的税费
#### 3.3 账期内收入计算 #### 3.3 账期内收入计算
账期内总收入 = 账期内所有正常订单的日均摊金额总和 + 账期内所有退费冲销金额总和 账期内总收入 = 账期内所有正常订单的日均摊金额总和 + 账期内所有退费冲销金额总和
@ -249,7 +250,7 @@ order_final_amort AS (
THEN 1 ELSE 0 THEN 1 ELSE 0
END AS is_pre_period_full_refund, END AS is_pre_period_full_refund,
-- 判断是否为账期前部分退费(本账期按剩余金额均摊) -- 判断是否为账期前部分退费(本账期按退后订单金额均摊)
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0 CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0
AND opa.latest_refund_date < '${账期起始日}'::date AND opa.latest_refund_date < '${账期起始日}'::date
THEN 1 ELSE 0 THEN 1 ELSE 0
@ -262,17 +263,17 @@ order_final_amort AS (
THEN 1 ELSE 0 THEN 1 ELSE 0
END AS is_current_period_refund, END AS is_current_period_refund,
-- 部分退费后的剩余税后金额 -- 部分退费后的退后订单税后金额
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0 CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0
THEN (opa.pay_amount - opa.total_refund_amount) * (1 - opa.tax_rate) THEN (opa.pay_amount - opa.total_refund_amount) * (1 - opa.tax_rate)
ELSE opa.after_tax_amount ELSE opa.after_tax_amount
END AS remaining_after_tax_amount, END AS refunded_after_tax_amount,
-- 部分退费后的剩余税费 -- 部分退费后的退后订单税费
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0 CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0
THEN (opa.pay_amount - opa.total_refund_amount) * opa.tax_rate THEN (opa.pay_amount - opa.total_refund_amount) * opa.tax_rate
ELSE opa.tax_amount ELSE opa.tax_amount
END AS remaining_tax_amount END AS refunded_tax_amount
FROM order_period_amort opa FROM order_period_amort opa
), ),
@ -299,9 +300,9 @@ summary_calc AS (
ROUND(SUM( ROUND(SUM(
CASE CASE
WHEN is_pre_period_full_refund = 1 THEN 0 -- 账期前全额退费,不统计 WHEN is_pre_period_full_refund = 1 THEN 0 -- 账期前全额退费,不统计
WHEN is_pre_period_partial_refund = 1 THEN -- 账期前部分退费,按剩余金额均摊 WHEN is_pre_period_partial_refund = 1 THEN -- 账期前部分退费,按退后订单金额均摊
CASE WHEN total_cycle_days > 0 AND period_amort_days > 0 CASE WHEN total_cycle_days > 0 AND period_amort_days > 0
THEN remaining_after_tax_amount / total_cycle_days * period_amort_days THEN refunded_after_tax_amount / total_cycle_days * period_amort_days
ELSE 0 ELSE 0
END END
WHEN is_current_period_refund = 0 AND period_amort_days > 0 THEN -- 正常未退费订单 WHEN is_current_period_refund = 0 AND period_amort_days > 0 THEN -- 正常未退费订单
@ -322,7 +323,7 @@ summary_calc AS (
WHEN is_pre_period_full_refund = 1 THEN 0 WHEN is_pre_period_full_refund = 1 THEN 0
WHEN is_pre_period_partial_refund = 1 THEN WHEN is_pre_period_partial_refund = 1 THEN
CASE WHEN total_cycle_days > 0 AND period_amort_days > 0 CASE WHEN total_cycle_days > 0 AND period_amort_days > 0
THEN remaining_tax_amount / total_cycle_days * period_amort_days THEN refunded_tax_amount / total_cycle_days * period_amort_days
ELSE 0 ELSE 0
END END
WHEN is_current_period_refund = 0 AND period_amort_days > 0 THEN WHEN is_current_period_refund = 0 AND period_amort_days > 0 THEN
@ -347,7 +348,7 @@ summary_calc AS (
END END
)::numeric, 2) AS writeoff_tax, )::numeric, 2) AS writeoff_tax,
-- ===== 补充均摊金额(税后):账期内部分退费订单,退费后剩余金额的均摊 ===== -- ===== 补充均摊金额(税后):账期内部分退费订单,退后订单金额的均摊 =====
ROUND(SUM( ROUND(SUM(
CASE WHEN is_current_period_refund = 1 CASE WHEN is_current_period_refund = 1
AND is_full_refund = 0 AND is_full_refund = 0
@ -405,7 +406,7 @@ FROM summary_calc;
3. **试用订单数**账期内新增的订单中截止账期结束日仍处于7天试用期内下单日+7天 > 账期结束日)的订单数量,试用订单未开始均摊,不参与金额计算 3. **试用订单数**账期内新增的订单中截止账期结束日仍处于7天试用期内下单日+7天 > 账期结束日)的订单数量,试用订单未开始均摊,不参与金额计算
4. **冲销前税费**:账期内所有正式订单的含税订单总金额 × 各订单对应税率 的总和 4. **冲销前税费**:账期内所有正式订单的含税订单总金额 × 各订单对应税率 的总和
5. **冲销税费**:本账期内发生退费的所有订单的含税订单总金额 × 各订单对应税率 的总和(正数展示,计算时扣除) 5. **冲销税费**:本账期内发生退费的所有订单的含税订单总金额 × 各订单对应税率 的总和(正数展示,计算时扣除)
6. **补充税费**:本账期内发生部分退费的订单,退费后剩余的含税订单金额 × 各订单对应税率 的总和,其中:部分退费订单剩余含税金额 = 原订单含税金额 - 退费含税金额 6. **补充税费**:本账期内发生部分退费的订单,退后订单含税金额 × 各订单对应税率 的总和,其中:部分退费订单退后含税金额 = 原订单含税金额 - 退费含税金额
7. **冲销后税费**:账期内最终确认的总税费,计算公式:`冲销后税费 = 冲销前税费 - 冲销税费 + 补充税费` 7. **冲销后税费**:账期内最终确认的总税费,计算公式:`冲销后税费 = 冲销前税费 - 冲销税费 + 补充税费`
8. **冲销前均摊金额(税后)**:历史未退费订单 + 账期内正式订单 在本账期内产生的税后均摊收入总和 8. **冲销前均摊金额(税后)**:历史未退费订单 + 账期内正式订单 在本账期内产生的税后均摊收入总和
9. **冲销均摊金额(税后)**:本账期内发生退费的所有订单,需要冲销的历史均摊金额总和(正数展示,计算时扣除) 9. **冲销均摊金额(税后)**:本账期内发生退费的所有订单,需要冲销的历史均摊金额总和(正数展示,计算时扣除)

View File

@ -1,12 +1,12 @@
WITH WITH
-- 步骤0获取所有历史退费记录(无时间范围,用于标记订单是否为退费订单,不受当前账期限制) -- 步骤0获取所有历史退费记录
all_refund_records AS ( all_refund_records AS (
SELECT SELECT
out_trade_no AS order_no, out_trade_no AS order_no,
SUM(refund_amount_int) / 100 AS total_refund_amount, -- 累计退费总金额(支持多笔部分退费叠加) SUM(refund_amount_int) / 100 AS total_refund_amount,
MAX(CASE WHEN refund_type = 2 THEN 1 ELSE 0 END) AS is_full_refund, -- 是否全额退费只要有一笔全额退费即标记为1 MAX(CASE WHEN refund_type = 2 THEN 1 ELSE 0 END) AS is_full_refund,
MAX(refund_type) AS refund_type, MAX(refund_type) AS refund_type,
MAX(DATE(updated_at)) AS latest_refund_date -- 最后一次退费完成时间 MAX(DATE(updated_at)) AS latest_refund_date
FROM bi_refund_order FROM bi_refund_order
WHERE status = 3 WHERE status = 3
GROUP BY out_trade_no GROUP BY out_trade_no
@ -15,34 +15,33 @@ all_refund_records AS (
order_base AS ( order_base AS (
SELECT SELECT
o.id AS order_id, o.id AS order_id,
o.out_trade_no AS order_no, -- 修正bi_vala_order无order_no字段使用out_trade_no作为订单号 o.out_trade_no AS order_no,
o.trade_no, -- 新增关联退费订单需要trade_no字段 o.trade_no,
DATE(o.created_at) AS order_date,
o.pay_amount_int / 100 AS pay_amount, o.pay_amount_int / 100 AS pay_amount,
-- 计算税率、税费、税后金额
CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END AS tax_rate, CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END AS tax_rate,
(o.pay_amount_int / 100) * CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END AS tax_amount, (o.pay_amount_int / 100.0) / (1 + CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END) * CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END AS tax_amount,
(o.pay_amount_int / 100) * (1 - CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END) AS after_tax_amount, (o.pay_amount_int / 100.0) / (1 + CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END) AS after_tax_amount,
DATE(o.created_at) + INTERVAL '7 days' AS amortization_start_date, DATE(o.created_at) + INTERVAL '7 days' AS amortization_start_date,
o.order_status, -- 修正字段名是order_status不是status o.order_status,
a.id AS account_id, a.id AS account_id,
o.key_from, o.key_from,
o.sale_channel, o.sale_channel,
-- 新增:订单退费标记字段(所有历史退费均可识别,不受当前账期限制) CASE WHEN ar.order_no IS NOT NULL THEN 1 ELSE 0 END AS has_refund,
CASE WHEN ar.order_no IS NOT NULL THEN 1 ELSE 0 END AS has_refund, -- 是否有退费记录 COALESCE(ar.total_refund_amount, 0) AS total_refund_amount,
COALESCE(ar.total_refund_amount, 0) AS total_refund_amount, -- 累计退费金额 COALESCE(ar.is_full_refund, 0) AS is_full_refund,
COALESCE(ar.is_full_refund, 0) AS is_full_refund, -- 是否全额退费
ar.refund_type, ar.refund_type,
ar.latest_refund_date -- 退费完成日期(解决历史退费订单退费日期为空的问题) ar.latest_refund_date
FROM bi_vala_order o FROM bi_vala_order o
JOIN bi_vala_app_account a ON o.account_id = a.id JOIN bi_vala_app_account a ON o.account_id = a.id
LEFT JOIN all_refund_records ar ON o.out_trade_no = ar.order_no -- 关联全量退费记录,不限制时间 LEFT JOIN all_refund_records ar ON o.out_trade_no = ar.order_no
WHERE WHERE
o.created_at >= '2025-09-01' o.created_at >= '2025-09-01'
AND o.order_status IN (3,4) -- 修正字段名是order_status不是status AND o.order_status IN (3,4)
AND o.pay_amount_int >= 1000 AND o.pay_amount_int >= 1000
AND a.status = 1 AND a.status = 1
), ),
-- 步骤2计算每个订单的总均摊周期 -- 步骤2计算每个订单的当前均摊周期(退费后)和原始均摊周期(退费前)
order_cycle AS ( order_cycle AS (
SELECT SELECT
out_trade_no AS order_no, out_trade_no AS order_no,
@ -51,166 +50,253 @@ order_cycle AS (
WHERE status != -1 WHERE status != -1
GROUP BY out_trade_no GROUP BY out_trade_no
), ),
-- 步骤3获取账期内的退费记录仅用于计算当前账期的冲销金额不影响订单退费状态标记 order_cycle_original AS (
refund_records AS (
SELECT SELECT
r.out_trade_no AS order_no, out_trade_no AS order_no,
r.refund_amount_int / 100 AS refund_amount, -- 修正使用分为单位的refund_amount_int避免字符串转换问题除以100得到元 COUNT(DISTINCT id) * 90 AS original_cycle_days
r.refund_type, FROM bi_vala_seasonal_ticket
DATE(r.updated_at) AS refund_date -- 退费日期使用updated_atstatus=3时即为退费完成时间 GROUP BY out_trade_no
FROM bi_refund_order r ),
JOIN order_base o ON r.out_trade_no = o.order_no OR r.trade_no = o.trade_no -- 修正支持out_trade_no/trade_no双字段匹配退费订单 -- 步骤3合并订单基础信息与均摊周期
WHERE
r.status = 3
AND r.updated_at BETWEEN '{period_start}' AND '{period_end}'
)
,
-- 步骤4合并订单基础信息与均摊周期
order_with_cycle AS ( order_with_cycle AS (
SELECT SELECT
ob.*, ob.*,
COALESCE(oc.total_cycle_days, 0) AS total_cycle_days, COALESCE(oc.total_cycle_days, 0) AS total_cycle_days,
-- 均摊结束日 = 转正日 + 总周期天数 - 1 COALESCE(oco.original_cycle_days, 0) AS original_cycle_days,
ob.amortization_start_date + COALESCE(oc.total_cycle_days, 0) * INTERVAL '1 day' - INTERVAL '1 day' AS amortization_end_date, ob.amortization_start_date + COALESCE(oc.total_cycle_days, 0) * INTERVAL '1 day' - INTERVAL '1 day' AS amortization_end_date,
-- 日均摊金额(税后) -- 原始均摊结束日(退费前)
CASE WHEN COALESCE(oc.total_cycle_days, 0) > 0 ob.amortization_start_date + COALESCE(oco.original_cycle_days, 0) * INTERVAL '1 day' - INTERVAL '1 day' AS original_amortization_end_date,
-- 原始日均摊金额(基于原订单税后金额和原始周期)
CASE WHEN COALESCE(oco.original_cycle_days, 0) > 0
THEN ob.after_tax_amount / oco.original_cycle_days
ELSE 0
END AS original_daily_amort_amount,
-- 原始日税费均摊
CASE WHEN COALESCE(oco.original_cycle_days, 0) > 0
THEN ob.tax_amount / oco.original_cycle_days
ELSE 0
END AS original_daily_tax_amount,
-- 退后日均摊金额(基于退后订单税后金额和退后周期)
CASE WHEN COALESCE(oc.total_cycle_days, 0) > 0 AND ob.has_refund = 1 AND ob.is_full_refund = 0
THEN (ob.pay_amount - ob.total_refund_amount) / (1 + ob.tax_rate) / oc.total_cycle_days
WHEN COALESCE(oc.total_cycle_days, 0) > 0
THEN ob.after_tax_amount / oc.total_cycle_days THEN ob.after_tax_amount / oc.total_cycle_days
ELSE 0 ELSE 0
END AS daily_amort_amount, END AS daily_amort_amount,
-- 日税费均摊 -- 退后日税费均摊
CASE WHEN COALESCE(oc.total_cycle_days, 0) > 0 CASE WHEN COALESCE(oc.total_cycle_days, 0) > 0 AND ob.has_refund = 1 AND ob.is_full_refund = 0
THEN (ob.pay_amount - ob.total_refund_amount) / (1 + ob.tax_rate) * ob.tax_rate / oc.total_cycle_days
WHEN COALESCE(oc.total_cycle_days, 0) > 0
THEN ob.tax_amount / oc.total_cycle_days THEN ob.tax_amount / oc.total_cycle_days
ELSE 0 ELSE 0
END AS daily_tax_amount END AS daily_tax_amount
FROM order_base ob FROM order_base ob
LEFT JOIN order_cycle oc ON ob.order_no = oc.order_no LEFT JOIN order_cycle oc ON ob.order_no = oc.order_no
LEFT JOIN order_cycle_original oco ON ob.order_no = oco.order_no
), ),
-- 步骤4判断订单场景分类
-- 步骤5判断订单在账期内的状态分类并计算各类均摊金额 order_classified AS (
order_amortization AS (
SELECT SELECT
owc.*, owc.*,
-- 是否为账期内新增订单 -- 均摊有效起始日
CASE WHEN DATE(owc.amortization_start_date) <= '{period_end}'
AND owc.amortization_start_date >= '{period_start}'::date - INTERVAL '6 days'
THEN 1 ELSE 0 END AS is_new_in_period,
-- 账期内新增且已转正
CASE WHEN DATE(owc.amortization_start_date) >= '{period_start}'
AND DATE(owc.amortization_start_date) <= '{period_end}'
THEN 1
WHEN owc.amortization_start_date < '{period_start}'
THEN 1
ELSE 0
END AS is_formal,
-- ===== 正常均摊金额计算(未退费 或 账期前部分退费的订单)=====
-- 均摊有效起始日(取转正日和账期起始日的较大值)
GREATEST(owc.amortization_start_date, '{period_start}'::date) AS eff_start, GREATEST(owc.amortization_start_date, '{period_start}'::date) AS eff_start,
-- 均摊有效结束日(取均摊结束日和账期结束日的较小值) -- 均摊有效结束日
LEAST(owc.amortization_end_date, '{period_end}'::date) AS eff_end LEAST(owc.amortization_end_date, '{period_end}'::date) AS eff_end,
FROM order_with_cycle owc -- 判断是否为账期前全额退费场景F排除
WHERE owc.total_cycle_days > 0 -- 排除无均摊周期的异常订单 CASE WHEN owc.has_refund = 1 AND owc.is_full_refund = 1
), AND owc.latest_refund_date < '{period_start}'::date
-- 步骤6计算每个订单在账期内的均摊天数和金额
order_period_amort AS (
SELECT
oa.*,
-- 账期内有效均摊天数
CASE WHEN oa.eff_end >= oa.eff_start
THEN EXTRACT(DAY FROM (oa.eff_end - oa.eff_start))::int + 1
ELSE 0
END AS period_amort_days,
-- 该订单从转正日到账期结束日的总已均摊天数(用于计算历史累计)
CASE WHEN '{period_end}'::date >= oa.amortization_start_date
THEN EXTRACT(DAY FROM (LEAST('{period_end}'::date, oa.amortization_end_date) - oa.amortization_start_date))::int + 1
ELSE 0
END AS total_amorted_days_to_period_end,
-- 该订单从转正日到账期起始日前一天的历史已均摊天数
CASE WHEN '{period_start}'::date > oa.amortization_start_date
THEN EXTRACT(DAY FROM (LEAST('{period_start}'::date - 1, oa.amortization_end_date) - oa.amortization_start_date))::int + 1
ELSE 0
END AS historical_amorted_days
FROM order_amortization oa
),
-- 步骤7计算最终均摊金额含补差逻辑
order_final_amort AS (
SELECT
opa.*,
-- === 正常订单(未退费 或 账期前已处理的退费订单)在账期内的均摊 ===
-- 判断是否为账期前全额退费(本账期完全不统计)
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 1
AND opa.latest_refund_date < '{period_start}'::date
THEN 1 ELSE 0 THEN 1 ELSE 0
END AS is_pre_period_full_refund, END AS is_pre_period_full_refund,
-- 判断是否为账期前部分退费(本账期按剩余金额均摊 -- 判断是否为账期前部分退费场景C
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0 CASE WHEN owc.has_refund = 1 AND owc.is_full_refund = 0
AND opa.latest_refund_date < '{period_start}'::date AND owc.latest_refund_date < '{period_start}'::date
THEN 1 ELSE 0 THEN 1 ELSE 0
END AS is_pre_period_partial_refund, END AS is_pre_period_partial_refund,
-- 判断是否为账期内退费 -- 判断是否为账期内退费
CASE WHEN opa.has_refund = 1 CASE WHEN owc.has_refund = 1
AND opa.latest_refund_date >= '{period_start}'::date AND owc.latest_refund_date >= '{period_start}'::date
AND opa.latest_refund_date <= '{period_end}'::date AND owc.latest_refund_date <= '{period_end}'::date
THEN 1 ELSE 0 THEN 1 ELSE 0
END AS is_current_period_refund, END AS is_current_period_refund,
-- 部分退费后的剩余税后金额 -- 判断是否为账期内下单(下单日在账期内)
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0 CASE WHEN owc.order_date >= '{period_start}'::date
THEN (opa.pay_amount - opa.total_refund_amount) * (1 - opa.tax_rate) AND owc.order_date <= '{period_end}'::date
ELSE opa.after_tax_amount THEN 1 ELSE 0
END AS remaining_after_tax_amount, END AS is_ordered_in_period,
-- 部分退费后的剩余税费 -- 退后订单税后金额
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0 CASE WHEN owc.has_refund = 1 AND owc.is_full_refund = 0
THEN (opa.pay_amount - opa.total_refund_amount) * opa.tax_rate THEN (owc.pay_amount - owc.total_refund_amount) / (1 + owc.tax_rate)
ELSE opa.tax_amount ELSE owc.after_tax_amount
END AS remaining_tax_amount END AS refunded_after_tax_amount,
FROM order_period_amort opa -- 退后订单税费
CASE WHEN owc.has_refund = 1 AND owc.is_full_refund = 0
THEN (owc.pay_amount - owc.total_refund_amount) / (1 + owc.tax_rate) * owc.tax_rate
ELSE owc.tax_amount
END AS refunded_tax_amount
FROM order_with_cycle owc
WHERE owc.total_cycle_days > 0 OR (owc.has_refund = 1 AND owc.is_full_refund = 1 AND owc.original_cycle_days > 0)
),
-- 步骤5计算均摊天数
order_with_days AS (
SELECT
oc2.*,
-- 账期内有效均摊天数(基于退后周期)
CASE WHEN oc2.eff_end >= oc2.eff_start AND oc2.total_cycle_days > 0
THEN EXTRACT(DAY FROM (oc2.eff_end - oc2.eff_start))::int + 1
ELSE 0
END AS period_amort_days,
-- 从转正日到账期结束日的总已均摊天数(基于退后周期)
CASE WHEN '{period_end}'::date >= oc2.amortization_start_date AND oc2.total_cycle_days > 0
THEN EXTRACT(DAY FROM (LEAST('{period_end}'::date, oc2.amortization_end_date) - oc2.amortization_start_date))::int + 1
ELSE 0
END AS total_amorted_days_to_period_end,
-- 从转正日到账期起始日前一天的历史已均摊天数(基于原始周期,用于冲销计算)
CASE WHEN '{period_start}'::date > oc2.amortization_start_date AND oc2.original_cycle_days > 0
THEN EXTRACT(DAY FROM (LEAST('{period_start}'::date - 1, oc2.original_amortization_end_date) - oc2.amortization_start_date))::int + 1
ELSE 0
END AS historical_amorted_days,
-- 从转正日到账期结束日的天数(基于退后周期,用于退后订单的重新均摊)
CASE WHEN '{period_end}'::date >= oc2.amortization_start_date AND oc2.total_cycle_days > 0
THEN EXTRACT(DAY FROM (LEAST('{period_end}'::date, oc2.amortization_end_date) - oc2.amortization_start_date))::int + 1
ELSE 0
END AS refunded_amort_days_to_period_end
FROM order_classified oc2
) )
-- 最终输出
SELECT SELECT
order_no AS "订单号", order_no AS "订单号",
order_date AS "下单日期",
latest_refund_date AS "退费日期",
CASE
WHEN is_pre_period_full_refund = 1 THEN '账期前全额退费'
WHEN is_pre_period_partial_refund = 1 THEN '账期前部分退费'
WHEN is_current_period_refund = 1 AND is_full_refund = 1 AND is_ordered_in_period = 1 THEN '账期内下单全额退费'
WHEN is_current_period_refund = 1 AND is_full_refund = 1 AND is_ordered_in_period = 0 THEN '历史下单账期内全额退费'
WHEN is_current_period_refund = 1 AND is_full_refund = 0 AND is_ordered_in_period = 1 THEN '账期内下单部分退费'
WHEN is_current_period_refund = 1 AND is_full_refund = 0 AND is_ordered_in_period = 0 THEN '历史下单账期内部分退费'
WHEN DATE(amortization_start_date) > '{period_end}'::date THEN '试用期中'
ELSE '正常订单'
END AS "订单分类",
ROUND(pay_amount::numeric, 2) AS "订单金额", ROUND(pay_amount::numeric, 2) AS "订单金额",
ROUND(tax_rate::numeric, 2) AS "税率", ROUND(tax_rate::numeric, 4) AS "税率",
ROUND(tax_amount::numeric, 2) AS "税额", ROUND(tax_amount::numeric, 2) AS "原订单税额",
ROUND(after_tax_amount::numeric, 2) AS "税后金额", ROUND(after_tax_amount::numeric, 2) AS "原订单税后金额",
total_cycle_days AS "总均摊周期", original_cycle_days AS "原始均摊周期",
period_amort_days AS "账期内均摊天数", total_cycle_days AS "退后均摊周期",
ROUND((historical_amorted_days * daily_amort_amount)::numeric, 2) AS "历史均摊金额",
-- 历史均摊金额(基于原始日均摊)
ROUND((historical_amorted_days * original_daily_amort_amount)::numeric, 2) AS "历史均摊金额",
-- 冲销历史均摊场景B/E历史下单+账期内退费)
ROUND(
CASE WHEN is_current_period_refund = 1 AND is_ordered_in_period = 0 AND historical_amorted_days > 0
THEN -(historical_amorted_days * original_daily_amort_amount)
ELSE 0
END::numeric, 2
) AS "冲销历史均摊",
-- 冲销原税款场景B/E历史下单+账期内退费)
ROUND(
CASE WHEN is_current_period_refund = 1 AND is_ordered_in_period = 0
THEN -tax_amount
ELSE 0
END::numeric, 2
) AS "冲销原税款",
-- 冲销未确认收入场景B/E历史下单+账期内退费)
ROUND(
CASE WHEN is_current_period_refund = 1 AND is_ordered_in_period = 0
THEN -(after_tax_amount - historical_amorted_days * original_daily_amort_amount)
ELSE 0
END::numeric, 2
) AS "冲销未确认收入",
-- 账期均摊金额
ROUND( ROUND(
CASE CASE
-- 场景F账期前全额退费不统计
WHEN is_pre_period_full_refund = 1 THEN 0 WHEN is_pre_period_full_refund = 1 THEN 0
WHEN is_pre_period_partial_refund = 1 THEN -- 场景D账期内下单+全额退费,无均摊
WHEN is_current_period_refund = 1 AND is_full_refund = 1 AND is_ordered_in_period = 1 THEN 0
-- 场景E历史下单+账期内全额退费,无退后均摊
WHEN is_current_period_refund = 1 AND is_full_refund = 1 AND is_ordered_in_period = 0 THEN 0
-- 场景A账期内下单+部分退费,按退后订单金额/退后周期从转正日均摊
WHEN is_current_period_refund = 1 AND is_full_refund = 0 AND is_ordered_in_period = 1 THEN
CASE WHEN total_cycle_days > 0 AND period_amort_days > 0 CASE WHEN total_cycle_days > 0 AND period_amort_days > 0
THEN remaining_after_tax_amount / total_cycle_days * period_amort_days THEN daily_amort_amount * period_amort_days
ELSE 0 ELSE 0
END END
WHEN is_current_period_refund = 0 AND period_amort_days > 0 THEN -- 场景B历史下单+账期内部分退费,按退后订单金额/退后周期从转正日重新均摊
WHEN is_current_period_refund = 1 AND is_full_refund = 0 AND is_ordered_in_period = 0 THEN
CASE WHEN total_cycle_days > 0 AND refunded_amort_days_to_period_end > 0
THEN daily_amort_amount * refunded_amort_days_to_period_end
ELSE 0
END
-- 场景C账期前部分退费按退后订单金额/退后周期正常均摊
WHEN is_pre_period_partial_refund = 1 THEN
CASE WHEN total_cycle_days > 0 AND period_amort_days > 0
THEN daily_amort_amount * period_amort_days
ELSE 0
END
-- 正常订单
WHEN period_amort_days > 0 THEN
CASE CASE
WHEN eff_end = amortization_end_date WHEN eff_end = amortization_end_date
THEN after_tax_amount - daily_amort_amount * (total_cycle_days - 1) + daily_amort_amount * (period_amort_days - 1) THEN after_tax_amount - original_daily_amort_amount * (original_cycle_days - 1) + original_daily_amort_amount * (period_amort_days - 1)
ELSE daily_amort_amount * period_amort_days ELSE original_daily_amort_amount * period_amort_days
END END
ELSE 0 ELSE 0
END::numeric, 2 END::numeric, 2
) AS "账期均摊金额", ) AS "账期均摊金额",
-- 退后订单税额(仅账期内下单且已转正的非全额退费订单计税)
ROUND( ROUND(
(CASE CASE
WHEN is_pre_period_partial_refund = 1 OR (is_current_period_refund = 1 AND is_full_refund = 0) -- 账期内下单 + 已转正 + 部分退费 → 退后订单税额
THEN remaining_after_tax_amount WHEN is_ordered_in_period = 1
ELSE after_tax_amount AND DATE(amortization_start_date) <= '{period_end}'::date
END - (historical_amorted_days * daily_amort_amount))::numeric, 2 AND is_current_period_refund = 1 AND is_full_refund = 0
THEN refunded_tax_amount
-- 账期内下单 + 已转正 + 未全额退费(含未退费)→ 原订单税额
WHEN is_ordered_in_period = 1
AND DATE(amortization_start_date) <= '{period_end}'::date
AND (has_refund = 0 OR (is_current_period_refund = 0 AND is_full_refund = 0))
THEN tax_amount
ELSE 0
END::numeric, 2
) AS "账期税额",
-- 未确认收入
ROUND(
CASE
WHEN is_pre_period_full_refund = 1 THEN 0
WHEN is_current_period_refund = 1 AND is_full_refund = 1 THEN 0
WHEN is_current_period_refund = 1 AND is_full_refund = 0 THEN
refunded_after_tax_amount - daily_amort_amount * refunded_amort_days_to_period_end
WHEN is_pre_period_partial_refund = 1 THEN
refunded_after_tax_amount - daily_amort_amount * total_amorted_days_to_period_end
ELSE
after_tax_amount - original_daily_amort_amount * total_amorted_days_to_period_end
END::numeric, 2
) AS "未确认收入", ) AS "未确认收入",
(total_cycle_days - total_amorted_days_to_period_end) AS "剩余周期"
FROM order_final_amort -- 剩余周期
CASE
WHEN is_current_period_refund = 1 AND is_full_refund = 1 THEN 0
ELSE (total_cycle_days - total_amorted_days_to_period_end)
END AS "剩余周期"
FROM order_with_days
WHERE is_pre_period_full_refund = 0; WHERE is_pre_period_full_refund = 0;

View File

@ -1,12 +1,12 @@
WITH WITH
-- 步骤0获取所有历史退费记录(无时间范围,用于标记订单是否为退费订单,不受当前账期限制) -- 步骤0获取所有历史退费记录
all_refund_records AS ( all_refund_records AS (
SELECT SELECT
out_trade_no AS order_no, out_trade_no AS order_no,
SUM(refund_amount_int) / 100 AS total_refund_amount, -- 累计退费总金额(支持多笔部分退费叠加) SUM(refund_amount_int) / 100 AS total_refund_amount,
MAX(CASE WHEN refund_type = 2 THEN 1 ELSE 0 END) AS is_full_refund, -- 是否全额退费只要有一笔全额退费即标记为1 MAX(CASE WHEN refund_type = 2 THEN 1 ELSE 0 END) AS is_full_refund,
MAX(refund_type) AS refund_type, MAX(refund_type) AS refund_type,
MAX(DATE(updated_at)) AS latest_refund_date -- 最后一次退费完成时间 MAX(DATE(updated_at)) AS latest_refund_date
FROM bi_refund_order FROM bi_refund_order
WHERE status = 3 WHERE status = 3
GROUP BY out_trade_no GROUP BY out_trade_no
@ -15,274 +15,202 @@ all_refund_records AS (
order_base AS ( order_base AS (
SELECT SELECT
o.id AS order_id, o.id AS order_id,
o.out_trade_no AS order_no, -- 修正bi_vala_order无order_no字段使用out_trade_no作为订单号 o.out_trade_no AS order_no,
o.trade_no, -- 新增关联退费订单需要trade_no字段 o.trade_no,
DATE(o.created_at) AS order_date,
o.pay_amount_int / 100 AS pay_amount, o.pay_amount_int / 100 AS pay_amount,
-- 计算税率、税费、税后金额
CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END AS tax_rate, CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END AS tax_rate,
(o.pay_amount_int / 100) * CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END AS tax_amount, (o.pay_amount_int / 100.0) / (1 + CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END) * CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END AS tax_amount,
(o.pay_amount_int / 100) * (1 - CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END) AS after_tax_amount, (o.pay_amount_int / 100.0) / (1 + CASE WHEN DATE(o.created_at) < '2026-05-01' THEN 0.01 ELSE 0.06 END) AS after_tax_amount,
DATE(o.created_at) + INTERVAL '7 days' AS amortization_start_date, DATE(o.created_at) + INTERVAL '7 days' AS amortization_start_date,
o.order_status, -- 修正字段名是order_status不是status o.order_status,
a.id AS account_id, a.id AS account_id,
o.key_from, o.key_from,
o.sale_channel, o.sale_channel,
-- 新增:订单退费标记字段(所有历史退费均可识别,不受当前账期限制) CASE WHEN ar.order_no IS NOT NULL THEN 1 ELSE 0 END AS has_refund,
CASE WHEN ar.order_no IS NOT NULL THEN 1 ELSE 0 END AS has_refund, -- 是否有退费记录 COALESCE(ar.total_refund_amount, 0) AS total_refund_amount,
COALESCE(ar.total_refund_amount, 0) AS total_refund_amount, -- 累计退费金额 COALESCE(ar.is_full_refund, 0) AS is_full_refund,
COALESCE(ar.is_full_refund, 0) AS is_full_refund, -- 是否全额退费
ar.refund_type, ar.refund_type,
ar.latest_refund_date -- 退费完成日期(解决历史退费订单退费日期为空的问题) ar.latest_refund_date
FROM bi_vala_order o FROM bi_vala_order o
JOIN bi_vala_app_account a ON o.account_id = a.id JOIN bi_vala_app_account a ON o.account_id = a.id
LEFT JOIN all_refund_records ar ON o.out_trade_no = ar.order_no -- 关联全量退费记录,不限制时间 LEFT JOIN all_refund_records ar ON o.out_trade_no = ar.order_no
WHERE WHERE
o.created_at >= '2025-09-01' o.created_at >= '2025-09-01'
AND o.order_status IN (3,4) -- 修正字段名是order_status不是status AND o.order_status IN (3,4)
AND o.pay_amount_int >= 1000 AND o.pay_amount_int >= 1000
AND a.status = 1 AND a.status = 1
), ),
-- 步骤2计算每个订单的总均摊周期 -- 步骤2计算均摊周期
order_cycle AS ( order_cycle AS (
SELECT SELECT out_trade_no AS order_no, COUNT(DISTINCT id) * 90 AS total_cycle_days
out_trade_no AS order_no, FROM bi_vala_seasonal_ticket WHERE status != -1 GROUP BY out_trade_no
COUNT(DISTINCT id) * 90 AS total_cycle_days
FROM bi_vala_seasonal_ticket
WHERE status != -1
GROUP BY out_trade_no
), ),
-- 步骤3获取账期内的退费记录仅用于计算当前账期的冲销金额不影响订单退费状态标记 order_cycle_original AS (
refund_records AS ( SELECT out_trade_no AS order_no, COUNT(DISTINCT id) * 90 AS original_cycle_days
SELECT FROM bi_vala_seasonal_ticket GROUP BY out_trade_no
r.out_trade_no AS order_no, ),
r.refund_amount_int / 100 AS refund_amount, -- 修正使用分为单位的refund_amount_int避免字符串转换问题除以100得到元 -- 步骤3合并
r.refund_type,
DATE(r.updated_at) AS refund_date -- 退费日期使用updated_atstatus=3时即为退费完成时间
FROM bi_refund_order r
JOIN order_base o ON r.out_trade_no = o.order_no OR r.trade_no = o.trade_no -- 修正支持out_trade_no/trade_no双字段匹配退费订单
WHERE
r.status = 3
AND r.updated_at BETWEEN '{period_start}' AND '{period_end}'
)
,
-- 步骤4合并订单基础信息与均摊周期
order_with_cycle AS ( order_with_cycle AS (
SELECT SELECT
ob.*, ob.*,
COALESCE(oc.total_cycle_days, 0) AS total_cycle_days, COALESCE(oc.total_cycle_days, 0) AS total_cycle_days,
-- 均摊结束日 = 转正日 + 总周期天数 - 1 COALESCE(oco.original_cycle_days, 0) AS original_cycle_days,
ob.amortization_start_date + COALESCE(oc.total_cycle_days, 0) * INTERVAL '1 day' - INTERVAL '1 day' AS amortization_end_date, ob.amortization_start_date + COALESCE(oc.total_cycle_days, 0) * INTERVAL '1 day' - INTERVAL '1 day' AS amortization_end_date,
-- 日均摊金额(税后) ob.amortization_start_date + COALESCE(oco.original_cycle_days, 0) * INTERVAL '1 day' - INTERVAL '1 day' AS original_amortization_end_date,
CASE WHEN COALESCE(oc.total_cycle_days, 0) > 0 CASE WHEN COALESCE(oco.original_cycle_days, 0) > 0
THEN ob.after_tax_amount / oc.total_cycle_days THEN ob.after_tax_amount / oco.original_cycle_days ELSE 0
ELSE 0 END AS original_daily_amort_amount,
CASE WHEN COALESCE(oco.original_cycle_days, 0) > 0
THEN ob.tax_amount / oco.original_cycle_days ELSE 0
END AS original_daily_tax_amount,
CASE WHEN COALESCE(oc.total_cycle_days, 0) > 0 AND ob.has_refund = 1 AND ob.is_full_refund = 0
THEN (ob.pay_amount - ob.total_refund_amount) / (1 + ob.tax_rate) / oc.total_cycle_days
WHEN COALESCE(oc.total_cycle_days, 0) > 0
THEN ob.after_tax_amount / oc.total_cycle_days ELSE 0
END AS daily_amort_amount, END AS daily_amort_amount,
-- 日税费均摊 CASE WHEN COALESCE(oc.total_cycle_days, 0) > 0 AND ob.has_refund = 1 AND ob.is_full_refund = 0
CASE WHEN COALESCE(oc.total_cycle_days, 0) > 0 THEN (ob.pay_amount - ob.total_refund_amount) / (1 + ob.tax_rate) * ob.tax_rate / oc.total_cycle_days
THEN ob.tax_amount / oc.total_cycle_days WHEN COALESCE(oc.total_cycle_days, 0) > 0
ELSE 0 THEN ob.tax_amount / oc.total_cycle_days ELSE 0
END AS daily_tax_amount END AS daily_tax_amount
FROM order_base ob FROM order_base ob
LEFT JOIN order_cycle oc ON ob.order_no = oc.order_no LEFT JOIN order_cycle oc ON ob.order_no = oc.order_no
LEFT JOIN order_cycle_original oco ON ob.order_no = oco.order_no
), ),
-- 步骤4分类
-- 步骤5判断订单在账期内的状态分类并计算各类均摊金额 order_classified AS (
order_amortization AS (
SELECT SELECT
owc.*, owc.*,
-- 是否为账期内新增订单
CASE WHEN DATE(owc.amortization_start_date) <= '{period_end}'
AND owc.amortization_start_date >= '{period_start}'::date - INTERVAL '6 days'
THEN 1 ELSE 0 END AS is_new_in_period,
-- 账期内新增且已转正
CASE WHEN DATE(owc.amortization_start_date) >= '{period_start}'
AND DATE(owc.amortization_start_date) <= '{period_end}'
THEN 1
WHEN owc.amortization_start_date < '{period_start}'
THEN 1
ELSE 0
END AS is_formal,
-- ===== 正常均摊金额计算(未退费 或 账期前部分退费的订单)=====
-- 均摊有效起始日(取转正日和账期起始日的较大值)
GREATEST(owc.amortization_start_date, '{period_start}'::date) AS eff_start, GREATEST(owc.amortization_start_date, '{period_start}'::date) AS eff_start,
-- 均摊有效结束日(取均摊结束日和账期结束日的较小值) LEAST(owc.amortization_end_date, '{period_end}'::date) AS eff_end,
LEAST(owc.amortization_end_date, '{period_end}'::date) AS eff_end CASE WHEN owc.has_refund = 1 AND owc.is_full_refund = 1 AND owc.latest_refund_date < '{period_start}'::date
THEN 1 ELSE 0 END AS is_pre_period_full_refund,
CASE WHEN owc.has_refund = 1 AND owc.is_full_refund = 0 AND owc.latest_refund_date < '{period_start}'::date
THEN 1 ELSE 0 END AS is_pre_period_partial_refund,
CASE WHEN owc.has_refund = 1
AND owc.latest_refund_date >= '{period_start}'::date AND owc.latest_refund_date <= '{period_end}'::date
THEN 1 ELSE 0 END AS is_current_period_refund,
CASE WHEN owc.order_date >= '{period_start}'::date AND owc.order_date <= '{period_end}'::date
THEN 1 ELSE 0 END AS is_ordered_in_period,
CASE WHEN owc.has_refund = 1 AND owc.is_full_refund = 0
THEN (owc.pay_amount - owc.total_refund_amount) / (1 + owc.tax_rate) ELSE owc.after_tax_amount
END AS refunded_after_tax_amount,
CASE WHEN owc.has_refund = 1 AND owc.is_full_refund = 0
THEN (owc.pay_amount - owc.total_refund_amount) / (1 + owc.tax_rate) * owc.tax_rate ELSE owc.tax_amount
END AS refunded_tax_amount
FROM order_with_cycle owc FROM order_with_cycle owc
WHERE owc.total_cycle_days > 0 -- 排除无均摊周期的异常订单 WHERE owc.total_cycle_days > 0 OR (owc.has_refund = 1 AND owc.is_full_refund = 1 AND owc.original_cycle_days > 0)
), ),
-- 步骤5计算天数
-- 步骤6计算每个订单在账期内的均摊天数和金额 order_with_days AS (
order_period_amort AS (
SELECT SELECT
oa.*, oc2.*,
-- 账期内有效均摊天数 CASE WHEN oc2.eff_end >= oc2.eff_start AND oc2.total_cycle_days > 0
CASE WHEN oa.eff_end >= oa.eff_start THEN EXTRACT(DAY FROM (oc2.eff_end - oc2.eff_start))::int + 1 ELSE 0
THEN EXTRACT(DAY FROM (oa.eff_end - oa.eff_start))::int + 1
ELSE 0
END AS period_amort_days, END AS period_amort_days,
CASE WHEN '{period_end}'::date >= oc2.amortization_start_date AND oc2.total_cycle_days > 0
-- 该订单从转正日到账期结束日的总已均摊天数(用于计算历史累计) THEN EXTRACT(DAY FROM (LEAST('{period_end}'::date, oc2.amortization_end_date) - oc2.amortization_start_date))::int + 1 ELSE 0
CASE WHEN '{period_end}'::date >= oa.amortization_start_date
THEN EXTRACT(DAY FROM (LEAST('{period_end}'::date, oa.amortization_end_date) - oa.amortization_start_date))::int + 1
ELSE 0
END AS total_amorted_days_to_period_end, END AS total_amorted_days_to_period_end,
CASE WHEN '{period_start}'::date > oc2.amortization_start_date AND oc2.original_cycle_days > 0
-- 该订单从转正日到账期起始日前一天的历史已均摊天数 THEN EXTRACT(DAY FROM (LEAST('{period_start}'::date - 1, oc2.original_amortization_end_date) - oc2.amortization_start_date))::int + 1 ELSE 0
CASE WHEN '{period_start}'::date > oa.amortization_start_date END AS historical_amorted_days,
THEN EXTRACT(DAY FROM (LEAST('{period_start}'::date - 1, oa.amortization_end_date) - oa.amortization_start_date))::int + 1 CASE WHEN '{period_end}'::date >= oc2.amortization_start_date AND oc2.total_cycle_days > 0
ELSE 0 THEN EXTRACT(DAY FROM (LEAST('{period_end}'::date, oc2.amortization_end_date) - oc2.amortization_start_date))::int + 1 ELSE 0
END AS historical_amorted_days END AS refunded_amort_days_to_period_end
FROM order_classified oc2
FROM order_amortization oa
), ),
-- 步骤6汇总
-- 步骤7计算最终均摊金额含补差逻辑
order_final_amort AS (
SELECT
opa.*,
-- === 正常订单(未退费 或 账期前已处理的退费订单)在账期内的均摊 ===
-- 判断是否为账期前全额退费(本账期完全不统计)
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 1
AND opa.latest_refund_date < '{period_start}'::date
THEN 1 ELSE 0
END AS is_pre_period_full_refund,
-- 判断是否为账期前部分退费(本账期按剩余金额均摊)
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0
AND opa.latest_refund_date < '{period_start}'::date
THEN 1 ELSE 0
END AS is_pre_period_partial_refund,
-- 判断是否为账期内退费
CASE WHEN opa.has_refund = 1
AND opa.latest_refund_date >= '{period_start}'::date
AND opa.latest_refund_date <= '{period_end}'::date
THEN 1 ELSE 0
END AS is_current_period_refund,
-- 部分退费后的剩余税后金额
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0
THEN (opa.pay_amount - opa.total_refund_amount) * (1 - opa.tax_rate)
ELSE opa.after_tax_amount
END AS remaining_after_tax_amount,
-- 部分退费后的剩余税费
CASE WHEN opa.has_refund = 1 AND opa.is_full_refund = 0
THEN (opa.pay_amount - opa.total_refund_amount) * opa.tax_rate
ELSE opa.tax_amount
END AS remaining_tax_amount
FROM order_period_amort opa
),
-- 步骤8最终汇总计算
summary_calc AS ( summary_calc AS (
SELECT SELECT
-- ===== 账期内新增订单统计 ===== -- 账期内新增订单统计
COUNT(CASE WHEN DATE(amortization_start_date - INTERVAL '7 days') >= '{period_start}'::date COUNT(CASE WHEN order_date >= '{period_start}'::date AND order_date <= '{period_end}'::date THEN 1 END) AS total_new_orders,
AND DATE(amortization_start_date - INTERVAL '7 days') <= '{period_end}'::date COUNT(CASE WHEN order_date >= '{period_start}'::date AND order_date <= '{period_end}'::date
THEN 1 END) AS total_new_orders, AND amortization_start_date <= '{period_end}'::date THEN 1 END) AS formal_orders,
COUNT(CASE WHEN order_date >= '{period_start}'::date AND order_date <= '{period_end}'::date
AND amortization_start_date > '{period_end}'::date THEN 1 END) AS trial_orders,
COUNT(CASE WHEN DATE(amortization_start_date - INTERVAL '7 days') >= '{period_start}'::date -- 冲销历史均摊场景B/E历史下单+账期内退费)
AND DATE(amortization_start_date - INTERVAL '7 days') <= '{period_end}'::date
AND amortization_start_date <= '{period_end}'::date
THEN 1 END) AS formal_orders,
COUNT(CASE WHEN DATE(amortization_start_date - INTERVAL '7 days') >= '{period_start}'::date
AND DATE(amortization_start_date - INTERVAL '7 days') <= '{period_end}'::date
AND amortization_start_date > '{period_end}'::date
THEN 1 END) AS trial_orders,
-- ===== 冲销前均摊金额(税后):所有非"账期前全额退费"订单在账期内的均摊 =====
ROUND(SUM( ROUND(SUM(
CASE CASE WHEN is_current_period_refund = 1 AND is_ordered_in_period = 0 AND historical_amorted_days > 0
WHEN is_pre_period_full_refund = 1 THEN 0 -- 账期前全额退费,不统计 THEN historical_amorted_days * original_daily_amort_amount
WHEN is_pre_period_partial_refund = 1 THEN -- 账期前部分退费,按剩余金额均摊
CASE WHEN total_cycle_days > 0 AND period_amort_days > 0
THEN remaining_after_tax_amount / total_cycle_days * period_amort_days
ELSE 0
END
WHEN is_current_period_refund = 0 AND period_amort_days > 0 THEN -- 正常未退费订单
CASE
-- 补差逻辑:如果账期结束日恰好是均摊最后一天
WHEN eff_end = amortization_end_date
THEN after_tax_amount - daily_amort_amount * (total_cycle_days - 1)
+ daily_amort_amount * (period_amort_days - 1)
ELSE daily_amort_amount * period_amort_days
END
ELSE 0
END
)::numeric, 2) AS pre_writeoff_amort,
-- ===== 冲销前税费 =====
ROUND(SUM(
CASE
WHEN is_pre_period_full_refund = 1 THEN 0
WHEN is_pre_period_partial_refund = 1 THEN
CASE WHEN total_cycle_days > 0 AND period_amort_days > 0
THEN remaining_tax_amount / total_cycle_days * period_amort_days
ELSE 0
END
WHEN is_current_period_refund = 0 AND period_amort_days > 0 THEN
daily_tax_amount * period_amort_days
ELSE 0
END
)::numeric, 2) AS pre_writeoff_tax,
-- ===== 冲销均摊金额(税后):账期内退费订单的历史已均摊金额 =====
ROUND(SUM(
CASE WHEN is_current_period_refund = 1 AND historical_amorted_days > 0
THEN daily_amort_amount * historical_amorted_days
ELSE 0 ELSE 0
END END
)::numeric, 2) AS writeoff_amort, )::numeric, 2) AS writeoff_amort,
-- ===== 冲销税费 ===== -- 冲销原税款场景B/E历史下单+账期内退费)
ROUND(SUM( ROUND(SUM(
CASE WHEN is_current_period_refund = 1 AND historical_amorted_days > 0 CASE WHEN is_current_period_refund = 1 AND is_ordered_in_period = 0
THEN daily_tax_amount * historical_amorted_days THEN tax_amount
ELSE 0 ELSE 0
END END
)::numeric, 2) AS writeoff_tax, )::numeric, 2) AS writeoff_tax,
-- ===== 补充均摊金额(税后):账期内部分退费订单,退费后剩余金额的均摊 ===== -- 冲销未确认收入场景B/E历史下单+账期内退费)
ROUND(SUM( ROUND(SUM(
CASE WHEN is_current_period_refund = 1 CASE WHEN is_current_period_refund = 1 AND is_ordered_in_period = 0
AND is_full_refund = 0 THEN after_tax_amount - historical_amorted_days * original_daily_amort_amount
AND total_cycle_days > 0
AND period_amort_days > 0
THEN (pay_amount - total_refund_amount) * (1 - tax_rate) / total_cycle_days * period_amort_days
ELSE 0 ELSE 0
END END
)::numeric, 2) AS supplement_amort, )::numeric, 2) AS writeoff_unconfirmed,
-- ===== 补充税费 ===== -- 账期均摊金额
ROUND(SUM( ROUND(SUM(
CASE WHEN is_current_period_refund = 1 CASE
AND is_full_refund = 0 WHEN is_pre_period_full_refund = 1 THEN 0
AND total_cycle_days > 0 WHEN is_current_period_refund = 1 AND is_full_refund = 1 THEN 0
AND period_amort_days > 0 -- 场景A账期内下单+部分退费
THEN (pay_amount - total_refund_amount) * tax_rate / total_cycle_days * period_amort_days WHEN is_current_period_refund = 1 AND is_full_refund = 0 AND is_ordered_in_period = 1 THEN
CASE WHEN total_cycle_days > 0 AND period_amort_days > 0
THEN daily_amort_amount * period_amort_days ELSE 0 END
-- 场景B历史下单+账期内部分退费,从转正日重新均摊
WHEN is_current_period_refund = 1 AND is_full_refund = 0 AND is_ordered_in_period = 0 THEN
CASE WHEN total_cycle_days > 0 AND refunded_amort_days_to_period_end > 0
THEN daily_amort_amount * refunded_amort_days_to_period_end ELSE 0 END
-- 场景C账期前部分退费
WHEN is_pre_period_partial_refund = 1 THEN
CASE WHEN total_cycle_days > 0 AND period_amort_days > 0
THEN daily_amort_amount * period_amort_days ELSE 0 END
-- 正常订单
WHEN period_amort_days > 0 THEN
CASE
WHEN eff_end = amortization_end_date
THEN after_tax_amount - original_daily_amort_amount * (original_cycle_days - 1) + original_daily_amort_amount * (period_amort_days - 1)
ELSE original_daily_amort_amount * period_amort_days
END
ELSE 0 ELSE 0
END END
)::numeric, 2) AS supplement_tax )::numeric, 2) AS period_amort,
FROM order_final_amort -- 账期税费(仅账期内下单且已转正的非全额退费订单)
ROUND(SUM(
CASE
-- 账期内下单 + 已转正 + 部分退费 → 退后订单税额
WHEN is_ordered_in_period = 1
AND amortization_start_date <= '{period_end}'::date
AND is_current_period_refund = 1 AND is_full_refund = 0
THEN refunded_tax_amount
-- 账期内下单 + 已转正 + 未全额退费(含未退费) → 原订单税额
WHEN is_ordered_in_period = 1
AND amortization_start_date <= '{period_end}'::date
AND (has_refund = 0 OR (is_current_period_refund = 0 AND is_full_refund = 0))
THEN tax_amount
ELSE 0
END
)::numeric, 2) AS period_tax
FROM order_with_days
WHERE is_pre_period_full_refund = 0
) )
SELECT SELECT
total_new_orders AS "订单数", total_new_orders AS "订单数",
formal_orders AS "正式订单数", formal_orders AS "正式订单数",
trial_orders AS "试用订单数", trial_orders AS "试用订单数",
pre_writeoff_tax AS "冲销前税费", writeoff_amort AS "冲销历史均摊",
writeoff_tax AS "冲销税费", writeoff_tax AS "冲销原税款",
supplement_tax AS "补充税费", writeoff_unconfirmed AS "冲销未确认收入",
ROUND((pre_writeoff_tax - writeoff_tax + supplement_tax)::numeric, 2) AS "冲销后税费", period_amort AS "账期均摊金额",
pre_writeoff_amort AS "冲销前均摊金额", period_tax AS "账期税费",
writeoff_amort AS "冲销均摊金额", ROUND((period_amort - writeoff_amort)::numeric, 2) AS "冲销后均摊金额",
supplement_amort AS "补充均摊金额", ROUND((period_tax - writeoff_tax)::numeric, 2) AS "冲销后税费"
ROUND((pre_writeoff_amort - writeoff_amort + supplement_amort)::numeric, 2) AS "冲销后均摊金额"
FROM summary_calc; FROM summary_calc;