feat: 京东账单专属分类映射配置

This commit is contained in:
CHE LIANG ZHAO
2026-01-26 14:12:05 +08:00
parent 9e146c5ef0
commit 279eceaa95
3 changed files with 147 additions and 7 deletions

View File

@@ -4,6 +4,9 @@
import csv
import re
from decimal import Decimal
from pathlib import Path
import yaml
from .base import (
BaseCleaner, parse_amount, format_amount,
@@ -12,6 +15,54 @@ from .base import (
from category import infer_category
# 加载京东专属分类配置
JD_CONFIG_FILE = Path(__file__).parent.parent / "config" / "category_jd.yaml"
def load_jd_config():
"""加载京东分类配置"""
with open(JD_CONFIG_FILE, "r", encoding="utf-8") as f:
return yaml.safe_load(f)
_jd_config = load_jd_config()
def infer_jd_category(merchant: str, product: str, original_category: str) -> tuple[str, bool]:
"""
根据京东账单的商户名称、商品说明和原分类推断统一分类
Args:
merchant: 商户名称(如"京东外卖""京东平台商户"
product: 交易说明/商品说明
original_category: 京东原始分类(如"食品酒饮""数码电器"
Returns:
(分类名称, 是否确定) - 如果无法确定分类,第二个值为 False
"""
# 1. 先检查商户名称直接映射(如"京东外卖" -> "餐饮美食"
merchant_mapping = _jd_config.get("商户映射", {})
for merchant_key, category in merchant_mapping.items():
if merchant_key in merchant:
return category, True
# 2. 尝试直接映射京东原分类
category_mapping = _jd_config.get("分类映射", {})
# 处理多分类情况(如"食品酒饮 其他网购"
original_cats = original_category.split() if original_category else []
for orig_cat in original_cats:
mapped = category_mapping.get(orig_cat)
if mapped: # 非空映射
return mapped, True
# 3. 使用通用分类推断(已包含京东平台商户关键词)
category, is_certain = infer_category(merchant, product, "支出")
if is_certain:
return category, True
# 4. 返回默认分类
return _jd_config.get("默认分类", "其他支出"), False
# 与支付宝/微信对齐的表头(包含"复核等级"字段)
ALIGNED_HEADER = [
"交易时间", "交易分类", "交易对方", "对方账号", "商品说明",
@@ -242,13 +293,8 @@ class JDCleaner(BaseCleaner):
merchant_order_no = row[9] if len(row) > 9 else ""
final_remark = remark if remark else (row[10] if len(row) > 10 else "/")
# 使用推断分类(京东原始分类相对准确,但仍可优化)
category, is_certain = infer_category(merchant, product, income_expense)
# 如果推断失败但原分类非空,使用原分类
if not is_certain and original_category and original_category not in ["其他", ""]:
category = original_category
is_certain = True # 信任京东原分类
# 使用京东专属分类推断
category, is_certain = infer_jd_category(merchant, product, original_category)
# 复核等级: 空=无需复核, HIGH=无法判断
review_mark = "" if is_certain else "HIGH"

View File

@@ -84,6 +84,40 @@
- 供暖
- 暖气
# 宠物用品
宠物用品:
- 宠物
- 猫咪
-
- 猫粮
- 狗粮
- 猫砂
- 喂水
- 猫零食
- 犬猫
# 数码电器
数码电器:
- 饮水机
- 净水
- 制冰
- nas
- 存储
- 硬盘
- 电脑
- 手机
- 平板
- 电器
- 小家电
- 充电
- 数据线
- 路由器
- 音箱
- 耳机
- 键盘
- 鼠标
- 显示器
# 运动健身
运动健身:
- 健身
@@ -113,6 +147,9 @@
- 电影
- 游戏
- 娱乐
-
- 图书
- 文娱
- 旅游
- 景区
- 门票
@@ -157,6 +194,15 @@
- 妍丽 # AFIONA妍丽美妆店
- 屈臣氏
- 丝芙兰
- 保鲜盒
- 收纳
- 厨房
- 清洁
- 洗衣
- 纸巾
- 毛巾
- 床品
- 家居
# 餐饮美食
餐饮美食:

View File

@@ -0,0 +1,48 @@
# =============================================================================
# 京东账单分类映射配置
# 将京东原始分类转换为统一分类
# =============================================================================
# =============================================================================
# 京东原始分类 -> 统一分类映射
# 京东账单中的"交易分类"字段可能包含以下值:
# - 余额、小金库、白条:财务操作(已在清洗时过滤)
# - 其他、其他网购、网购:需要根据商品说明进一步判断
# - 食品酒饮:餐饮美食
# - 数码电器、电脑办公:数码电器
# - 日用百货:日用百货
# - 图书文娱:文化休闲
# =============================================================================
分类映射:
# 直接映射(京东分类 -> 统一分类)
食品酒饮: 餐饮美食
数码电器: 数码电器
电脑办公: 数码电器
日用百货: 日用百货
图书文娱: 文化休闲
# 需要进一步判断的分类(返回空字符串,由关键词推断)
其他: ""
其他网购: ""
网购: ""
# 财务类(通常已被过滤,但以防万一)
余额: ""
小金库: ""
白条: ""
# =============================================================================
# 商户名称 -> 统一分类映射
# 根据商户名称直接映射分类,无需关键词匹配
# =============================================================================
商户映射:
京东外卖: 餐饮美食
# =============================================================================
# 默认分类
# 当无法匹配任何规则时使用
# =============================================================================
默认分类: 其他支出