Pārlūkot izejas kodu

微众银行加功能 了

dongguoliang 2 mēneši atpakaļ
vecāks
revīzija
f8421ffc4e

BIN
__pycache__/abc_parser.cpython-312.pyc


BIN
__pycache__/gui.cpython-312.pyc


BIN
__pycache__/journal_generator.cpython-312.pyc


BIN
__pycache__/parser_factory.cpython-312.pyc


BIN
__pycache__/wechat_parser.cpython-312.pyc


+ 9 - 0
check_wechat_columns.py

@@ -0,0 +1,9 @@
+import pandas as pd
+
+df = pd.read_excel(r'C:\Users\EDY\Desktop\日记账\微众银行(202601)(人民币)交易明细.xlsx', header=1)
+print('所有列名:')
+for i, col in enumerate(df.columns):
+    print(f'{i}: {col}')
+
+print('\n前20行数据:')
+print(df.head(20))

+ 2 - 2
gui.py

@@ -27,14 +27,14 @@ class JournalGeneratorGUI:
         frame_company.pack(fill=tk.X)
         ttk.Label(frame_company, text="公司名称:").pack(side=tk.LEFT)
         company_combo = ttk.Combobox(frame_company, textvariable=self.company_var, state="readonly")
-        company_combo["values"] = ["成都锦高量科科技有限公司", "成都云启寰宇科技有限公司", "成都橙风有量科技有限公司"]
+        company_combo["values"] = ["成都锦高量科科技有限公司", "成都云启寰宇科技有限公司", "成都橙风有量科技有限公司", "绵阳新手游圈科技有限公司"]
         company_combo.pack(side=tk.LEFT, padx=5)
         
         frame_bank = ttk.Frame(self.root, padding="10")
         frame_bank.pack(fill=tk.X)
         ttk.Label(frame_bank, text="开户银行:").pack(side=tk.LEFT)
         bank_combo = ttk.Combobox(frame_bank, textvariable=self.bank_var, state="readonly")
-        bank_combo["values"] = ["建设银行", "中国银行", "农业银行"]
+        bank_combo["values"] = ["建设银行", "中国银行", "农业银行", "微众银行"]
         bank_combo.pack(side=tk.LEFT, padx=5)
         
         frame_param = ttk.Frame(self.root, padding="10")

+ 137 - 124
journal_generator.py

@@ -5,151 +5,164 @@ from tkinter import messagebox
 class JournalGenerator:
     """日记账生成器"""
     
-    def __init__(self, account_param_sheet="账户信息参数", category_param_sheet="收支分类参数"):
-        self.account_param_sheet = account_param_sheet
-        self.category_param_sheet = category_param_sheet
-        self.settlement_companies = ["成都合煦商贸有限公司", "四川泗讯科技有限公司"]
+    def __init__(self):
+        self.param_df = None
+        self.account_info_df = None
+        self.shouzhi_class_df = None
     
     def load_parameter_table(self, param_file_path):
-        """加载参数表,返回账户信息和收支分类"""
+        """加载参数表"""
         try:
-            account_params = pd.read_excel(param_file_path, sheet_name=self.account_param_sheet, header=1)
-            category_params = pd.read_excel(param_file_path, sheet_name=self.category_param_sheet, header=1)
-            return account_params, category_params
+            self.param_df = pd.read_excel(param_file_path, dtype=str)
+            
+            account_info_sheet = pd.read_excel(param_file_path, sheet_name="账户信息参数", dtype=str, header=1)
+            self.account_info_df = account_info_sheet
+            
+            shouzhi_class_sheet = pd.read_excel(param_file_path, sheet_name="收支分类参数", dtype=str, header=1)
+            self.shouzhi_class_df = shouzhi_class_sheet
+            
+            return True
         except Exception as e:
             messagebox.showerror("错误", f"加载参数表失败:{str(e)}")
-            return None, None
+            return False
     
-    def generate_journal_data(self, company_name, bank_name, param_file, flow_df):
-        """核心:生成日记账数据"""
-        account_params, category_params = self.load_parameter_table(param_file)
-        if account_params is None:
+    def generate_journal_data(self, company_name, bank_name, param_file_path, flow_df):
+        """生成日记账数据"""
+        if not self.load_parameter_table(param_file_path):
             return None
         
