import sqlite3 import json from pathlib import Path import os from config import OUTPUT_DIR, DB_PATH RECEIPT_JSON = OUTPUT_DIR / "receipt_details_full_clean.json" BOM_JSON = OUTPUT_DIR / "bom_cost_full_tree_final.json" def init_db(): """初始化数据库并创建表""" conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() # 创建收货明细表 cursor.execute(''' CREATE TABLE IF NOT EXISTS receipt_details ( id INTEGER PRIMARY KEY AUTOINCREMENT, purchase_order_code TEXT, row_no INTEGER, material_code TEXT, material_name TEXT, material_specification TEXT, warehouse_code TEXT, warehouse_name TEXT, supplier_code TEXT, supplier_name TEXT, unit_name TEXT, conversion_unit TEXT, receive_price REAL, receipt_time TEXT, purchase_qty REAL, receive_qty REAL, total_amount REAL ) ''') # 为收货明细表创建索引以加速查询 cursor.execute('CREATE INDEX IF NOT EXISTS idx_receipt_material_code ON receipt_details(material_code)') cursor.execute('CREATE INDEX IF NOT EXISTS idx_receipt_supplier_name ON receipt_details(supplier_name)') cursor.execute('CREATE INDEX IF NOT EXISTS idx_receipt_time ON receipt_details(receipt_time)') # 注意:为了在打包部署时不丢失用户已抓取的数据,改为 IF NOT EXISTS cursor.execute(''' CREATE TABLE IF NOT EXISTS bom_parent ( id INTEGER PRIMARY KEY AUTOINCREMENT, parent_material_code TEXT UNIQUE, parent_material_name TEXT ) ''') cursor.execute(''' CREATE TABLE IF NOT EXISTS bom_child ( id INTEGER PRIMARY KEY AUTOINCREMENT, parent_material_code TEXT, -- 归属的最顶层父件 node_material_code TEXT, node_material_name TEXT, bom_level INTEGER, parent_node_id INTEGER, -- 指向上一级子件的 id,如果是一级子件则为空 usage_qty REAL DEFAULT 1.0, FOREIGN KEY(parent_material_code) REFERENCES bom_parent(parent_material_code), FOREIGN KEY(parent_node_id) REFERENCES bom_child(id) ) ''') cursor.execute('CREATE INDEX IF NOT EXISTS idx_bom_child_parent_code ON bom_child(parent_material_code)') cursor.execute('CREATE INDEX IF NOT EXISTS idx_bom_child_node_code ON bom_child(node_material_code)') conn.commit() return conn def import_receipt_details(conn): """导入收货明细数据""" if not RECEIPT_JSON.exists(): print(f"找不到收货明细文件: {RECEIPT_JSON}") return print("开始导入收货明细数据...") with open(RECEIPT_JSON, 'r', encoding='utf-8') as f: data = json.load(f) cursor = conn.cursor() # 清空旧数据(如果需要重复运行),并且我们现在要更新表结构 cursor.execute('DROP TABLE IF EXISTS receipt_details') cursor.execute(''' CREATE TABLE receipt_details ( id INTEGER PRIMARY KEY AUTOINCREMENT, purchase_order_code TEXT, row_no INTEGER, material_code TEXT, material_name TEXT, material_specification TEXT, warehouse_code TEXT, warehouse_name TEXT, supplier_code TEXT, supplier_name TEXT, unit_name TEXT, conversion_unit TEXT, receive_price REAL, receipt_time TEXT, purchase_qty REAL, receive_qty REAL, total_amount REAL ) ''') cursor.execute('CREATE INDEX IF NOT EXISTS idx_receipt_material_code ON receipt_details(material_code)') cursor.execute('CREATE INDEX IF NOT EXISTS idx_receipt_supplier_name ON receipt_details(supplier_name)') cursor.execute('CREATE INDEX IF NOT EXISTS idx_receipt_time ON receipt_details(receipt_time)') count = 0 for item in data: p_qty = item.get("进货数量") r_qty = item.get("收货数量") cursor.execute(''' INSERT INTO receipt_details ( purchase_order_code, row_no, material_code, material_name, material_specification, warehouse_code, warehouse_name, supplier_code, supplier_name, unit_name, conversion_unit, receive_price, receipt_time, purchase_qty, receive_qty, total_amount ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( item.get("采购订单号"), item.get("行号"), item.get("物料代码"), item.get("物料名称"), item.get("物料规格"), item.get("仓库代码"), item.get("仓库名称"), item.get("供应商代码"), item.get("供应商名称"), item.get("单位名称"), item.get("转换单位"), item.get("收货单价"), item.get("收货时间"), p_qty, r_qty, item.get("收货总金额") )) count += 1 conn.commit() print(f"成功导入 {count} 条收货明细数据!") def _insert_bom_tree(cursor, parent_material_code, tree_nodes, parent_node_id=None): """递归插入 BOM 树节点""" for node in tree_nodes: # 提取当前节点信息 node_code = node.get("childMaterialCode") node_name = node.get("childMaterialName") bom_level = node.get("bomLevel") usage_qty = float(node.get("usageQty") or 1.0) # 插入当前节点 cursor.execute(''' INSERT INTO bom_child ( parent_material_code, node_material_code, node_material_name, bom_level, parent_node_id, usage_qty ) VALUES (?, ?, ?, ?, ?, ?) ''', (parent_material_code, node_code, node_name, bom_level, parent_node_id, usage_qty)) # 获取刚插入的节点 ID,作为其子节点的 parent_node_id current_node_id = cursor.lastrowid # 如果有子节点,递归插入 sub_items = node.get("sub_items", []) if sub_items: _insert_bom_tree(cursor, parent_material_code, sub_items, current_node_id) def import_bom_data(conn): """导入 BOM 成本树状数据""" if not BOM_JSON.exists(): print(f"找不到 BOM 成本文件: {BOM_JSON}") return print("开始导入 BOM 成本数据...") with open(BOM_JSON, 'r', encoding='utf-8') as f: data = json.load(f) cursor = conn.cursor() # 清空旧数据 cursor.execute('DELETE FROM bom_child') cursor.execute('DELETE FROM bom_parent') parent_count = 0 for parent in data: parent_code = parent.get("parentMaterialCode") parent_name = parent.get("parentMaterialName") # 忽略空父件 if not parent_code: continue try: cursor.execute(''' INSERT INTO bom_parent (parent_material_code, parent_material_name) VALUES (?, ?) ''', (parent_code, parent_name)) parent_count += 1 # 递归处理这棵树 tree = parent.get("bom_cost_tree", []) if tree: _insert_bom_tree(cursor, parent_code, tree, parent_node_id=None) except sqlite3.IntegrityError: print(f"警告: 父件重复 {parent_code},跳过") conn.commit() # 统计插入的子件数量 cursor.execute('SELECT COUNT(*) FROM bom_child') child_count = cursor.fetchone()[0] print(f"成功导入 {parent_count} 个 BOM 父件,包含 {child_count} 个子件节点!") if __name__ == "__main__": import sys print(f"数据库文件将保存在: {DB_PATH}") conn = init_db() # 允许通过命令行参数单独导入某一部分数据 args = sys.argv[1:] if "--bom-only" in args: import_bom_data(conn) elif "--receipt-only" in args: import_receipt_details(conn) else: # 默认全量导入 import_receipt_details(conn) import_bom_data(conn) conn.close() print("全部导入完成!你可以使用 SQLite 客户端连接 erp_data.db 查看数据。")