journal_generator.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import pandas as pd
  2. from tkinter import messagebox
  3. from fund_classification_rules import get_classification_rules
  4. class JournalGenerator:
  5. """日记账生成器"""
  6. def __init__(self):
  7. self.param_df = None
  8. self.account_info_df = None
  9. self.shouzhi_class_df = None
  10. self.classification_rules = get_classification_rules()
  11. def load_parameter_table(self, param_file_path):
  12. """加载参数表"""
  13. try:
  14. self.param_df = pd.read_excel(param_file_path, dtype=str)
  15. account_info_sheet = pd.read_excel(param_file_path, sheet_name="账户信息参数", dtype=str, header=1)
  16. self.account_info_df = account_info_sheet
  17. shouzhi_class_sheet = pd.read_excel(param_file_path, sheet_name="收支分类参数", dtype=str, header=1)
  18. self.shouzhi_class_df = shouzhi_class_sheet
  19. return True
  20. except Exception as e:
  21. messagebox.showerror("错误", f"加载参数表失败:{str(e)}")
  22. return False
  23. def generate_journal_data(self, company_name, bank_name, param_file_path, flow_df):
  24. """生成日记账数据"""
  25. if not self.load_parameter_table(param_file_path):
  26. return None
  27. try:
  28. bank_keyword_mapping = {
  29. "微众银行": "微众",
  30. "中国银行": "中国银行",
  31. "农业银行": "农业银行",
  32. "建设银行": "建设银行",
  33. "农信银行": "小枧支行",
  34. "农信银行芙蓉支行": "芙蓉支行"
  35. }
  36. bank_keyword = bank_keyword_mapping.get(bank_name, bank_name)
  37. company_accounts = self.account_info_df[self.account_info_df["公司"] == company_name]
  38. account_info = None
  39. for _, account in company_accounts.iterrows():
  40. if bank_keyword in account["开户行"]:
  41. account_info = company_accounts[company_accounts.index == account.name]
  42. break
  43. if account_info is None or account_info.empty:
  44. messagebox.showerror("错误", f"未找到账户信息:{company_name} - {bank_name}")
  45. return None
  46. account_code = account_info["编号"].values[0]
  47. account_short_name = account_info["简称"].values[0]
  48. company_name_full = account_info["公司"].values[0]
  49. journal_data = []
  50. for _, row in flow_df.iterrows():
  51. transaction_time = row["交易时间"]
  52. opponent_name = str(row["对方户名"]).strip()
  53. summary = str(row["摘要"]).strip()
  54. income = pd.to_numeric(str(row["收入"]).replace(',', '') if str(row["收入"]).strip() != '' else '0', errors="coerce")
  55. expense = pd.to_numeric(str(row["支出"]).replace(',', '') if str(row["支出"]).strip() != '' else '0', errors="coerce")
  56. balance = str(row["余额"]).strip()
  57. if pd.isna(income):
  58. income = 0
  59. if pd.isna(expense):
  60. expense = 0
  61. if income == 0 and expense == 0:
  62. continue
  63. amount = income if income > 0 else expense
  64. shouzhi_type = "收入" if income > 0 else "支出"
  65. try:
  66. transaction_date = pd.to_datetime(transaction_time, errors="coerce")
  67. if pd.isna(transaction_date):
  68. continue
  69. formatted_date = f"{transaction_date.year}/{transaction_date.month}/{transaction_date.day}"
  70. month = str(transaction_date.month)
  71. except:
  72. continue
  73. opponent_bank = str(row.get("对方开户机构", "")).strip()
  74. flow_remark = str(row.get("备注", "")).strip()
  75. is_settlement = False
  76. if opponent_name in self.account_info_df["公司"].values:
  77. is_settlement = True
  78. context = {
  79. "is_settlement": is_settlement,
  80. "income": income,
  81. "opponent_name": opponent_name,
  82. "summary": summary,
  83. "flow_remark": flow_remark
  84. }
  85. fund_level1 = ""
  86. fund_level2 = ""
  87. fund_level3 = ""
  88. for rule in self.classification_rules:
  89. if rule.match(context):
  90. result = rule.apply(context)
  91. fund_level1 = result["level1"]
  92. fund_level2 = result["level2"]
  93. fund_level3 = result["level3"]
  94. break
  95. if "手续费" in summary or "服务费" in summary:
  96. opponent_name = "手续费"
  97. remark = "手续费"
  98. elif "会长提现" in flow_remark or "提现" in flow_remark:
  99. remark = opponent_name + flow_remark
  100. elif flow_remark is not None and flow_remark.strip() != "" and flow_remark != "nan":
  101. remark = flow_remark
  102. else:
  103. remark = opponent_name + opponent_bank
  104. journal_row = {
  105. "编号": account_code,
  106. "简称": account_short_name,
  107. "企业": company_name_full,
  108. "日期": formatted_date,
  109. "月份": month,
  110. "收支": shouzhi_type,
  111. "资金分类-1级": fund_level1,
  112. "资金分类-2级": fund_level2,
  113. "资金分类-3级": fund_level3,
  114. "对手户": opponent_name,
  115. "备注": remark,
  116. "发生额": amount,
  117. "余额": balance,
  118. "备注.1": ""
  119. }
  120. journal_data.append(journal_row)
  121. if not journal_data:
  122. messagebox.showwarning("警告", "未生成任何日记账数据")
  123. return None
  124. journal_df = pd.DataFrame(journal_data)
  125. column_order = ["编号", "简称", "企业", "日期", "月份", "收支", "资金分类-1级",
  126. "资金分类-2级", "资金分类-3级", "对手户", "备注", "发生额", "余额", "备注.1"]
  127. journal_df = journal_df[column_order]
  128. return journal_df
  129. except Exception as e:
  130. messagebox.showerror("错误", f"生成日记账数据失败:{str(e)}")
  131. return None
  132. def save_journal(self, journal_df, save_path):
  133. """保存日记账"""
  134. try:
  135. journal_df.to_excel(save_path, index=False)
  136. return True
  137. except Exception as e:
  138. messagebox.showerror("错误", f"保存日记账失败:{str(e)}")
  139. return False