150 lines
6.4 KiB
Python
150 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
検查和清理逆仕訳データと不正なis_latest標記
|
||
"""
|
||
import psycopg
|
||
from psycopg.rows import dict_row
|
||
|
||
def check_and_cleanup():
|
||
try:
|
||
conn = psycopg.connect(
|
||
host="127.0.0.1",
|
||
port=5432,
|
||
dbname="njts_accounting",
|
||
user="postgres",
|
||
password="postgres",
|
||
connect_timeout=3
|
||
)
|
||
|
||
with conn:
|
||
with conn.cursor(row_factory=dict_row) as cur:
|
||
print("=" * 80)
|
||
print("【ステップ1】逆仕訳データの検出")
|
||
print("=" * 80)
|
||
|
||
# 検査是否存在通过反向分录来处理修改的数据
|
||
cur.execute("""
|
||
SELECT
|
||
j1.journal_entry_id as original_id,
|
||
j1.description as original_desc,
|
||
j1.entry_date as original_date,
|
||
j2.journal_entry_id as reverse_id,
|
||
j2.description as reverse_desc,
|
||
j2.entry_date as reverse_date
|
||
FROM journal_entries j1
|
||
JOIN journal_lines l1 ON l1.journal_entry_id = j1.journal_entry_id
|
||
JOIN journal_entries j2 ON j1.journal_entry_id = j2.parent_entry_id
|
||
JOIN journal_lines l2 ON l2.journal_entry_id = j2.journal_entry_id
|
||
AND l2.account_id = l1.account_id
|
||
AND l2.debit = l1.credit
|
||
AND l2.credit = l1.debit
|
||
WHERE j1.is_deleted = false
|
||
AND j2.is_deleted = false
|
||
GROUP BY j1.journal_entry_id, j1.description, j1.entry_date,
|
||
j2.journal_entry_id, j2.description, j2.entry_date
|
||
LIMIT 20
|
||
""")
|
||
|
||
reverse_entries = cur.fetchall()
|
||
if reverse_entries:
|
||
print(f"見つかった逆仕訳ペア: {len(reverse_entries)}")
|
||
for entry in reverse_entries:
|
||
print(f" 元:ID={entry['original_id']} ({entry['original_desc']}) {entry['original_date']}")
|
||
print(f" 逆:ID={entry['reverse_id']} ({entry['reverse_desc']}) {entry['reverse_date']}")
|
||
else:
|
||
print("逆仕訳ペアが見つかりません")
|
||
|
||
print()
|
||
print("=" * 80)
|
||
print("【ステップ2】is_latest=false だけど修正鎖に含まれない孤立記録")
|
||
print("=" * 80)
|
||
|
||
cur.execute("""
|
||
SELECT
|
||
journal_entry_id,
|
||
description,
|
||
is_latest,
|
||
is_deleted,
|
||
parent_entry_id,
|
||
original_entry_id,
|
||
entry_date
|
||
FROM journal_entries
|
||
WHERE is_latest = false
|
||
AND (original_entry_id IS NULL AND parent_entry_id IS NULL)
|
||
AND is_deleted = false
|
||
LIMIT 20
|
||
""")
|
||
|
||
orphan_entries = cur.fetchall()
|
||
if orphan_entries:
|
||
print(f"孤立記録が見つかりました: {len(orphan_entries)}")
|
||
for entry in orphan_entries:
|
||
print(f" ID={entry['journal_entry_id']}: {entry['description']} (date={entry['entry_date']})")
|
||
else:
|
||
print("孤立記録が見つかりません")
|
||
|
||
print()
|
||
print("=" * 80)
|
||
print("【ステップ3】修正鎖の整体性確認")
|
||
print("=" * 80)
|
||
|
||
# 检查是否有parent_entry_id指向不存在的記録
|
||
cur.execute("""
|
||
SELECT
|
||
je.journal_entry_id,
|
||
je.parent_entry_id,
|
||
je.description
|
||
FROM journal_entries je
|
||
LEFT JOIN journal_entries parent ON parent.journal_entry_id = je.parent_entry_id
|
||
WHERE je.parent_entry_id IS NOT NULL
|
||
AND parent.journal_entry_id IS NULL
|
||
LIMIT 20
|
||
""")
|
||
|
||
broken_links = cur.fetchall()
|
||
if broken_links:
|
||
print(f"破损されたリンク が見つかりました: {len(broken_links)}")
|
||
for entry in broken_links:
|
||
print(f" ID={entry['journal_entry_id']}: 削除されたparen_entry_id={entry['parent_entry_id']}")
|
||
else:
|
||
print("破损されたリンクが見つかりません")
|
||
|
||
print()
|
||
print("=" * 80)
|
||
print("【ステップ4】修正被修改的还有没有更新成正确is_latest的记录")
|
||
print("=" * 80)
|
||
|
||
# 检查是否有多个is_latest=true在同一修正鎖中
|
||
cur.execute("""
|
||
SELECT
|
||
original_entry_id,
|
||
COUNT(*) as total_count,
|
||
SUM(CASE WHEN is_latest = true THEN 1 ELSE 0 END) as latest_count,
|
||
SUM(CASE WHEN is_latest = false THEN 1 ELSE 0 END) as old_count
|
||
FROM journal_entries
|
||
WHERE original_entry_id IS NOT NULL
|
||
GROUP BY original_entry_id
|
||
HAVING SUM(CASE WHEN is_latest = true THEN 1 ELSE 0 END) != 1
|
||
""")
|
||
|
||
bad_chains = cur.fetchall()
|
||
if bad_chains:
|
||
print(f"不正合な修正鎖が見つかりました: {len(bad_chains)}")
|
||
for chain in bad_chains:
|
||
print(f" original_id={chain['original_entry_id']}: 合計={chain['total_count']}, latest={chain['latest_count']}, old={chain['old_count']}")
|
||
else:
|
||
print("正常な修正鎖のみです")
|
||
|
||
conn.close()
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"エラー: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
if __name__ == "__main__":
|
||
check_and_cleanup()
|