-        account_filter = account_params["公司"] == company_name
-        account_info = account_params[account_filter]
-        
-        if not account_info.empty and bank_name not in account_info["开户行"].values:
-            account_filter = account_filter & account_params["开户行"].str.contains(bank_name, na=False)
-            account_info = account_params[account_filter]
-        
-        if account_info.empty:
-            messagebox.showerror("错误", f"参数表中未找到{company_name}-{bank_name}的账户信息")
-            return None
-        
-        account_code = account_info["编号"].iloc[0]
-        account_short_name = account_info["简称"].iloc[0]
-        company_name_full = account_info["公司"].iloc[0]
-        
-        journal_data = []
-        for _, row in flow_df.iterrows():
-            if pd.isna(row["交易时间"]) or str(row["交易时间"]).strip() == "":
-                continue
+        try:
+            bank_keyword_mapping = {
+                "微众银行": "微众",
+                "中国银行": "中国银行",
+                "农业银行": "农业银行",
+                "建设银行": "建设银行"
+            }
+            
+            bank_keyword = bank_keyword_mapping.get(bank_name, bank_name)
+            
+            company_accounts = self.account_info_df[self.account_info_df["公司"] == company_name]
+            
+            account_info = None
+            for _, account in company_accounts.iterrows():
+                if bank_keyword in account["开户行"]:
+                    account_info = company_accounts[company_accounts.index == account.name]
+                    break
             
-            income = row["收入"] if pd.notna(row["收入"]) else 0
-            expense = row["支出"] if pd.notna(row["支出"]) else 0
+            if account_info is None or account_info.empty:
+                messagebox.showerror("错误", f"未找到账户信息:{company_name} - {bank_name}")
+                return None
             
-            if income > 0:
-                shouzhi_type = "收入"
-                amount = income
-            elif expense > 0:
-                shouzhi_type = "支出"
-                amount = expense
-            else:
-                shouzhi_type = ""
-                amount = 0
+            account_code = account_info["编号"].values[0]
+            account_short_name = account_info["简称"].values[0]
+            company_name_full = account_info["公司"].values[0]
             
-            try:
-                date_obj = pd.to_datetime(row["交易时间"], errors='coerce')
-                month = date_obj.month if pd.notna(date_obj) else ""
-            except:
-                month = ""
+            journal_data = []
             
-            try:
-                date_obj = pd.to_datetime(row["交易时间"], errors='coerce')
-                if pd.notna(date_obj):
-                    formatted_date = f"{date_obj.year}/{date_obj.month}/{date_obj.day}"
+            for _, row in flow_df.iterrows():
+                transaction_time = row["交易时间"]
+                opponent_name = str(row["对方户名"]).strip()
+                summary = str(row["摘要"]).strip()
+                income = pd.to_numeric(row["收入"], errors="coerce")
+                expense = pd.to_numeric(row["支出"], errors="coerce")
+                balance = str(row["余额"]).strip()
+                
+                if pd.isna(income):
+                    income = 0
+                if pd.isna(expense):
+                    expense = 0
+                
+                if income == 0 and expense == 0:
+                    continue
+                
+                amount = income if income > 0 else expense
+                shouzhi_type = "收入" if income > 0 else "支出"
+                
+                try:
+                    transaction_date = pd.to_datetime(transaction_time, errors="coerce")
+                    if pd.isna(transaction_date):
+                        continue
+                    formatted_date = f"{transaction_date.year}/{transaction_date.month}/{transaction_date.day}"
+                    month = str(transaction_date.month)
+                except:
+                    continue
+                
+                opponent_bank = str(row.get("对方开户机构", "")).strip()
+                flow_remark = str(row.get("备注", "")).strip()
+                
+                is_settlement = False
+                if opponent_name in self.account_info_df["公司"].values:
+                    is_settlement = True
+                
+                if is_settlement:
+                    if income > 0:
+                        fund_level1 = "结算收入"
+                        fund_level2 = "结算收入"
+                        fund_level3 = "结算收入"
+                    else:
+                        fund_level1 = "结算支出"
+                        fund_level2 = "结算支出"
+                        fund_level3 = "结算支出"
+                elif "会长提现" in flow_remark or "提现" in flow_remark:
+                        fund_level1 = "游戏业务"
+                        fund_level2 = "结算支出"
+                        fund_level3 = "会长提现支付"
+                elif "手续费" in summary or "服务费" in summary:
+                    fund_level1 = "财务费用"
+                    fund_level2 = "财务费用"
+                    fund_level3 = "手续费"
+                else:
+                    fund_level1 = ""
+                    fund_level2 = ""
+                    fund_level3 = ""
+                
+                if "手续费" in summary or "服务费" in summary:
+                    opponent_name = "手续费"
+                    remark = "手续费"
+                elif "会长提现" in flow_remark or "提现" in flow_remark:
+                    remark = opponent_name + flow_remark
                 else:
