import psycopg2 conn = psycopg2.connect( host="192.168.0.61", port=55432, database="njts_acct", user="njts_app", password="njts_app2025" ) cur = conn.cursor() print("=" * 140) print("【识别可能的6月→7月/8月复制数据】") print("=" * 140) # 第1步:找出6月所有有的仕訳(描述+金额的组合) print("\n第1步:提取6月的所有仕訳(描述和金额作为KEY)") cur.execute(""" SELECT DISTINCT je.description, COALESCE(SUM(jl.debit), 0)::BIGINT as total_debit, COALESCE(SUM(jl.credit), 0)::BIGINT as total_credit FROM journal_entries je LEFT JOIN journal_lines jl ON je.journal_entry_id = jl.journal_entry_id WHERE je.is_deleted = false AND je.is_latest = true AND EXTRACT(YEAR FROM je.entry_date) = 2025 AND EXTRACT(MONTH FROM je.entry_date) = 6 GROUP BY je.journal_entry_id, je.description ORDER BY je.description """) june_patterns = cur.fetchall() print(f"找到 {len(june_patterns)} 个6月的仕訳模式") # 第2步:在7月和8月中查找相同的仕訳 print("\n第2步:在7月和8月中查找相同描述和金额的仕訳") duplicates_for_deletion = [] for description, debit, credit in june_patterns: cur.execute(""" SELECT je.journal_entry_id, TO_CHAR(je.entry_date, 'YYYY-MM-DD') as entry_date, EXTRACT(MONTH FROM je.entry_date)::INT as month, COALESCE(SUM(jl.debit), 0)::BIGINT as calc_debit, COALESCE(SUM(jl.credit), 0)::BIGINT as calc_credit FROM journal_entries je LEFT JOIN journal_lines jl ON je.journal_entry_id = jl.journal_entry_id WHERE je.is_deleted = false AND je.is_latest = true AND EXTRACT(YEAR FROM je.entry_date) = 2025 AND EXTRACT(MONTH FROM je.entry_date) IN (7, 8) AND je.description = %s GROUP BY je.journal_entry_id, je.entry_date HAVING COALESCE(SUM(jl.debit), 0) = %s AND COALESCE(SUM(jl.credit), 0) = %s """, (description, debit, credit)) matches = cur.fetchall() if matches: for entry_id, entry_date, month, calc_debit, calc_credit in matches: duplicates_for_deletion.append({ 'entry_id': entry_id, 'date': entry_date, 'month': month, 'description': description, 'debit': debit, 'credit': credit }) # 按月份排序 duplicates_for_deletion.sort(key=lambda x: (x['month'], x['entry_id'])) print(f"\n找到 {len(duplicates_for_deletion)} 个可能的复制记录(7月/8月中与6月相同的)") if duplicates_for_deletion: print("\n【可能的复制记录列表】\n") current_month = None for dup in duplicates_for_deletion: if dup['month'] != current_month: print(f"\n--- {dup['month']}月 ---") current_month = dup['month'] print(f"ID={dup['entry_id']:3d} | {dup['date']} | 借={dup['debit']:>12,} 貸={dup['credit']:>12,}") print(f" └─ {dup['description'][:80]}") print("\n" + "=" * 140) print(f"【预期删除】{len(duplicates_for_deletion)} 条记录") print("=" * 140) # 计算删除前后的普通預金期末残高变化 cur.execute(""" SELECT COALESCE(SUM(COALESCE(jl.debit, 0) - COALESCE(jl.credit, 0)), 0) as balance FROM journal_lines jl INNER JOIN journal_entries je ON jl.journal_entry_id = je.journal_entry_id WHERE jl.account_id = 2 -- 普通預金 AND je.is_deleted = false AND je.is_latest = true """) current_balance = cur.fetchone()[0] print(f"\n删除前普通預金期末残高: {current_balance:>15,.0f}円") # 计算这些重复记录对普通預金的影响 deletion_impact = 0 for dup in duplicates_for_deletion: cur.execute(""" SELECT COALESCE(SUM(COALESCE(jl.debit, 0) - COALESCE(jl.credit, 0)), 0) FROM journal_lines jl WHERE jl.journal_entry_id = %s AND jl.account_id = 2 -- 普通預金 """, (dup['entry_id'],)) impact = cur.fetchone()[0] deletion_impact += impact expected_balance_after = current_balance - deletion_impact print(f"这些记录对普通預金的总影响: {deletion_impact:>15,.0f}円") print(f"删除后预期普通預金期末残高: {expected_balance_after:>15,.0f}円") print(f"\n期望目标值: 14,916,322円") print(f"删除后vs目标值差距: {14_916_322 - expected_balance_after:>15,.0f}円") cur.close() conn.close() # 保存删除列表到Python变量以供后续使用 print("\n" + "=" * 140) print(f"识别完成。找到 {len(duplicates_for_deletion)} 条可能的复制记录") print("=" * 140) # 返回delete_list供后续使用 import json print("\n【识别的删除对象IDs】") delete_ids = [dup['entry_id'] for dup in duplicates_for_deletion] print(delete_ids)