dongguoliang пре 2 месеци
родитељ
комит
20d0acd730

+ 1 - 0
.gitignore

@@ -1,2 +1,3 @@
 build/
 dist/
+__pycache__/

BIN
__pycache__/fund_classification_rules.cpython-312.pyc


BIN
__pycache__/gui.cpython-312.pyc


BIN
__pycache__/journal_generator.cpython-312.pyc


BIN
__pycache__/parser_factory.cpython-312.pyc


+ 8 - 0
check_nongxin.py

@@ -0,0 +1,8 @@
+import pandas as pd
+
+df = pd.read_excel('C:\\Users\\EDY\\Desktop\\日记账1月\\新手游农信.xls')
+print('列名:', df.columns.tolist())
+print('\n前10行:')
+print(df.head(10))
+print('\n数据类型:')
+print(df.dtypes)

+ 5 - 0
check_nongxin_detail.py

@@ -0,0 +1,5 @@
+import pandas as pd
+
+df = pd.read_excel('C:\\Users\\EDY\\Desktop\\日记账1月\\新手游农信.xls', header=None)
+print('完整数据:')
+print(df.to_string())

+ 10 - 0
check_nongxin_v3.py

@@ -0,0 +1,10 @@
+import pandas as pd
+
+df = pd.read_excel('C:\\Users\\EDY\\Desktop\\日记账1月\\新手游农信.xls', header=None)
+print('数据形状:', df.shape)
+print('\n前20行:')
+for idx in range(min(20, len(df))):
+    print(f'\n行 {idx}:')
+    for col_idx in range(min(10, len(df.columns))):
+        val = df.iloc[idx, col_idx]
+        print(f'  列{col_idx}: {val}')

+ 3 - 3
check_params.py

@@ -1,5 +1,5 @@
 import pandas as pd
 
-df = pd.read_excel(r'D:\project\caiwu\rijizhang\参数表.xlsx', sheet_name='账户信息参数', header=1)
-print('参数表中的公司列表:')
-print(df['公司'].tolist())
+df = pd.read_excel('参数表.xlsx', sheet_name='收支分类参数', dtype=str, header=1)
+print('所有行:')
+print(df)

+ 56 - 1
fund_classification_rules.py

@@ -122,6 +122,56 @@ class PendingSettlementRule(FundClassificationRule):
         return {"level1": "游戏业务", "level2": "会长收款", "level3": "个人会长充值"}
 
 
