Files
query-payslip-default/scripts/db/connection.py
skill-dev 3db196e49d feat: 工资查询助手首版 v1.0.105
基于 skill-template 脚手架开发,包含:
- payroll_config(费率配置,可编辑)+ payslip_snapshots(解析历史,只读)2 张业务表
- 全国默认 + 北上广 4 套费率(社保/公积金/个税起征点/7 级税率表)
- 5 个业务 Action:calculate-payslip-simple / calculate-payslip-full / explain-term / view-config / edit-config
- 个税累计预扣法计算,支持多月历史累加
- 20 个薪资名词库(社保/公积金/个税/全勤/加班费等)
- 完整市场文档(README/TUTORIAL/DEMO/CHANGELOG)
- 296 测试全部通过
2026-09-07 17:02:05 +08:00

281 lines
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""SQLite 连接与幂等初始化。
模板默认只建数据管理元数据表。业务表由复制后的技能自行 CREATE,并同步展示元数据。
本技能建两张业务表:payroll_config(费率配置,可编辑)与 payslip_snapshots(解析历史,只读)。
"""
from __future__ import annotations
import sqlite3
from db.display_metadata import (
init_display_metadata,
seed_column_metadata_batch,
upsert_table_metadata,
)
from db.seed_config import seed_default_config
from util.runtime_paths import get_db_path
def get_conn() -> sqlite3.Connection:
return sqlite3.connect(get_db_path())
_PAYROLL_CONFIG_DDL = """
CREATE TABLE IF NOT EXISTS payroll_config (
config_key TEXT NOT NULL,
region TEXT NOT NULL DEFAULT 'default',
config_value REAL NOT NULL,
display_name TEXT NOT NULL,
description TEXT,
effective_date INTEGER,
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
PRIMARY KEY (config_key, region)
)
"""
_PAYROLL_CONFIG_UPDATED_AT_TRIGGER = """
CREATE TRIGGER IF NOT EXISTS payroll_config_set_updated_at
AFTER UPDATE ON payroll_config
FOR EACH ROW
BEGIN
UPDATE payroll_config SET updated_at = unixepoch() WHERE config_key = NEW.config_key AND region = NEW.region;
END
"""
_PAYSLIP_SNAPSHOTS_DDL = """
CREATE TABLE IF NOT EXISTS payslip_snapshots (
id INTEGER PRIMARY KEY AUTOINCREMENT,
snapshot_date INTEGER NOT NULL,
period TEXT,
base_salary REAL,
gross_total REAL NOT NULL,
deduction_total REAL NOT NULL,
net_salary REAL NOT NULL,
reported_net REAL,
check_match INTEGER,
check_diff REAL,
detail_json TEXT,
raw_payload TEXT,
created_at INTEGER NOT NULL DEFAULT (unixepoch())
)
"""
_PAYROLL_CONFIG_COLUMNS: tuple[dict[str, object], ...] = (
{
"column_name": "config_key",
"display_name": "配置项",
"description": "费率配置键,如 social_pension_rate / tax_threshold。",
"visible": 1,
"searchable": 1,
"editable": 0,
},
{
"column_name": "region",
"display_name": "地区",
"description": "费率适用地区:default(全国默认)/ beijing / shanghai / guangzhou。",
"visible": 1,
"searchable": 1,
"editable": 0,
"options_json": '[{"value":"default","label":"全国默认"},{"value":"beijing","label":"北京"},{"value":"shanghai","label":"上海"},{"value":"guangzhou","label":"广州"}]',
},
{
"column_name": "config_value",
"display_name": "数值",
"description": "费率数值(比例为小数,如 0.08 表示 8%)。",
"visible": 1,
"searchable": 1,
"editable": 1,
"display_type": "number",
},
{
"column_name": "display_name",
"display_name": "中文名",
"description": "配置项的中文展示名。",
"visible": 1,
"searchable": 1,
"editable": 1,
},
{
"column_name": "description",
"display_name": "说明",
"description": "配置项的详细说明。",
"visible": 1,
"searchable": 0,
"editable": 1,
"display_type": "textarea",
},
{
"column_name": "effective_date",
"display_name": "生效日期",
"description": "该费率的生效日期(Unix 秒级时间戳)。",
"visible": 1,
"searchable": 1,
"editable": 1,
"display_type": "datetime_unix_seconds",
},
{
"column_name": "created_at",
"display_name": "创建时间",
"description": "记录创建时间(Unix 秒级时间戳,自动生成)。",
"visible": 1,
"searchable": 0,
"editable": 0,
"display_type": "datetime_unix_seconds",
},
{
"column_name": "updated_at",
"display_name": "更新时间",
"description": "记录最后更新时间(Unix 秒级时间戳,自动维护)。",
"visible": 1,
"searchable": 0,
"editable": 0,
"display_type": "datetime_unix_seconds",
},
)
_PAYSLIP_SNAPSHOTS_COLUMNS: tuple[dict[str, object], ...] = (
{"column_name": "id", "display_name": "编号", "description": "主键", "visible": 1, "searchable": 1, "editable": 0},
{
"column_name": "snapshot_date",
"display_name": "解析时间",
"description": "本次解析执行的时间(Unix 秒级时间戳)。",
"visible": 1, "searchable": 1, "editable": 0,
"display_type": "datetime_unix_seconds",
},
{
"column_name": "period",
"display_name": "工资期间",
"description": "工资所属期间,如 2026-08。",
"visible": 1, "searchable": 1, "editable": 0,
},
{
"column_name": "base_salary",
"display_name": "基本工资",
"description": "本次解析的基本工资。",
"visible": 1, "searchable": 1, "editable": 0,
"display_type": "number",
},
{
"column_name": "gross_total",
"display_name": "应发合计",
"description": "本次核算的应发合计。",
"visible": 1, "searchable": 1, "editable": 0,
"display_type": "number",
},
{
"column_name": "deduction_total",
"display_name": "扣除合计",
"description": "本次核算的扣除合计。",
"visible": 1, "searchable": 1, "editable": 0,
"display_type": "number",
},
{
"column_name": "net_salary",
"display_name": "实发工资",
"description": "本次核算的实发工资(应发-扣除)。",
"visible": 1, "searchable": 1, "editable": 0,
"display_type": "number",
},
{
"column_name": "reported_net",
"display_name": "用户自报实发",
"description": "用户给出的实发金额,用于核对。",
"visible": 1, "searchable": 1, "editable": 0,
"display_type": "number",
},
{
"column_name": "check_match",
"display_name": "核对一致",
"description": "1=用户自报与计算一致,0=不一致,NULL=未提供自报。",
"visible": 1, "searchable": 1, "editable": 0,
},
{
"column_name": "check_diff",
"display_name": "差异金额",
"description": "用户自报 - 计算实发。正数表示用户多报,负数表示少报。",
"visible": 1, "searchable": 1, "editable": 0,
"display_type": "number",
},
{
"column_name": "detail_json",
"display_name": "完整明细",
"description": "本次核算的完整明细(JSON 字符串),含各项应发/扣除/估算。",
"visible": 1, "searchable": 0, "editable": 0,
"display_type": "textarea",
},
{
"column_name": "raw_payload",
"display_name": "原始文本",
"description": "用户粘贴的原始工资条文本(隐私保护,默认隐藏)。",
"visible": 0, "searchable": 0, "editable": 0,
"display_type": "textarea",
},
{
"column_name": "created_at",
"display_name": "创建时间",
"description": "记录入库时间(Unix 秒级时间戳,自动生成)。",
"visible": 1, "searchable": 0, "editable": 0,
"display_type": "datetime_unix_seconds",
},
)
def _init_payroll_config_metadata(cursor) -> None:
"""建 payroll_config 表 + 展示元数据。"""
cursor.execute(_PAYROLL_CONFIG_DDL)
cursor.execute(_PAYROLL_CONFIG_UPDATED_AT_TRIGGER)
upsert_table_metadata(
cursor,
table_name="payroll_config",
display_name="费率配置",
description="社保/公积金/个税等费率配置,按地区区分。管理员可编辑数值,影响估算结果。",
grid_help="按地区查看费率;双击数值可编辑(仅管理员)。地区 default 为全国默认。",
visible=1,
readonly=0,
)
seed_column_metadata_batch(
cursor,
table_name="payroll_config",
columns=_PAYROLL_CONFIG_COLUMNS,
valid_column_names=[str(c["column_name"]) for c in _PAYROLL_CONFIG_COLUMNS],
)
def _init_payslip_snapshots_metadata(cursor) -> None:
"""建 payslip_snapshots 表 + 展示元数据(只读)。"""
cursor.execute(_PAYSLIP_SNAPSHOTS_DDL)
upsert_table_metadata(
cursor,
table_name="payslip_snapshots",
display_name="解析历史",
description="本人工资条解析历史记录。每次解析自动写入,可回顾/对比多月。",
grid_help="按工资期间或时间排序查看历史;raw_payload 默认隐藏。",
visible=1,
readonly=1,
default_sort_json='[{"column":"snapshot_date","direction":"desc"},{"column":"id","direction":"desc"}]',
default_visible_columns_json='["snapshot_date","period","base_salary","gross_total","deduction_total","net_salary","check_match"]',
)
seed_column_metadata_batch(
cursor,
table_name="payslip_snapshots",
columns=_PAYSLIP_SNAPSHOTS_COLUMNS,
valid_column_names=[str(c["column_name"]) for c in _PAYSLIP_SNAPSHOTS_COLUMNS],
)
def init_db() -> None:
conn = get_conn()
try:
cur = conn.cursor()
init_display_metadata(cur)
_init_payroll_config_metadata(cur)
_init_payslip_snapshots_metadata(cur)
seed_default_config(cur)
conn.commit()
finally:
conn.close()