Files
njts-accounting-core/check_data_integrity.py
2026-02-20 15:47:27 +09:00

150 lines
6.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()