#!/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()