-                    formatted_date = row["交易时间"]
-            except:
-                formatted_date = row["交易时间"]
+                    remark = opponent_name + opponent_bank
+                
+                journal_row = {
+                    "编号": account_code,
+                    "简称": account_short_name,
+                    "企业": company_name_full,
+                    "日期": formatted_date,
+                    "月份": month,
+                    "收支": shouzhi_type,
+                    "资金分类-1级": fund_level1,
+                    "资金分类-2级": fund_level2,
+                    "资金分类-3级": fund_level3,
+                    "对手户": opponent_name,
+                    "备注": remark,
+                    "发生额": amount,
+                    "余额": balance,
+                    "备注.1": ""
+                }
+                
+                journal_data.append(journal_row)
             
-            opponent_name = str(row["对方户名"]).strip()
-            is_personal = len(opponent_name) < 5 or "公司" not in opponent_name
+            if not journal_data:
+                messagebox.showwarning("警告", "未生成任何日记账数据")
+                return None
             
-            if is_personal:
-                remark = f"{opponent_name}{row['备注']}"
-            else:
-                remark = f"{opponent_name}{row['对方开户机构']}"
+            journal_df = pd.DataFrame(journal_data)
             
-            journal_row = {
-                "编号": account_code,
-                "简称": account_short_name,
-                "企业": company_name_full,
-                "日期": formatted_date,
-                "月份": month,
-                "收支": shouzhi_type,
-                "资金分类-1级": "",
-                "资金分类-2级": "",
-                "资金分类-3级": "",
-                "对手户": opponent_name,
-                "备注": remark,
-                "发生额": amount,
-                "余额": row["余额"],
-                "备注.1": ""
-            }
+            column_order = ["编号", "简称", "企业", "日期", "月份", "收支", "资金分类-1级", 
+                          "资金分类-2级", "资金分类-3级", "对手户", "备注", "发生额", "余额", "备注.1"]
+            journal_df = journal_df[column_order]
             
-            if (opponent_name in account_params["公司"].values) or (opponent_name in self.settlement_companies):
-                if income > 0:
-                    journal_row["资金分类-1级"] = "结算收入"
-                    journal_row["资金分类-2级"] = "结算收入"
-                    journal_row["资金分类-3级"] = "结算收入"
-                else:
-                    journal_row["资金分类-1级"] = "结算支出"
-                    journal_row["资金分类-2级"] = "结算支出"
-                    journal_row["资金分类-3级"] = "结算支出"
-            elif "手续费" in str(row["摘要"]) or "对公跨行转账汇款手续费" in str(row["摘要"]):
-                journal_row["资金分类-1级"] = "财务费用"
-                journal_row["资金分类-2级"] = "财务费用"
-                journal_row["资金分类-3级"] = "手续费"
-                journal_row["对手户"] = "手续费"
-                journal_row["备注"] = "手续费"
-            elif "会长提现" in str(row["备注"]):
-                journal_row["资金分类-1级"] = "结算支出"
-                journal_row["资金分类-2级"] = "结算支出"
-                journal_row["资金分类-3级"] = "会长提现支付"
-            else:
-                journal_row["资金分类-1级"] = "待分类"
-                journal_row["资金分类-2级"] = "待分类"
-                journal_row["资金分类-3级"] = "待分类"
+            return journal_df
             
-            journal_data.append(journal_row)
-        
-        journal_df = pd.DataFrame(journal_data)
-        journal_columns = [
-            "编号", "简称", "企业", "日期", "月份", "收支",
-            "资金分类-1级", "资金分类-2级", "资金分类-3级", "对手户", "备注", "发生额", "余额", "备注.1"
-        ]
-        journal_df = journal_df[journal_columns]
-        
-        return journal_df
+        except Exception as e:
+            messagebox.showerror("错误", f"生成日记账数据失败:{str(e)}")
+            return None
     
     def save_journal(self, journal_df, save_path):
