journal_generator.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import pandas as pd
  2. from tkinter import messagebox
  3. class JournalGenerator:
  4. """日记账生成器"""
  5. def __init__(self, account_param_sheet="账户信息参数", category_param_sheet="收支分类参数"):
  6. self.account_param_sheet = account_param_sheet
  7. self.category_param_sheet = category_param_sheet
  8. self.settlement_companies = ["成都合煦商贸有限公司", "四川泗讯科技有限公司"]
  9. def load_parameter_table(self, param_file_path):
  10. """加载参数表,返回账户信息和收支分类"""
  11. try:
  12. account_params = pd.read_excel(param_file_path, sheet_name=self.account_param_sheet, header=1)
  13. category_params = pd.read_excel(param_file_path, sheet_name=self.category_param_sheet, header=1)
  14. return account_params, category_params
  15. except Exception as e:
  16. messagebox.showerror("错误", f"加载参数表失败:{str(e)}")
  17. return None, None
  18. def generate_journal_data(self, company_name, bank_name, param_file, flow_df):
  19. """核心:生成日记账数据"""
  20. account_params, category_params = self.load_parameter_table(param_file)
  21. if account_params is None:
  22. return None
  23. account_filter = account_params["公司"] == company_name
  24. account_info = account_params[account_filter]
  25. if not account_info.empty and bank_name not in account_info["开户行"].values:
  26. account_filter = account_filter & account_params["开户行"].str.contains(bank_name, na=False)
  27. account_info = account_params[account_filter]
  28. if account_info.empty:
  29. messagebox.showerror("错误", f"参数表中未找到{company_name}-{bank_name}的账户信息")
  30. return None
  31. account_code = account_info["编号"].iloc[0]
  32. account_short_name = account_info["简称"].iloc[0]
  33. company_name_full = account_info["公司"].iloc[0]
  34. journal_data = []
  35. for _, row in flow_df.iterrows():
  36. if pd.isna(row["交易时间"]) or str(row["交易时间"]).strip() == "":
  37. continue
  38. income = row["收入"] if pd.notna(row["收入"]) else 0
  39. expense = row["支出"] if pd.notna(row["支出"]) else 0
  40. if income > 0:
  41. shouzhi_type = "收入"
  42. amount = income
  43. elif expense > 0:
  44. shouzhi_type = "支出"
  45. amount = expense
  46. else:
  47. shouzhi_type = ""
  48. amount = 0
  49. try:
  50. date_obj = pd.to_datetime(row["交易时间"], errors='coerce')
  51. month = date_obj.month if pd.notna(date_obj) else ""
  52. except:
  53. month = ""
  54. try:
  55. date_obj = pd.to_datetime(row["交易时间"], errors='coerce')
  56. if pd.notna(date_obj):
  57. formatted_date = f"{date_obj.year}/{date_obj.month}/{date_obj.day}"
  58. else:
  59. formatted_date = row["交易时间"]
  60. except:
  61. formatted_date = row["交易时间"]
  62. opponent_name = str(row["对方户名"]).strip()
  63. is_personal = len(opponent_name) < 5 or "公司" not in opponent_name
  64. if is_personal:
  65. remark = f"{opponent_name}{row['备注']}"
  66. else:
  67. remark = f"{opponent_name}{row['对方开户机构']}"
  68. journal_row = {
  69. "编号": account_code,
  70. "简称": account_short_name,
  71. "企业": company_name_full,
  72. "日期": formatted_date,
  73. "月份": month,
  74. "收支": shouzhi_type,
  75. "资金分类-1级": "",
  76. "资金分类-2级": "",
  77. "资金分类-3级": "",
  78. "对手户": opponent_name,
  79. "备注": remark,
  80. "发生额": amount,
  81. "余额": row["余额"],
  82. "备注.1": ""
  83. }
  84. if (opponent_name in account_params["公司"].values) or (opponent_name in self.settlement_companies):
  85. if income > 0:
  86. journal_row["资金分类-1级"] = "结算收入"
  87. journal_row["资金分类-2级"] = "结算收入"
  88. journal_row["资金分类-3级"] = "结算收入"
  89. else:
  90. journal_row["资金分类-1级"] = "结算支出"
  91. journal_row["资金分类-2级"] = "结算支出"
  92. journal_row["资金分类-3级"] = "结算支出"
  93. elif "手续费" in str(row["摘要"]) or "对公跨行转账汇款手续费" in str(row["摘要"]):
  94. journal_row["资金分类-1级"] = "财务费用"
  95. journal_row["资金分类-2级"] = "财务费用"
  96. journal_row["资金分类-3级"] = "手续费"
  97. journal_row["对手户"] = "手续费"
  98. journal_row["备注"] = "手续费"
  99. elif "会长提现" in str(row["备注"]):
  100. journal_row["资金分类-1级"] = "结算支出"
  101. journal_row["资金分类-2级"] = "结算支出"
  102. journal_row["资金分类-3级"] = "会长提现支付"
  103. else:
  104. journal_row["资金分类-1级"] = "待分类"
  105. journal_row["资金分类-2级"] = "待分类"
  106. journal_row["资金分类-3级"] = "待分类"
  107. journal_data.append(journal_row)
  108. journal_df = pd.DataFrame(journal_data)
  109. journal_columns = [
  110. "编号", "简称", "企业", "日期", "月份", "收支",
  111. "资金分类-1级", "资金分类-2级", "资金分类-3级", "对手户", "备注", "发生额", "余额", "备注.1"
  112. ]
  113. journal_df = journal_df[journal_columns]
  114. return journal_df
  115. def save_journal(self, journal_df, save_path):
  116. """保存日记账到Excel文件"""
  117. try:
  118. from openpyxl.styles import Font
  119. with pd.ExcelWriter(save_path, engine="openpyxl") as writer:
  120. journal_df.to_excel(writer, index=False, sheet_name="日记账")
  121. workbook = writer.book
  122. worksheet = writer.sheets["日记账"]
  123. bold_font = Font(bold=True)
  124. for cell in worksheet[1]:
  125. cell.font = bold_font
  126. return True
  127. except Exception as e:
  128. messagebox.showerror("错误", f"保存日记账失败:{str(e)}")
  129. return False