281 lines
12 KiB
Python
281 lines
12 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
分析会员卡结算情况,找出所有相关字段和正确的消费金额计算方式
|
|
"""
|
|
|
|
import os
|
|
import psycopg2
|
|
from datetime import datetime
|
|
from dotenv import load_dotenv
|
|
|
|
def main():
|
|
# 加载环境变量
|
|
load_dotenv()
|
|
|
|
test_db_dsn = os.environ.get('TEST_DB_DSN')
|
|
if not test_db_dsn:
|
|
raise RuntimeError("TEST_DB_DSN 环境变量未设置")
|
|
|
|
print("💳 会员卡结算分析")
|
|
print("=" * 50)
|
|
|
|
with psycopg2.connect(test_db_dsn) as conn:
|
|
with conn.cursor() as cur:
|
|
|
|
# 1. 查看所有金额相关字段
|
|
print("\n💰 1. 所有金额相关字段分析")
|
|
|
|
cur.execute("""
|
|
SELECT column_name, data_type
|
|
FROM information_schema.columns
|
|
WHERE table_schema = 'ods' AND table_name = 'settlement_records'
|
|
AND (column_name LIKE '%amount%' OR column_name LIKE '%money%' OR column_name LIKE '%card%')
|
|
ORDER BY column_name
|
|
""")
|
|
|
|
amount_fields = cur.fetchall()
|
|
print("金额相关字段:")
|
|
for field_name, data_type in amount_fields:
|
|
print(f" {field_name}: {data_type}")
|
|
|
|
# 2. 分析零消费订单的各字段值
|
|
print("\n🔍 2. 零消费订单字段值分析")
|
|
|
|
cur.execute("""
|
|
SELECT
|
|
payamount,
|
|
balanceamount,
|
|
cardamount,
|
|
cashamount,
|
|
couponamount,
|
|
onlineamount,
|
|
pointamount,
|
|
refundamount,
|
|
roundingamount,
|
|
adjustamount,
|
|
couponsaleamount,
|
|
memberdiscountamount,
|
|
tablechargemoney,
|
|
goodsmoney,
|
|
realgoodsmoney,
|
|
servicemoney,
|
|
prepaymoney,
|
|
rechargecardamount,
|
|
giftcardamount,
|
|
COUNT(*) as record_count
|
|
FROM ods.settlement_records
|
|
WHERE payamount = 0
|
|
AND paytime >= '2026-02-01'
|
|
GROUP BY
|
|
payamount, balanceamount, cardamount, cashamount, couponamount,
|
|
onlineamount, pointamount, refundamount, roundingamount, adjustamount,
|
|
couponsaleamount, memberdiscountamount, tablechargemoney, goodsmoney,
|
|
realgoodsmoney, servicemoney, prepaymoney, rechargecardamount, giftcardamount
|
|
ORDER BY record_count DESC
|
|
LIMIT 10
|
|
""")
|
|
|
|
zero_patterns = cur.fetchall()
|
|
print("零消费订单的字段组合 (前10种模式):")
|
|
for i, pattern in enumerate(zero_patterns):
|
|
print(f"\n 模式 {i+1} ({pattern[-1]} 条记录):")
|
|
field_names = [
|
|
'payamount', 'balanceamount', 'cardamount', 'cashamount', 'couponamount',
|
|
'onlineamount', 'pointamount', 'refundamount', 'roundingamount', 'adjustamount',
|
|
'couponsaleamount', 'memberdiscountamount', 'tablechargemoney', 'goodsmoney',
|
|
'realgoodsmoney', 'servicemoney', 'prepaymoney', 'rechargecardamount', 'giftcardamount'
|
|
]
|
|
for j, field_name in enumerate(field_names):
|
|
value = pattern[j]
|
|
if value != 0:
|
|
print(f" {field_name}: {value}")
|
|
|
|
# 3. 分析正常消费订单的字段值
|
|
print("\n💵 3. 正常消费订单字段值分析")
|
|
|
|
cur.execute("""
|
|
SELECT
|
|
payamount,
|
|
balanceamount,
|
|
cardamount,
|
|
cashamount,
|
|
couponamount,
|
|
goodsmoney,
|
|
realgoodsmoney,
|
|
servicemoney,
|
|
tablechargemoney,
|
|
COUNT(*) as record_count
|
|
FROM ods.settlement_records
|
|
WHERE payamount > 0
|
|
AND paytime >= '2026-02-01'
|
|
GROUP BY
|
|
payamount, balanceamount, cardamount, cashamount, couponamount,
|
|
goodsmoney, realgoodsmoney, servicemoney, tablechargemoney
|
|
ORDER BY record_count DESC
|
|
LIMIT 5
|
|
""")
|
|
|
|
normal_patterns = cur.fetchall()
|
|
print("正常消费订单的字段组合 (前5种模式):")
|
|
for i, pattern in enumerate(normal_patterns):
|
|
print(f"\n 模式 {i+1} ({pattern[-1]} 条记录):")
|
|
field_names = [
|
|
'payamount', 'balanceamount', 'cardamount', 'cashamount', 'couponamount',
|
|
'goodsmoney', 'realgoodsmoney', 'servicemoney', 'tablechargemoney'
|
|
]
|
|
for j, field_name in enumerate(field_names):
|
|
value = pattern[j]
|
|
print(f" {field_name}: {value}")
|
|
|
|
# 4. 分析可能的消费金额计算公式
|
|
print("\n🧮 4. 消费金额计算公式分析")
|
|
|
|
# 测试不同的计算公式
|
|
formulas = [
|
|
("payamount", "payamount"),
|
|
("现金+卡", "cashamount + cardamount"),
|
|
("现金+卡+余额", "cashamount + cardamount + balanceamount"),
|
|
("现金+卡+优惠券", "cashamount + cardamount + couponamount"),
|
|
("商品金额", "goodsmoney"),
|
|
("实际商品金额", "realgoodsmoney"),
|
|
("商品+服务", "goodsmoney + servicemoney"),
|
|
("商品+台费", "goodsmoney + tablechargemoney"),
|
|
("全部金额", "cashamount + cardamount + balanceamount + couponamount + onlineamount"),
|
|
("储值卡+现金+团购", "cardamount + cashamount + couponamount")
|
|
]
|
|
|
|
for formula_name, formula_sql in formulas:
|
|
cur.execute(f"""
|
|
SELECT
|
|
COUNT(*) as total_records,
|
|
COUNT(CASE WHEN ({formula_sql}) > 0 THEN 1 END) as positive_records,
|
|
AVG({formula_sql}) as avg_amount,
|
|
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY {formula_sql}) as median_amount,
|
|
MIN({formula_sql}) as min_amount,
|
|
MAX({formula_sql}) as max_amount
|
|
FROM ods.settlement_records
|
|
WHERE paytime >= '2026-02-01'
|
|
AND memberid > 0 -- 只看会员订单
|
|
""")
|
|
|
|
result = cur.fetchone()
|
|
total, positive, avg_amt, median_amt, min_amt, max_amt = result
|
|
positive_rate = (positive / total) * 100 if total > 0 else 0
|
|
|
|
print(f"\n {formula_name}: {formula_sql}")
|
|
print(f" 正数记录: {positive:,}/{total:,} ({positive_rate:.1f}%)")
|
|
print(f" 平均值: {avg_amt:.2f}, 中位数: {median_amt:.2f}")
|
|
print(f" 范围: [{min_amt:.2f}, {max_amt:.2f}]")
|
|
|
|
# 5. 深入分析会员卡相关字段
|
|
print("\n💳 5. 会员卡相关字段深度分析")
|
|
|
|
card_fields = ['cardamount', 'balanceamount', 'rechargecardamount', 'giftcardamount']
|
|
|
|
for field in card_fields:
|
|
cur.execute(f"""
|
|
SELECT
|
|
CASE
|
|
WHEN {field} = 0 THEN '零值'
|
|
WHEN {field} > 0 AND {field} <= 50 THEN '小额(≤50)'
|
|
WHEN {field} > 50 AND {field} <= 200 THEN '中额(50-200)'
|
|
WHEN {field} > 200 THEN '大额(>200)'
|
|
WHEN {field} < 0 THEN '负值'
|
|
END as amount_range,
|
|
COUNT(*) as record_count,
|
|
AVG({field}) as avg_amount
|
|
FROM ods.settlement_records
|
|
WHERE paytime >= '2026-02-01'
|
|
GROUP BY
|
|
CASE
|
|
WHEN {field} = 0 THEN '零值'
|
|
WHEN {field} > 0 AND {field} <= 50 THEN '小额(≤50)'
|
|
WHEN {field} > 50 AND {field} <= 200 THEN '中额(50-200)'
|
|
WHEN {field} > 200 THEN '大额(>200)'
|
|
WHEN {field} < 0 THEN '负值'
|
|
END
|
|
ORDER BY record_count DESC
|
|
""")
|
|
|
|
field_stats = cur.fetchall()
|
|
print(f"\n {field} 分布:")
|
|
for amount_range, count, avg_amt in field_stats:
|
|
print(f" {amount_range}: {count:,} 条, 平均 {avg_amt:.2f}")
|
|
|
|
# 6. 找出最可能的会员卡抵扣字段
|
|
print("\n🎯 6. 推荐的会员卡抵扣字段")
|
|
|
|
# 分析零消费但有其他金额的订单
|
|
cur.execute("""
|
|
SELECT
|
|
'cardamount' as field_name,
|
|
COUNT(CASE WHEN payamount = 0 AND cardamount > 0 THEN 1 END) as zero_pay_positive_field,
|
|
COUNT(CASE WHEN payamount > 0 AND cardamount > 0 THEN 1 END) as positive_pay_positive_field,
|
|
AVG(CASE WHEN cardamount > 0 THEN cardamount END) as avg_when_positive
|
|
FROM ods.settlement_records
|
|
WHERE paytime >= '2026-02-01'
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
'balanceamount' as field_name,
|
|
COUNT(CASE WHEN payamount = 0 AND balanceamount > 0 THEN 1 END),
|
|
COUNT(CASE WHEN payamount > 0 AND balanceamount > 0 THEN 1 END),
|
|
AVG(CASE WHEN balanceamount > 0 THEN balanceamount END)
|
|
FROM ods.settlement_records
|
|
WHERE paytime >= '2026-02-01'
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
'couponamount' as field_name,
|
|
COUNT(CASE WHEN payamount = 0 AND couponamount > 0 THEN 1 END),
|
|
COUNT(CASE WHEN payamount > 0 AND couponamount > 0 THEN 1 END),
|
|
AVG(CASE WHEN couponamount > 0 THEN couponamount END)
|
|
FROM ods.settlement_records
|
|
WHERE paytime >= '2026-02-01'
|
|
""")
|
|
|
|
field_analysis = cur.fetchall()
|
|
print("字段与零消费关联性分析:")
|
|
for field_name, zero_pay_positive, positive_pay_positive, avg_positive in field_analysis:
|
|
print(f" {field_name}:")
|
|
print(f" 零消费但该字段>0: {zero_pay_positive:,} 条")
|
|
print(f" 正常消费且该字段>0: {positive_pay_positive:,} 条")
|
|
if avg_positive is not None:
|
|
print(f" 该字段>0时平均值: {avg_positive:.2f}")
|
|
else:
|
|
print(f" 该字段>0时平均值: 无数据")
|
|
|
|
# 7. 提供具体的样本数据
|
|
print("\n📋 7. 具体样本数据")
|
|
|
|
cur.execute("""
|
|
SELECT
|
|
id,
|
|
paytime,
|
|
payamount,
|
|
cardamount,
|
|
balanceamount,
|
|
cashamount,
|
|
couponamount,
|
|
goodsmoney,
|
|
memberid
|
|
FROM ods.settlement_records
|
|
WHERE payamount = 0
|
|
AND (cardamount > 0 OR balanceamount > 0 OR couponamount > 0)
|
|
AND paytime >= '2026-02-01'
|
|
ORDER BY paytime DESC
|
|
LIMIT 10
|
|
""")
|
|
|
|
samples = cur.fetchall()
|
|
print("零消费但有其他金额的样本 (前10条):")
|
|
for sample in samples:
|
|
oid, paytime, payamount, cardamount, balanceamount, cashamount, couponamount, goodsmoney, memberid = sample
|
|
print(f" ID: {oid}, 时间: {paytime.strftime('%m-%d %H:%M')}")
|
|
print(f" pay: {payamount}, card: {cardamount}, balance: {balanceamount}")
|
|
print(f" cash: {cashamount}, coupon: {couponamount}, goods: {goodsmoney}")
|
|
|
|
if __name__ == "__main__":
|
|
main() |