-        """保存日记账到Excel文件"""
+        """保存日记账"""
         try:
-            from openpyxl.styles import Font
-            
-            with pd.ExcelWriter(save_path, engine="openpyxl") as writer:
-                journal_df.to_excel(writer, index=False, sheet_name="日记账")
-                
-                workbook = writer.book
-                worksheet = writer.sheets["日记账"]
-                
-                bold_font = Font(bold=True)
-                
-                for cell in worksheet[1]:
-                    cell.font = bold_font
-            
+            journal_df.to_excel(save_path, index=False)
             return True
         except Exception as e:
             messagebox.showerror("错误", f"保存日记账失败:{str(e)}")

+ 3 - 1
parser_factory.py

@@ -1,6 +1,7 @@
 from ccb_parser import CCBFlowParser
 from boc_parser import BOCFlowParser
 from abc_parser import ABCFlowParser
+from wechat_parser import WeChatFlowParser
 
 
 class ParserFactory:
@@ -10,7 +11,8 @@ class ParserFactory:
         self.parsers = {
             "建设银行": CCBFlowParser(),
             "中国银行": BOCFlowParser(),
-            "农业银行": ABCFlowParser()
+            "农业银行": ABCFlowParser(),
+            "微众银行": WeChatFlowParser()
         }
     
     def get_parser(self, bank_name):

+ 61 - 0
wechat_parser.py

@@ -0,0 +1,61 @@
+import pandas as pd
+from tkinter import messagebox
+from flow_parser_base import FlowParserBase
+
+
+class WeChatFlowParser(FlowParserBase):
+    """微众银行流水解析器"""
+    
+    def parse(self, flow_file_path):
+        """解析微众银行流水文件,返回标准化的流水数据"""
+        try:
+            flow_df = pd.read_excel(flow_file_path, dtype=str, header=1)
+            
+            flow_df.columns = flow_df.columns.str.strip()
+            
+            required_columns = ["流水号", "交易时间", "借", "贷", "账户余额", "对方姓名", "对方账号开户行", "备注"]
+            
+            missing_fields = [k for k in required_columns if k not in flow_df.columns]
+            if missing_fields:
+                messagebox.showerror("错误", f"微众银行流水缺少必要列:{missing_fields}")
+                return None
+            
+            flow_df["交易时间"] = pd.to_datetime(flow_df["交易时间"], errors='coerce')
+            flow_df = flow_df.sort_values("交易时间", ascending=True)
+            
+            standard_flow = []
+            for _, row in flow_df.iterrows():
+                transaction_time = row["交易时间"]
+                debit_str = str(row["借"]).strip()
+                credit_str = str(row["贷"]).strip()
+                debit_amount = pd.to_numeric(debit_str.replace(',', ''), errors='coerce') if debit_str != 'nan' else 0
+                credit_amount = pd.to_numeric(credit_str.replace(',', ''), errors='coerce') if credit_str != 'nan' else 0
+                balance = str(row["账户余额"]).strip()
+                opponent_name = str(row["对方姓名"]).strip()
+                opponent_bank = str(row["对方账号开户行"]).strip()
+                summary = str(row["备注"]).strip()
+                
+                expense = debit_amount if pd.notna(debit_amount) and debit_amount > 0 else 0
+                income = credit_amount if pd.notna(credit_amount) and credit_amount > 0 else 0
+                
+                transaction_time_str = transaction_time.strftime("%Y-%m-%d %H:%M:%S") if pd.notna(transaction_time) else ""
+                
+                standard_flow.append({
+                    "交易时间": transaction_time_str,
+                    "对方户名": opponent_name,
+                    "摘要": summary,
+                    "收入": income,
+                    "支出": expense,
+                    "对方开户机构": opponent_bank,
+                    "备注": opponent_bank,
+                    "余额": balance
+                })
+            
+            return pd.DataFrame(standard_flow)
+        except Exception as e:
+            messagebox.showerror("错误", f"解析微众银行流水失败:{str(e)}")
+            return None
+    
+    def get_bank_name(self):
+        """返回银行名称"""
+        return "微众银行"