1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
| print("=== 专业银行对账系统 ===")
import sqlite3 import hashlib from datetime import datetime, timedelta import pandas as pd from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment, Border, Side from openpyxl.chart import LineChart, Reference
class 专业对账系统: def __init__(self): self.conn = sqlite3.connect(':memory:') self.创建数据库表() def 创建数据库表(self): """创建数据库表结构""" cursor = self.conn.cursor() cursor.execute(''' CREATE TABLE 银行交易 ( id INTEGER PRIMARY KEY AUTOINCREMENT, 交易日期 DATE, 摘要 TEXT, 借方金额 REAL, 贷方金额 REAL, 余额 REAL, 交易哈希 TEXT UNIQUE, 对账状态 TEXT DEFAULT '未对账', 对账时间 TIMESTAMP, 差异说明 TEXT ) ''') cursor.execute(''' CREATE TABLE 企业账目 ( id INTEGER PRIMARY KEY AUTOINCREMENT, 日期 DATE, 摘要 TEXT, 借方 REAL, 贷方 REAL, 金额 REAL, 余额 REAL, 交易哈希 TEXT UNIQUE, 对账状态 TEXT DEFAULT '未对账', 对账时间 TIMESTAMP, 差异说明 TEXT ) ''') cursor.execute(''' CREATE TABLE 对账结果 ( id INTEGER PRIMARY KEY AUTOINCREMENT, 银行交易ID INTEGER, 企业账目ID INTEGER, 对账类型 TEXT, 匹配度 REAL, 差异说明 TEXT, 对账时间 TIMESTAMP, 操作员 TEXT, FOREIGN KEY (银行交易ID) REFERENCES 银行交易(id), FOREIGN KEY (企业账目ID) REFERENCES 企业账目(id) ) ''') self.conn.commit() def 计算交易哈希(self, 日期, 金额, 摘要): """计算交易唯一哈希值""" 哈希字符串 = f"{日期}_{金额}_{摘要[:10]}" return hashlib.md5(哈希字符串.encode()).hexdigest() def 导入银行数据(self, 数据框): """导入银行数据""" cursor = self.conn.cursor() 导入数量 = 0 for _, 行 in 数据框.iterrows(): 交易哈希 = self.计算交易哈希(行['交易日期'], 行['贷方金额'] - 行['借方金额'], 行['摘要']) try: cursor.execute(''' INSERT INTO 银行交易 (交易日期, 摘要, 借方金额, 贷方金额, 余额, 交易哈希) VALUES (?, ?, ?, ?, ?, ?) ''', (行['交易日期'], 行['摘要'], 行['借方金额'], 行['贷方金额'], 行['余额'], 交易哈希)) 导入数量 += 1 except sqlite3.IntegrityError: continue self.conn.commit() print(f"✅ 银行数据导入完成:{导入数量}笔") return 导入数量 def 导入企业数据(self, 数据框): """导入企业数据""" cursor = self.conn.cursor() 导入数量 = 0 for _, 行 in 数据框.iterrows(): 金额 = 行['贷方'] - 行['借方'] 交易哈希 = self.计算交易哈希(行['日期'], 金额, 行['摘要']) try: cursor.execute(''' INSERT INTO 企业账目 (日期, 摘要, 借方, 贷方, 金额, 余额, 交易哈希) VALUES (?, ?, ?, ?, ?, ?, ?) ''', (行['日期'], 行['摘要'], 行['借方'], 行['贷方'], 金额, 行['余额'], 交易哈希)) 导入数量 += 1 except sqlite3.IntegrityError: continue self.conn.commit() print(f"✅ 企业数据导入完成:{导入数量}笔") return 导入数量 def 执行智能对账(self, 容差天数=2, 容差金额=0.01): """执行智能对账""" cursor = self.conn.cursor() print("🔍 执行智能对账...") cursor.execute(''' SELECT b.id, c.id, b.交易日期, c.日期, b.金额, c.金额, b.摘要, c.摘要 FROM 银行交易 b JOIN 企业账目 c ON b.交易哈希 = c.交易哈希 WHERE b.对账状态 = '未对账' AND c.对账状态 = '未对账' ''') 精确匹配 = cursor.fetchall() print(f" 精确匹配:{len(精确匹配)}笔") for 匹配 in 精确匹配: 银行ID, 企业ID = 匹配[0], 匹配[1] cursor.execute('UPDATE 银行交易 SET 对账状态=?, 对账时间=? WHERE id=?', ('已匹配', datetime.now(), 银行ID)) cursor.execute('UPDATE 企业账目 SET 对账状态=?, 对账时间=? WHERE id=?', ('已匹配', datetime.now(), 企业ID)) cursor.execute(''' INSERT INTO 对账结果 (银行交易ID, 企业账目ID, 对账类型, 匹配度, 对账时间) VALUES (?, ?, ?, ?, ?) ''', (银行ID, 企业ID, '精确匹配', 1.0, datetime.now())) cursor.execute(''' SELECT b.id, c.id, b.交易日期, c.日期, b.金额, c.金额, b.摘要, c.摘要 FROM 银行交易 b, 企业账目 c WHERE b.对账状态 = '未对账' AND c.对账状态 = '未对账' AND ABS(b.金额 - c.金额) <= ? AND ABS(JULIANDAY(b.交易日期) - JULIANDAY(c.日期)) <= ? ''', (容差金额, 容差天数)) 模糊匹配 = cursor.fetchall() print(f" 模糊匹配:{len(模糊匹配)}笔") for 匹配 in 模糊匹配: 银行ID, 企业ID, 银行日期, 企业日期, 银行金额, 企业金额, 银行摘要, 企业摘要 = 匹配 日期差异 = abs((pd.to_datetime(银行日期) - pd.to_datetime(企业日期)).days) 金额差异 = abs(银行金额 - 企业金额) 匹配度 = max(0, 1 - 日期差异/容差天数 * 0.5 - 金额差异/max(abs(银行金额), abs(企业金额)) * 0.5) cursor.execute('UPDATE 银行交易 SET 对账状态=?, 对账时间=?, 差异说明=? WHERE id=?', ('模糊匹配', datetime.now(), f'日期差异{日期差异}天', 银行ID)) cursor.execute('UPDATE 企业账目 SET 对账状态=?, 对账时间=?, 差异说明=? WHERE id=?', ('模糊匹配', datetime.now(), f'金额差异{金额差异:.2f}元', 企业ID)) cursor.execute(''' INSERT INTO 对账结果 (银行交易ID, 企业账目ID, 对账类型, 匹配度, 差异说明, 对账时间) VALUES (?, ?, ?, ?, ?, ?) ''', (银行ID, 企业ID, '模糊匹配', 匹配度, f'日期差异{日期差异}天,金额差异{金额差异:.2f}元', datetime.now())) self.conn.commit() cursor.execute('SELECT COUNT(*) FROM 银行交易 WHERE 对账状态="已匹配"') 银行已匹配 = cursor.fetchone()[0] cursor.execute('SELECT COUNT(*) FROM 企业账目 WHERE 对账状态="已匹配"') 企业已匹配 = cursor.fetchone()[0] cursor.execute('SELECT COUNT(*) FROM 银行交易 WHERE 对账状态="未对账"') 银行未匹配 = cursor.fetchone()[0] cursor.execute('SELECT COUNT(*) FROM 企业账目 WHERE 对账状态="未对账"') 企业未匹配 = cursor.fetchone()[0] return { "银行已匹配": 银行已匹配, "企业已匹配": 企业已匹配, "银行未匹配": 银行未匹配, "企业未匹配": 企业未匹配, "精确匹配": len(精确匹配), "模糊匹配": len(模糊匹配) } def 生成专业报告(self, 文件名="专业对账报告.xlsx"): """生成专业的Excel对账报告""" wb = Workbook() cursor = self.conn.cursor() 汇总结果 = self.执行智能对账() 汇总表 = wb.active 汇总表.title = "对账汇总" 汇总表["A1"] = "银行对账汇总报告" 汇总表["A1"].font = Font(size=18, bold=True, color="FFFFFF") 汇总表["A1"].fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid") 汇总表.merge_cells("A1:F1") 汇总表["A1"].alignment = Alignment(horizontal="center") 汇总表["A3"] = f"报告生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" 汇总表["A3"].font = Font(size=10, italic=True) 汇总数据 = [ ["对账结果", "笔数", "占比", "状态说明"], ["精确匹配", 汇总结果["精确匹配"], f"{汇总结果['精确匹配']/max(汇总结果['银行已匹配'], 1)*100:.1f}%", "完全一致"], ["模糊匹配", 汇总结果["模糊匹配"], f"{汇总结果['模糊匹配']/max(汇总结果['银行已匹配'], 1)*100:.1f}%", "金额相近,日期差异"], ["银行未匹配", 汇总结果["银行未匹配"], f"{汇总结果['银行未匹配']/max(len(self.银行数据), 1)*100:.1f}%", "银行有,企业无"], ["企业未匹配", 汇总结果["企业未匹配"], f"{汇总结果['企业未匹配']/max(len(self.企业数据), 1)*100:.1f}%", "企业有,银行无"] ] 起始行 = 5 for 行号, 数据行 in enumerate(汇总数据, 起始行): for 列号, 值 in enumerate(数据行, 1): 单元格 = 汇总表.cell(row=行号, column=列号, value=值) if 行号 == 起始行: 单元格.font = Font(bold=True) 单元格.fill = PatternFill(start_color="D9E2F3", end_color="D9E2F3", fill_type="solid") 明细表 = wb.create_sheet("未匹配明细") cursor.execute(''' SELECT 交易日期, 摘要, 借方金额, 贷方金额, 余额, 差异说明 FROM 银行交易 WHERE 对账状态 = '未对账' ORDER BY 交易日期 ''') 银行未匹配 = cursor.fetchall() 明细表["A1"] = "银行未达账项" 明细表["A1"].font = Font(size=14, bold=True, color="FF0000") if 银行未匹配: 表头 = ["日期", "摘要", "借方", "贷方", "余额", "备注"] for 列号, 标题 in enumerate(表头, 1): 明细表.cell(row=3, column=列号, value=标题) 明细表.cell(row=3, column=列号).font = Font(bold=True) for 行号, 记录 in enumerate(银行未匹配, 4): for 列号, 值 in enumerate(记录, 1): 明细表.cell(row=行号, column=列号, value=值) 小计行 = len(银行未匹配) + 5 明细表.cell(row=小计行, column=1, value="小计") 明细表.cell(row=小计行, column=3, value=f"=SUM(C4:C{小计行-1})") 明细表.cell(row=小计行, column=4, value=f"=SUM(D4:D{小计行-1})") 明细表.cell(row=小计行, column=1).font = Font(bold=True) 起始行 = len(银行未匹配) + 8 if 银行未匹配 else 5 明细表.cell(row=起始行, column=1, value="企业未达账项") 明细表.cell(row=起始行, column=1).font = Font(size=14, bold=True, color="FF0000") cursor.execute(''' SELECT 日期, 摘要, 借方, 贷方, 余额, 差异说明 FROM 企业账目 WHERE 对账状态 = '未对账' ORDER BY 日期 ''') 企业未匹配 = cursor.fetchall() if 企业未匹配: 数据起始行 = 起始行 + 2 for 列号, 标题 in enumerate(["日期", "摘要", "借方", "贷方", "余额", "备注"], 1): 明细表.cell(row=数据起始行, column=列号, value=标题) 明细表.cell(row=数据起始行, column=列号).font = Font(bold=True) for 行号, 记录 in enumerate(企业未匹配, 数据起始行 + 1): for 列号, 值 in enumerate(记录, 1): 明细表.cell(row=行号, column=列号, value=值) for 列 in ["A", "B", "C", "D", "E", "F"]: 明细表.column_dimensions[列].width = 15 建议表 = wb.create_sheet("调整分录建议") 建议表["A1"] = "调整分录建议" 建议表["A1"].font = Font(size=14, bold=True) 调整建议 = [ ["序号", "调整事项", "会计分录", "金额", "说明"], ["1", "银行已收企业未收", "借:银行存款\n贷:应收账款", "按未达金额", "银行已入账,企业未获取回单"], ["2", "银行已付企业未付", "借:应付账款\n贷:银行存款", "按未达金额", "银行已扣款,企业未获取回单"], ["3", "企业已收银行未收", "借:其他应收款\n贷:应收账款", "按未达金额", "企业已记账,银行尚未到账"], ["4", "企业已付银行未付", "借:应付账款\n贷:其他应付款", "按未达金额", "企业已付款,银行尚未扣款"] ] for 行号, 数据行 in enumerate(调整建议, 3): for 列号, 值 in enumerate(数据行, 1): 单元格 = 建议表.cell(row=行号, column=列号, value=值) if 行号 == 3: 单元格.font = Font(bold=True) 单元格.fill = PatternFill(start_color="E8F4FD", end_color="E8F4FD", fill_type="solid") if 列号 == 3: 单元格.alignment = Alignment(wrap_text=True) for 列号, 宽度 in enumerate([5, 15, 20, 12, 30], 1): 列字母 = chr(64 + 列号) 建议表.column_dimensions[列字母].width = 宽度 wb.save(文件名) print(f"✅ 专业对账报告已生成:{文件名}") return 文件名
专业系统 = 专业对账系统()
import random from datetime import datetime, timedelta
def 生成示例银行数据(文件名="示例银行数据.csv", 记录数=20): """生成示例银行数据""" 起始日期 = datetime(2024, 1, 1) 当前余额 = 50000 数据 = [] 数据.append(["交易日期", "摘要", "借方金额", "贷方金额", "余额"]) for i in range(记录数): 日期 = 起始日期 + timedelta(days=random.randint(1, 30)) 交易类型 = random.choice(["收入", "支出"]) if 交易类型 == "收入": 金额 = random.randint(1000, 10000) 摘要 = random.choice(["客户货款", "利息收入", "退款"]) 借方, 贷方 = 0, 金额 当前余额 += 金额 else: 金额 = random.randint(500, 5000) 摘要 = random.choice(["供应商付款", "工资", "水电费", "办公费"]) 借方, 贷方 = 金额, 0 当前余额 -= 金额 数据.append([ 日期.strftime("%Y-%m-%d"), 摘要, f"{借方:.2f}", f"{贷方:.2f}", f"{当前余额:.2f}" ]) with open(文件名, "w", encoding="utf-8", newline='') as f: writer = csv.writer(f) writer.writerows(数据) return 文件名
def 生成示例企业数据(文件名="示例企业数据.csv", 记录数=18): """生成示例企业数据(故意制造一些差异)""" 起始日期 = datetime(2024, 1, 1) 当前余额 = 50000 数据 = [] 数据.append(["日期", "摘要", "借方", "贷方", "余额"]) 交易列表 = [ ("2024-01-01", "上月结转", 0, 0, 50000), ("2024-01-05", "客户A货款", 0, 25000, 75000), ("2024-01-10", "供应商B付款", 15000, 0, 60000), ("2024-01-15", "工资发放", 35000, 0, 25000), ("2024-01-22", "客户E货款(未达)", 0, 15000, 40000), ("2024-01-25", "水电费", 1200, 0, 38800), ("2024-01-28", "客户D货款", 0, 20000, 58800), ("2024-01-30", "银行手续费", 50, 0, 58750), ("2024-02-05", "预收客户款", 0, 8000, 66750), ("2024-02-10", "预付供应商款", 5000, 0, 61750), ] for 日期, 摘要, 借方, 贷方, 余额 in 交易列表: 数据.append([日期, 摘要, f"{借方:.2f}", f"{贷方:.2f}", f"{余额:.2f}"]) 起始日期 = datetime(2024, 2, 15) for i in range(记录数 - len(交易列表)): 日期 = 起始日期 + timedelta(days=random.randint(1, 30)) 交易类型 = random.choice(["收入", "支出"]) if 交易类型 == "收入": 金额 = random.randint(2000, 8000) 摘要 = random.choice(["服务费收入", "其他收入"]) 借方, 贷方 = 0, 金额 else: 金额 = random.randint(1000, 3000) 摘要 = random.choice(["办公费", "差旅费", "通讯费"]) 借方, 贷方 = 金额, 0 当前余额 = 当前余额 - 借方 + 贷方 数据.append([ 日期.strftime("%Y-%m-%d"), 摘要, f"{借方:.2f}", f"{贷方:.2f}", f"{当前余额:.2f}" ]) with open(文件名, "w", encoding="utf-8", newline='') as f: writer = csv.writer(f) writer.writerows(数据) return 文件名
银行文件 = 生成示例银行数据("专业银行数据.csv", 25) 企业文件 = 生成示例企业数据("专业企业数据.csv", 22)
银行df = pd.read_csv(银行文件) 企业df = pd.read_csv(企业文件)
银行df['交易日期'] = pd.to_datetime(银行df['交易日期']) 银行df['借方金额'] = pd.to_numeric(银行df['借方金额'], errors='coerce').fillna(0) 银行df['贷方金额'] = pd.to_numeric(银行df['贷方金额'], errors='coerce').fillna(0) 银行df['余额'] = pd.to_numeric(银行df['余额'], errors='coerce').fillna(0)
企业df['日期'] = pd.to_datetime(企业df['日期']) 企业df['借方'] = pd.to_numeric(企业df['借方'], errors='coerce').fillna(0) 企业df['贷方'] = pd.to_numeric(企业df['贷方'], errors='coerce').fillna(0) 企业df['余额'] = pd.to_numeric(企业df['余额'], errors='coerce').fillna(0)
专业系统.导入银行数据(银行df) 专业系统.导入企业数据(企业df)
对账统计 = 专业系统.执行智能对账(容差天数=3, 容差金额=0.01)
专业报告 = 专业系统.生成专业报告("专业银行对账报告.xlsx")
print(f"\n📊 专业对账完成!") print(f"报告文件:{专业报告}") print(f"\n对账统计:") for 项目, 数量 in 对账统计.items(): print(f" {项目}:{数量}")
|