Files
openclaw-config/workspace-finances/import_wangfang_wx.py
T

91 lines
4.2 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""导入王芳2026H1微信账单,剔除与支付宝/邮储卡重复的支出"""
import json, pymysql
from datetime import datetime
cfg = json.load(open('db_config.json'))
conn = pymysql.connect(host=cfg['host'], port=cfg['port'], user=cfg['user'],
password=cfg.get('password'), database=cfg['database'], charset='utf8mb4')
cur = conn.cursor()
MEMBER = 3
# 已导入的支付宝+邮储卡支出集合 (同日+同金额)
cur.execute("""SELECT amount, recorded_date FROM variable_expenses
WHERE member_id=3 AND recorded_date BETWEEN '2026-01-01' AND '2026-06-30'
AND (note LIKE '%[支付宝]%' OR note LIKE '%[邮储卡]%')""")
imported = {(d.strftime('%Y-%m-%d'), round(float(a), 2)) for a, d in cur.fetchall()}
print(f"已导入支付宝+邮储卡: {len(imported)}笔")
d = json.load(open('/tmp/wx_juaner.json'))
def fp(s): return float(s)
REFUND_STATES = ('已全额退款', '对方已退还', '已退款', '已退款¥')
def is_refunded(st):
return any(x in st for x in REFUND_STATES)
def cat_of(peer, goods):
s = peer + '|' + (goods or '')
if any(k in s for k in ['超市','生鲜','便利店','水果','餐饮','烧烤','龙虾','包子','蜜雪','瑞幸','金拱门','餐厅','食堂','食品','桃酥','米糕','奶茶','蛋糕','饭店','卷' ,'鱼店','粮油','菜']):
return '餐饮/食品'
if any(k in s for k in ['滴滴','12306','铁路','交通','停车','地铁','火车','中石化','加油','顺风','轨道','导航','共享单车']):
return '交通'
if any(k in s for k in ['药','医院','诊所','口腔','门诊','健康','体检']):
return '医疗'
if any(k in s for k in ['母婴','奶粉','尿不湿','童装','早教','幼教','园']):
return '母婴'
if any(k in s for k in ['服装','女装','百货','鞋','淘宝','拼多多','快团团','旗舰店','饰品','电商','服饰']):
return '购物'
if any(k in s for k in ['美发','美容','护肤','理容']):
return '美容美发'
if any(k in s for k in ['缴费','水电','话费','燃气','物业']):
return '生活缴费'
if any(k in s for k in ['游泳','健身','运动','乐刻']):
return '运动'
if any(k in s for k in ['酒店','旅游','门票','住宿']):
return '旅游'
if any(k in s for k in ['美团','饿了么','外卖','三快','拉扎斯']):
return '餐饮/食品'
if any(k in s for k in ['转账','红包']):
return '转账/红包'
return '其他'
exp_c = 0; exp_s = 0.0; dup = 0; dup_amt = 0.0; cat_tot = {}
for r in d['records']:
direction = r[4].strip()
if direction != '支出':
continue
if is_refunded(r[7].strip()):
continue
amt = fp(r[5]); dt = datetime.strptime(r[0][:19], '%Y-%m-%d %H:%M:%S')
key = (r[0][:10], round(amt, 2))
if key in imported: # 跨平台重复,不重复计数
dup += 1; dup_amt += amt
continue
peer = r[2]; goods = r[3]
c = cat_of(peer, goods)
note = f"[微信] 支出|{r[1].strip()}|{peer}|{goods or '/'}|{r[6].strip()}"
cur.execute("INSERT INTO variable_expenses (member_id,category,amount,recorded_date,note) VALUES (%s,%s,%s,%s,%s)",
(MEMBER, c, amt, dt.date(), note))
exp_c += 1; exp_s += amt; cat_tot[c] = cat_tot.get(c, 0) + amt
inc_c = 0; inc_s = 0.0
for r in d['records']:
direction = r[4].strip()
if direction != '收入':
continue
if is_refunded(r[7].strip()):
continue
amt = fp(r[5]); dt = datetime.strptime(r[0][:19], '%Y-%m-%d %H:%M:%S')
source = r[2] if r[2].strip() else r[1].strip()
note = f"[微信] 收入|{r[1].strip()}|{r[2]}"
cur.execute("INSERT INTO income_records (member_id,source,amount,frequency,recorded_date,note) VALUES (%s,%s,%s,%s,%s,%s)",
(MEMBER, source, amt, '一次性', dt.date(), note))
inc_c += 1; inc_s += amt
conn.commit()
print(f"微信支出导入: {exp_c}笔 ¥{exp_s:.2f}")
print(f"微信支出去重排除: {dup}笔 ¥{dup_amt:.2f}")
print(f"微信收入导入: {inc_c}笔 ¥{inc_s:.2f}")
print("支出分类:", {k: round(v, 2) for k, v in sorted(cat_tot.items(), key=lambda x: -x[1])})
conn.close()