+class NongxinMerchant238Rule(FundClassificationRule):
+    """农信银行商户238165993385171入账规则"""
+    
+    def match(self, context):
+        return "商户238165993385171入账" in context["summary"] or "商户238165993385171入账" in context["opponent_name"]
+    
+    def apply(self, context):
+        return {"level1": "游戏业务", "level2": "会长收款", "level3": "个人会长充值"}
+
+
+class NongxinFeeRule(FundClassificationRule):
+    """农信银行手续费规则"""
+    
+    def match(self, context):
+        return "手续费" in context["summary"]
+    
+    def apply(self, context):
+        return {"level1": "财务费用", "level2": "财务费用", "level3": "手续费"}
+
+
+class NongxinYilianRule(FundClassificationRule):
+    """农信银行易练规则"""
+    
+    def match(self, context):
+        return "易练" in context["summary"]
+    
+    def apply(self, context):
+        return {"level1": "易练结算", "level2": "易练结算", "level3": "易练推广支付"}
+
+
+class NongxinLoanRule(FundClassificationRule):
+    """农信银行贷款规则"""
+    
+    def match(self, context):
+        return "贷款" in context["summary"]
+    
+    def apply(self, context):
+        return {"level1": "贷款支出", "level2": "贷款支出", "level3": "贷款支出"}
+
+
+class NongxinMerchant238ExpenseRule(FundClassificationRule):
+    """农信银行商户238165993385171入账支出规则"""
+    
+    def match(self, context):
+        return "商户238165993385171入账" in context["opponent_name"]
+    
+    def apply(self, context):
+        return {"level1": "日常管理", "level2": "日常管理", "level3": "法务费"}
+
+
 def get_classification_rules():
     """
     获取所有资金分类规则列表
@@ -137,5 +187,10 @@ def get_classification_rules():
         YilianRule(),
         FeeRule(),
         CloudServiceRule(),
-        PendingSettlementRule()
+        PendingSettlementRule(),
+        NongxinMerchant238Rule(),
+        NongxinFeeRule(),
+        NongxinYilianRule(),
+        NongxinLoanRule(),
+        NongxinMerchant238ExpenseRule()
     ]

+ 1 - 1
gui.py

@@ -37,7 +37,7 @@ class JournalGeneratorGUI:
         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")

+ 2 - 1
journal_generator.py

@@ -38,7 +38,8 @@ class JournalGenerator:
                 "微众银行": "微众",
                 "中国银行": "中国银行",
                 "农业银行": "农业银行",
-                "建设银行": "建设银行"
+                "建设银行": "建设银行",
+                "农信银行": "小枧支行"
             }
             
             bank_keyword = bank_keyword_mapping.get(bank_name, bank_name)

+ 68 - 0
nongxin_parser.py

@@ -0,0 +1,68 @@
+import pandas as pd
+from tkinter import messagebox
+from flow_parser_base import FlowParserBase
+
+
+class NongxinFlowParser(FlowParserBase):
+    """农信银行流水解析器"""
+    
+    def parse(self, flow_file_path):
+        """解析农信银行流水文件,返回标准化的流水数据"""
+        try:
+            flow_df = pd.read_excel(flow_file_path, header=None)
+            
+            flow_data = []
+            
+            for idx, row in flow_df.iterrows():
+                if idx < 3:
+                    continue
+                    
+                if pd.isna(row[0]) or str(row[0]).strip() == '':
+                    continue
+                    
+                try:
+                    date_part = str(row[0]).strip()
+                    time_part = str(row[1]).strip()
+                    transaction_time = f"{date_part} {time_part}"
+                    
+                    shouzhi_type = str(row[2]).strip()
+                    
+                    income_amount = pd.to_numeric(row[3], errors='coerce')
+                    expense_amount = pd.to_numeric(row[4], errors='coerce')
+                    
+                    if pd.isna(income_amount):
+                        income_amount = 0
+                    if pd.isna(expense_amount):
+                        expense_amount = 0
+                    
+                    balance = str(row[5]).strip() if not pd.isna(row[5]) else ''
+                    opponent_name = str(row[6]).strip() if not pd.isna(row[6]) else ''
+                    opponent_bank = str(row[8]).strip() if not pd.isna(row[8]) else ''
+                    summary = str(row[9]).strip() if not pd.isna(row[9]) else ''
+                    
+                    if income_amount > 0 or expense_amount > 0:
+                        flow_data.append({
+                            "交易时间": transaction_time,
+                            "对方户名": opponent_name,
+                            "摘要": summary,
+                            "收入": income_amount,
+                            "支出": expense_amount,
+                            "余额": balance
+                        })
+                except Exception as e:
+                    continue
+            
+            if not flow_data:
+                messagebox.showerror("错误", "农信银行流水解析失败:未找到有效数据")
+                return None
+            
+            standard_flow = pd.DataFrame(flow_data)
+            
+            return standard_flow
+        except Exception as e:
+            messagebox.showerror("错误", f"解析农信银行流水失败:{str(e)}")
+            return None
+    
+    def get_bank_name(self):
+        """返回银行名称"""
+        return "农信银行"

+ 3 - 1
parser_factory.py

@@ -2,6 +2,7 @@ from ccb_parser import CCBFlowParser
 from boc_parser import BOCFlowParser
 from abc_parser import ABCFlowParser
 from wechat_parser import WeChatFlowParser
+from nongxin_parser import NongxinFlowParser
 
 
 class ParserFactory:
@@ -12,7 +13,8 @@ class ParserFactory:
             "建设银行": CCBFlowParser(),
             "中国银行": BOCFlowParser(),
             "农业银行": ABCFlowParser(),
-            "微众银行": WeChatFlowParser()
+            "微众银行": WeChatFlowParser(),
+            "农信银行": NongxinFlowParser()
         }
     
     def get_parser(self, bank_name):

+ 16 - 0
test_nongxin.py

@@ -0,0 +1,16 @@
+from parser_factory import ParserFactory
+from journal_generator import JournalGenerator
+
+pf = ParserFactory()
+parser = pf.get_parser('农信银行')
+print('农信银行解析器:', parser)
+print('银行名称:', parser.get_bank_name())
+
+flow_df = parser.parse('C:\\Users\\EDY\\Desktop\\日记账1月\\新手游农信.xls')
+print('解析成功,流水数据:')
+print(flow_df.head())
+
+jg = JournalGenerator()
+journal_df = jg.generate_journal_data('绵阳新手游科技技术有限公司', '农信银行', '参数表.xlsx', flow_df)
+print('\n日记账数据:')
+print(journal_df[['日期', '月份', '收支', '资金分类-1级', '资金分类-2级', '资金分类-3级', '对手户', '备注']].head(10))

+ 28 - 0
test_nongxin_v2.py

@@ -0,0 +1,28 @@
+from parser_factory import ParserFactory
+from journal_generator import JournalGenerator
+
+pf = ParserFactory()
+parser = pf.get_parser('农信银行')
+print('农信银行解析器:', parser)
+print('银行名称:', parser.get_bank_name())
+
+try:
+    flow_df = parser.parse('C:\\Users\\EDY\\Desktop\\日记账1月\\新手游农信.xls')
+    if flow_df is not None:
+        print('解析成功,流水数据:')
+        print(flow_df.head())
+        print('\n数据形状:', flow_df.shape)
+        
+        jg = JournalGenerator()
+        journal_df = jg.generate_journal_data('绵阳新手游科技技术有限公司', '农信银行', '参数表.xlsx', flow_df)
+        if journal_df is not None:
+            print('\n日记账数据:')
+            print(journal_df[['日期', '月份', '收支', '资金分类-1级', '资金分类-2级', '资金分类-3级', '对手户', '备注']].head(10))
+        else:
+            print('日记账生成失败')
+    else:
+        print('流水解析失败')
+except Exception as e:
+    print('发生错误:', str(e))
+    import traceback
+    traceback.print_exc()

+ 29 - 0
test_nongxin_v3.py

@@ -0,0 +1,29 @@
+from parser_factory import ParserFactory
+from journal_generator import JournalGenerator
+
+pf = ParserFactory()
+parser = pf.get_parser('农信银行')
+print('农信银行解析器:', parser)
+print('银行名称:', parser.get_bank_name())
+
+try:
+    flow_df = parser.parse('C:\\Users\\EDY\\Desktop\\日记账1月\\新手游农信.xls')
+    if flow_df is not None:
+        print('解析成功,流水数据:')
+        print(flow_df[['交易时间', '对方户名', '摘要', '收入', '支出', '余额']].head(10))
+        print('\n数据形状:', flow_df.shape)
+        
+        jg = JournalGenerator()
+        journal_df = jg.generate_journal_data('绵阳新手游科技技术有限公司', '农信银行', '参数表.xlsx', flow_df)
+        if journal_df is not None:
+            print('\n日记账数据形状:', journal_df.shape)
+            print('\n前10行日记账:')
+            print(journal_df[['日期', '月份', '收支', '资金分类-1级', '资金分类-2级', '资金分类-3级', '对手户', '备注']].head(10).to_string())
+        else:
+            print('日记账生成失败')
+    else:
+        print('流水解析失败')
+except Exception as e:
+    print('发生错误:', str(e))
+    import traceback
+    traceback.print_exc()