This commit is contained in:
admin
2026-01-16 09:50:21 +09:00
parent 24c04e0d29
commit d8ec60629e
18 changed files with 941 additions and 22 deletions

View File

@@ -8,7 +8,13 @@ SELECT
FROM journal_lines l
JOIN journal_entries j
ON j.journal_id = l.journal_id
LEFT JOIN journal_entries child
ON child.parent_entry_id = j.journal_id
WHERE l.account_id = %(account_id)s
AND j.journal_date BETWEEN %(date_from)s AND %(date_to)s
-- 逆仕訳を除外
AND j.description NOT LIKE '[逆仕訳]%'
-- 子仕訳(修正後仕訳)を持つ修正前の仕訳を除外
AND child.journal_id IS NULL
ORDER BY j.journal_date, l.line_id;
"""

View File

@@ -64,8 +64,14 @@ def get_general_ledger(
FROM journal_entries j
JOIN journal_lines l
ON l.journal_id = j.journal_id
LEFT JOIN journal_entries child
ON child.parent_entry_id = j.journal_id
WHERE l.account_id = %s
AND j.journal_date BETWEEN %s AND %s
-- 逆仕訳を除外
AND j.description NOT LIKE '[逆仕訳]%'
-- 子仕訳(修正後仕訳)を持つ修正前の仕訳を除外
AND child.journal_id IS NULL
ORDER BY j.journal_date, l.line_id
""", (account_id, date_from, date_to))

View File

@@ -60,14 +60,19 @@ def fetch_trial_balance(date_from: str, date_to: str):
opening_balance_from_table = D(ob_row["ob"]) if ob_row else D(0)
# date_from より前の仕訳による増減
# 修正された仕訳(親となった仕訳)は除外
cur.execute("""
SELECT COALESCE(SUM(l.debit - l.credit), 0) AS opening
FROM journal_lines l
JOIN journal_entries j
ON j.journal_entry_id = l.journal_entry_id
LEFT JOIN journal_entries child
ON child.parent_entry_id = j.journal_entry_id
WHERE l.account_id = %s
AND j.entry_date < %s
AND j.is_deleted = false
AND j.description NOT LIKE '[逆仕訳]%%'
AND child.journal_entry_id IS NULL
""", (aid, date_from))
opening_from_journals = D(cur.fetchone()["opening"])
@@ -75,6 +80,7 @@ def fetch_trial_balance(date_from: str, date_to: str):
opening = opening_balance_from_table + opening_from_journals
# 当期増減date_from date_to
# 修正された仕訳(親となった仕訳)は除外
cur.execute("""
SELECT
COALESCE(SUM(l.debit), 0) AS debit,
@@ -82,9 +88,13 @@ def fetch_trial_balance(date_from: str, date_to: str):
FROM journal_lines l
JOIN journal_entries j
ON j.journal_entry_id = l.journal_entry_id
LEFT JOIN journal_entries child
ON child.parent_entry_id = j.journal_entry_id
WHERE l.account_id = %s
AND j.entry_date BETWEEN %s AND %s
AND j.is_deleted = false
AND j.description NOT LIKE '[逆仕訳]%%'
AND child.journal_entry_id IS NULL
""", (aid, date_from, date_to))
row = cur.fetchone()
debit = D(row["debit"])

View File

@@ -17,9 +17,10 @@ opening AS (
SUM(jl.debit) AS opening_debit,
SUM(jl.credit) AS opening_credit
FROM journal_entries je
JOIN journal_lines jl ON jl.journal_id = je.journal_id
JOIN journal_lines jl ON jl.journal_entry_id = je.journal_entry_id
WHERE je.description = '前期残高'
AND je.journal_date = %(start_date)s
AND je.entry_date = %(start_date)s
AND je.is_deleted = false
GROUP BY jl.account_id
),
@@ -29,9 +30,15 @@ period AS (
SUM(jl.debit) AS period_debit,
SUM(jl.credit) AS period_credit
FROM journal_entries je
JOIN journal_lines jl ON jl.journal_id = je.journal_id
WHERE je.journal_date BETWEEN %(start_date)s AND %(end_date)s
JOIN journal_lines jl ON jl.journal_entry_id = je.journal_entry_id
LEFT JOIN journal_entries child ON child.parent_entry_id = je.journal_entry_id
WHERE je.entry_date BETWEEN %(start_date)s AND %(end_date)s
AND je.description <> '前期残高'
AND je.is_deleted = false
-- 逆仕訳を除外([逆仕訳]プレフィックスを持つ仕訳)
AND je.description NOT LIKE '[逆仕訳]%'
-- 子仕訳(修正後仕訳)を持つ修正前の仕訳を除外
AND child.journal_entry_id IS NULL
GROUP BY jl.account_id
)

View File

@@ -23,6 +23,7 @@ class JournalEntryRequest(BaseModel):
tax_paid_account_id: Optional[int] = None # 仮払消費税等 勘定
tax_received_account_id: Optional[int] = None # 仮受消費税等 勘定
rounding_mode: str = "round" # "round", "floor", or "ceil"
parent_entry_id: Optional[int] = None # 修正元の仕訳ID
class JournalEntryUpdateRequest(BaseModel):
description: str
@@ -58,7 +59,8 @@ def get_journal_entries(
je.fiscal_year,
je.version,
COALESCE(SUM(jl.debit), 0) as debit_total,
COALESCE(SUM(jl.credit), 0) as credit_total
COALESCE(SUM(jl.credit), 0) as credit_total,
STRING_AGG(DISTINCT CASE WHEN jl.tax_rate IS NOT NULL THEN jl.tax_rate::text END, ', ' ORDER BY CASE WHEN jl.tax_rate IS NOT NULL THEN jl.tax_rate::text END) as tax_rates
FROM journal_entries je
LEFT JOIN journal_lines jl ON je.journal_entry_id = jl.journal_entry_id
WHERE je.is_deleted = false
@@ -74,7 +76,8 @@ def get_journal_entries(
je.fiscal_year,
je.version,
COALESCE(SUM(jl.debit), 0) as debit_total,
COALESCE(SUM(jl.credit), 0) as credit_total
COALESCE(SUM(jl.credit), 0) as credit_total,
STRING_AGG(DISTINCT CASE WHEN jl.tax_rate IS NOT NULL THEN jl.tax_rate::text END, ', ' ORDER BY CASE WHEN jl.tax_rate IS NOT NULL THEN jl.tax_rate::text END) as tax_rates
FROM journal_entries je
LEFT JOIN journal_lines jl ON je.journal_entry_id = jl.journal_entry_id
WHERE je.is_deleted = false
@@ -202,15 +205,17 @@ def create_reverse_entry(journal_id: int):
fiscal_year,
version,
is_deleted,
created_by
created_by,
parent_entry_id
)
VALUES (%s, %s, %s, 1, false, %s)
VALUES (%s, %s, %s, 1, false, %s, %s)
RETURNING journal_entry_id
""", (
header["entry_date"],
f"[逆仕訳] {header['description']}",
header["fiscal_year"],
"system"
"system",
journal_id # 逆仕訳の元となる仕訳ID
))
new_entry_id = cur.fetchone()["journal_entry_id"]
@@ -322,15 +327,17 @@ def create_journal_entry(req: JournalEntryRequest):
fiscal_year,
version,
is_deleted,
created_by
created_by,
parent_entry_id
)
VALUES (%s, %s, %s, 1, false, %s)
VALUES (%s, %s, %s, 1, false, %s, %s)
RETURNING journal_entry_id
""", (
req.entry_date,
req.description,
fiscal_year,
"system"
"system",
req.parent_entry_id
))
entry_id = cur.fetchone()["journal_entry_id"]

109
backend/check_data.py Normal file
View File

@@ -0,0 +1,109 @@
import os
os.environ['DB_HOST'] = '192.168.0.61'
os.environ['DB_PORT'] = '55432'
os.environ['DB_NAME'] = 'njts_acct'
os.environ['DB_USER'] = 'njts_app'
os.environ['DB_PASSWORD'] = 'njts_app2025'
import sys
sys.path.insert(0, os.path.dirname(__file__))
from app.core.database import get_connection
conn = get_connection()
cur = conn.cursor()
# 逸速ビル関連の仕訳を確認
cur.execute("""
SELECT journal_entry_id, entry_date, description, parent_entry_id, is_deleted
FROM journal_entries
WHERE description LIKE '%遠達ビル%'
ORDER BY journal_entry_id
""")
rows = cur.fetchall()
print("\n遠達ビル関連の仕訳:")
for r in rows:
print(f"ID: {r['journal_entry_id']}, Date: {r['entry_date']}, Desc: {r['description']}, Parent: {r['parent_entry_id']}, is_deleted: {r['is_deleted']}")
# parent_entry_idが設定されている仕訳IDの一覧を取得
cur.execute("""
SELECT DISTINCT parent_entry_id
FROM journal_entries
WHERE parent_entry_id IS NOT NULL
ORDER BY parent_entry_id
""")
parent_ids = [r['parent_entry_id'] for r in cur.fetchall()]
print(f"\nparent_entry_idとして参照されているID: {parent_ids}")
cur.close()
conn.close()
# 実際の検索クエリと同じロジックでテスト
print("\n--- 検索クエリのテストinclude_history=False ---")
conn2 = get_connection()
cur2 = conn2.cursor()
# まず、条件なしでID 80が取得できるか確認
cur2.execute("""
SELECT journal_entry_id, description
FROM journal_entries
WHERE journal_entry_id = 80
""")
print(f"ID 80の存在確認: {cur2.fetchall()}")
# 各条件を個別にチェック
cur2.execute("SELECT journal_entry_id FROM journal_entries WHERE journal_entry_id = 80 AND is_deleted = false")
print(f"is_deleted=false: {len(cur2.fetchall())}")
cur2.execute("SELECT journal_entry_id FROM journal_entries WHERE journal_entry_id = 80 AND description NOT LIKE '%[逆仕訳]%'")
print(f"NOT LIKE '%%[逆仕訳]%%': {len(cur2.fetchall())}")
cur2.execute("""
SELECT journal_entry_id FROM journal_entries
WHERE journal_entry_id = 80
AND journal_entry_id NOT IN (SELECT parent_entry_id FROM journal_entries WHERE parent_entry_id IS NOT NULL)
""")
print(f"NOT IN parent_entry_id: {len(cur2.fetchall())}")
cur2.execute("SELECT journal_entry_id FROM journal_entries WHERE journal_entry_id = 80 AND description LIKE '%逸速ビル%'")
print(f"LIKE '%%逸速ビル%%': {len(cur2.fetchall())}")
cur2.execute("SELECT journal_entry_id FROM journal_entries WHERE journal_entry_id = 80 AND description LIKE '%遠達ビル%'")
print(f"LIKE '%%遠達ビル%%': {len(cur2.fetchall())}")
sql = """
SELECT
je.journal_entry_id,
je.entry_date,
je.description,
je.fiscal_year,
je.version,
COALESCE(SUM(jl.debit), 0) as debit_total,
COALESCE(SUM(jl.credit), 0) as credit_total,
STRING_AGG(DISTINCT CASE WHEN jl.tax_rate IS NOT NULL THEN jl.tax_rate::text END, ', ' ORDER BY CASE WHEN jl.tax_rate IS NOT NULL THEN jl.tax_rate::text END) as tax_rates
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.description NOT LIKE %s
AND je.journal_entry_id NOT IN (
SELECT parent_entry_id
FROM journal_entries
WHERE parent_entry_id IS NOT NULL
)
AND je.entry_date >= %s AND je.entry_date <= %s
AND je.description LIKE %s
GROUP BY je.journal_entry_id, je.entry_date, je.description, je.fiscal_year, je.version
ORDER BY je.entry_date DESC, je.journal_entry_id DESC, je.version DESC
"""
cur2.execute(sql, ['%[逆仕訳]%', '2025-06-01', '2025-06-30', '%逸速ビル%'])
results = cur2.fetchall()
print(f"\n検索結果({len(results)}件):")
for r in results:
print(f"ID: {r['journal_entry_id']}, Date: {r['entry_date']}, Desc: {r['description']}, Tax: {r['tax_rates']}")
cur2.close()
conn2.close()

View File

@@ -0,0 +1,71 @@
import os
os.environ['DB_HOST'] = '192.168.0.61'
os.environ['DB_PORT'] = '55432'
os.environ['DB_NAME'] = 'njts_acct'
os.environ['DB_USER'] = 'njts_app'
os.environ['DB_PASSWORD'] = 'njts_app2025'
from app.core.database import get_connection
with get_connection() as conn:
with conn.cursor() as cur:
print("=== 6月の普通預金102仕訳 ===")
cur.execute("""
SELECT
je.journal_entry_id,
je.entry_date,
je.description,
je.parent_entry_id,
jl.debit,
jl.credit
FROM journal_entries je
JOIN journal_lines jl ON jl.journal_entry_id = je.journal_entry_id
JOIN accounts a ON a.account_id = jl.account_id
WHERE je.entry_date BETWEEN '2025-06-01' AND '2025-06-30'
AND a.account_code = '102'
ORDER BY je.journal_entry_id
""")
rows = cur.fetchall()
for row in rows:
print(f"ID: {row['journal_entry_id']:4d}, Parent: {str(row['parent_entry_id']):4s}, "
f"Debit: {row['debit']:6.0f}, Credit: {row['credit']:6.0f}, "
f"Desc: {row['description'][:50]}")
print("\n=== 試算表クエリでの除外状況 ===")
cur.execute("""
SELECT
je.journal_entry_id,
je.description,
child.journal_entry_id as has_child,
jl.debit,
jl.credit,
CASE
WHEN je.description LIKE '[逆仕訳]%%' THEN '除外:逆仕訳'
WHEN child.journal_entry_id IS NOT NULL THEN '除外:親仕訳'
ELSE '計上'
END as status
FROM journal_entries je
JOIN journal_lines jl ON jl.journal_entry_id = je.journal_entry_id
LEFT JOIN journal_entries child ON child.parent_entry_id = je.journal_entry_id
JOIN accounts a ON a.account_id = jl.account_id
WHERE je.entry_date BETWEEN '2025-06-01' AND '2025-06-30'
AND a.account_code = '102'
AND je.is_deleted = false
ORDER BY je.journal_entry_id
""")
rows = cur.fetchall()
total_debit = 0
total_credit = 0
for row in rows:
status = row['status']
if status == '計上':
total_debit += float(row['debit'])
total_credit += float(row['credit'])
print(f"ID: {row['journal_entry_id']:4d}, Status: {status:12s}, "
f"Debit: {row['debit']:6.0f}, Credit: {row['credit']:6.0f}, "
f"Desc: {row['description'][:40]}")
print(f"\n計上される借方合計: {total_debit:.0f}")
print(f"計上される貸方合計: {total_credit:.0f}")

View File

@@ -0,0 +1,45 @@
from app.core.database import get_connection
with get_connection() as conn, conn.cursor() as cur:
# 普通預金(102)の6月の仕訳を確認
cur.execute('''
SELECT
je.journal_entry_id,
je.entry_date,
je.description,
je.parent_entry_id,
jl.debit,
jl.credit,
CASE WHEN child.journal_entry_id IS NOT NULL THEN 'Y' ELSE 'N' END as has_child
FROM journal_entries je
JOIN journal_lines jl ON jl.journal_entry_id = je.journal_entry_id
LEFT JOIN journal_entries child ON child.parent_entry_id = je.journal_entry_id
WHERE jl.account_id = (SELECT account_id FROM accounts WHERE account_code = '102')
AND je.entry_date BETWEEN '2025-06-01' AND '2025-06-30'
AND je.is_deleted = false
ORDER BY je.journal_entry_id
''')
rows = cur.fetchall()
print('ID\t日付\t\t説明\t\t\t\t\tparent\t借方\t\t貸方\t\tchild?')
print('='*120)
for r in rows:
desc = r['description'][:40].ljust(40)
parent = str(r['parent_entry_id']) if r['parent_entry_id'] else '-'
print(f"{r['journal_entry_id']}\t{r['entry_date']}\t{desc}\t{parent}\t{r['debit']}\t{r['credit']}\t{r['has_child']}")
print('\n集計child=Nのみ:')
cur.execute('''
SELECT
SUM(jl.debit) as total_debit,
SUM(jl.credit) as total_credit
FROM journal_entries je
JOIN journal_lines jl ON jl.journal_entry_id = je.journal_entry_id
LEFT JOIN journal_entries child ON child.parent_entry_id = je.journal_entry_id
WHERE jl.account_id = (SELECT account_id FROM accounts WHERE account_code = '102')
AND je.entry_date BETWEEN '2025-06-01' AND '2025-06-30'
AND je.is_deleted = false
AND child.journal_entry_id IS NULL
''')
result = cur.fetchone()
print(f"借方: {result['total_debit']}, 貸方: {result['total_credit']}")

View File

@@ -0,0 +1,93 @@
import os
os.environ['DB_HOST'] = '192.168.0.61'
os.environ['DB_PORT'] = '55432'
os.environ['DB_NAME'] = 'njts_acct'
os.environ['DB_USER'] = 'njts_app'
os.environ['DB_PASSWORD'] = 'njts_app2025'
import sys
sys.path.insert(0, os.path.dirname(__file__))
from app.core.database import get_connection
conn = get_connection()
cur = conn.cursor()
# 社会保険料関連の仕訳を確認
print("\n=== 2025年4月 社会保険料の仕訳チェーン ===")
cur.execute("""
SELECT
je.journal_entry_id,
je.entry_date,
je.description,
je.parent_entry_id,
je.is_deleted,
CASE
WHEN EXISTS (SELECT 1 FROM journal_entries child WHERE child.parent_entry_id = je.journal_entry_id)
THEN 'Y' ELSE 'N'
END as has_child
FROM journal_entries je
WHERE je.description LIKE '%2025年4月 社会保険料%'
ORDER BY je.journal_entry_id
""")
rows = cur.fetchall()
for r in rows:
print(f"ID:{r['journal_entry_id']:3d} 親:{r['parent_entry_id'] or '-':>3} 子:{r['has_child']} 削除:{r['is_deleted']} {r['description']}")
# 試算表と同じロジックで集計
print("\n=== 試算表と同じロジックでの集計2025-06-012025-06-30 ===")
cur.execute("""
SELECT
je.journal_entry_id,
je.entry_date,
je.description,
jl.debit,
jl.credit,
je.parent_entry_id,
je.is_deleted,
CASE
WHEN EXISTS (SELECT 1 FROM journal_entries child WHERE child.parent_entry_id = je.journal_entry_id)
THEN 'Y' ELSE 'N'
END as has_child
FROM journal_entries je
JOIN journal_lines jl ON je.journal_entry_id = jl.journal_entry_id
JOIN accounts a ON jl.account_id = a.account_id
WHERE a.account_code = '102'
AND je.entry_date BETWEEN '2025-06-01' AND '2025-06-30'
AND je.description <> '前期残高'
AND je.is_deleted = false
ORDER BY je.journal_entry_id
""")
print(f"\n{'ID':>3} {'日付':10} {'借方':>12} {'貸方':>12} {'':>3} {'':2} {'集計':4} 摘要")
print("-" * 120)
total_debit_all = 0
total_credit_all = 0
total_debit_filtered = 0
total_credit_filtered = 0
rows = cur.fetchall()
for r in rows:
total_debit_all += r['debit']
total_credit_all += r['credit']
# 試算表のロジック: 子を持たない仕訳のみ集計
should_include = r['has_child'] == 'N'
if should_include:
total_debit_filtered += r['debit']
total_credit_filtered += r['credit']
status = "集計" if should_include else "除外"
parent_str = str(r['parent_entry_id']) if r['parent_entry_id'] else "-"
print(f"{r['journal_entry_id']:3d} {r['entry_date']} {r['debit']:>12,.0f} {r['credit']:>12,.0f} {parent_str:>3} {r['has_child']:2} {status:4} {r['description'][:60]}")
print("-" * 120)
print(f"全仕訳: 借方={total_debit_all:>12,.0f} 貸方={total_credit_all:>12,.0f}")
print(f"試算表集計: 借方={total_debit_filtered:>12,.0f} 貸方={total_credit_filtered:>12,.0f}")
cur.close()
conn.close()

View File

@@ -0,0 +1,25 @@
-- 既存の修正仕訳データを修正
-- 1. ID 80のis_deletedをfalseに設定修正版は削除されていないはず
UPDATE journal_entries
SET is_deleted = false
WHERE journal_entry_id = 80;
-- 2. 最新の修正仕訳【修正後】【修正後】などのparent_entry_idが正しく設定されているか確認
-- まず確認クエリ
SELECT journal_entry_id, description, parent_entry_id, is_deleted
FROM journal_entries
WHERE description LIKE '%遠達ビル%'
ORDER BY journal_entry_id;
-- 3. 修正チェーンを正しく設定
-- ID 98: [逆仕訳] 【修正後】·遠達ビル 事務所費用 → parent_entry_idを80に設定
UPDATE journal_entries SET parent_entry_id = 80 WHERE journal_entry_id = 98;
-- ID 99: 【修正後】【修正後】·遠達ビル 事務所費用 → parent_entry_idを98に設定
UPDATE journal_entries SET parent_entry_id = 98 WHERE journal_entry_id = 99;
-- 4. すべての【修正後】仕訳のis_deletedをfalseに設定
UPDATE journal_entries
SET is_deleted = false
WHERE description LIKE '【修正後】%';

View File

@@ -0,0 +1,78 @@
-- 既存の全仕訳のparent_entry_idを一括設定
-- ステップ1: 現在の状況を確認
SELECT
journal_entry_id,
entry_date,
description,
parent_entry_id,
is_deleted
FROM journal_entries
ORDER BY entry_date, journal_entry_id;
-- ステップ2: [逆仕訳]のparent_entry_idを設定
-- [逆仕訳]の直前の同じ日付・同じベース説明の仕訳を親とする
UPDATE journal_entries je_reverse
SET parent_entry_id = (
SELECT je_original.journal_entry_id
FROM journal_entries je_original
WHERE je_original.entry_date = je_reverse.entry_date
AND je_original.journal_entry_id < je_reverse.journal_entry_id
AND REPLACE(je_reverse.description, '[逆仕訳] ', '') = je_original.description
AND je_original.description NOT LIKE '[逆仕訳]%'
ORDER BY je_original.journal_entry_id DESC
LIMIT 1
)
WHERE je_reverse.description LIKE '[逆仕訳]%'
AND je_reverse.parent_entry_id IS NULL;
-- ステップ3: 【修正後】のparent_entry_idを設定
-- 【修正後】の直前の逆仕訳を親とする
UPDATE journal_entries je_modified
SET parent_entry_id = (
SELECT je_reverse.journal_entry_id
FROM journal_entries je_reverse
WHERE je_reverse.journal_entry_id < je_modified.journal_entry_id
AND je_reverse.description = '[逆仕訳] ' || REPLACE(je_modified.description, '【修正後】', '')
ORDER BY je_reverse.journal_entry_id DESC
LIMIT 1
)
WHERE je_modified.description LIKE '【修正後】%'
AND je_modified.parent_entry_id IS NULL;
-- ステップ4: 複数の【修正後】プレフィックスがある場合の処理
-- 【修正後】【修正後】などのケース
UPDATE journal_entries je_modified
SET parent_entry_id = (
SELECT je_reverse.journal_entry_id
FROM journal_entries je_reverse
WHERE je_reverse.entry_date = je_modified.entry_date
AND je_reverse.journal_entry_id < je_modified.journal_entry_id
AND je_reverse.description LIKE '[逆仕訳]%'
ORDER BY je_reverse.journal_entry_id DESC
LIMIT 1
)
WHERE je_modified.description LIKE '【修正後】%'
AND je_modified.parent_entry_id IS NULL;
-- ステップ5: 結果確認
SELECT
journal_entry_id,
entry_date,
LEFT(description, 50) as description,
parent_entry_id,
is_deleted
FROM journal_entries
WHERE parent_entry_id IS NOT NULL
ORDER BY entry_date, journal_entry_id;
-- ステップ6: parent_entry_idが設定されていない逆仕訳・修正後を確認
SELECT
journal_entry_id,
entry_date,
LEFT(description, 50) as description,
parent_entry_id
FROM journal_entries
WHERE (description LIKE '[逆仕訳]%' OR description LIKE '【修正後】%')
AND parent_entry_id IS NULL
ORDER BY journal_entry_id;

View File

@@ -1,5 +1,9 @@
-- 修正後の仕訳に対して、元の仕訳IDをparent_entry_idに設定
-- 特定の修正チェーンを手動で設定72 → 79 → 80
-- UPDATE journal_entries SET parent_entry_id = 72 WHERE journal_entry_id = 79;
-- UPDATE journal_entries SET parent_entry_id = 79 WHERE journal_entry_id = 80;
-- ステップ1: 【修正後】の仕訳を確認
SELECT
je_modified.journal_entry_id as modified_id,

View File

@@ -0,0 +1,150 @@
import os
os.environ['DB_HOST'] = '192.168.0.61'
os.environ['DB_PORT'] = '55432'
os.environ['DB_NAME'] = 'njts_acct'
os.environ['DB_USER'] = 'njts_app'
os.environ['DB_PASSWORD'] = 'njts_app2025'
import sys
sys.path.insert(0, os.path.dirname(__file__))
from app.core.database import get_connection
conn = get_connection()
cur = conn.cursor()
print("\n" + "="*120)
print("試算表ロジック検証 - 普通預金(102) 2025年6月")
print("="*120)
# 試算表SQLと同じロジックで集計
cur.execute("""
SELECT
jl.account_id,
SUM(jl.debit) as total_debit,
SUM(jl.credit) as total_credit
FROM journal_entries je
JOIN journal_lines jl ON jl.journal_entry_id = je.journal_entry_id
LEFT JOIN journal_entries child ON child.parent_entry_id = je.journal_entry_id
JOIN accounts a ON jl.account_id = a.account_id
WHERE je.entry_date BETWEEN '2025-06-01' AND '2025-06-30'
AND je.description <> '前期残高'
AND je.is_deleted = false
AND child.journal_entry_id IS NULL
AND a.account_code = '102'
GROUP BY jl.account_id
""")
result = cur.fetchone()
print(f"\n【試算表の集計結果】")
print(f"借方発生額: {result['total_debit']:>15,.0f}")
print(f"貸方発生額: {result['total_credit']:>15,.0f}")
# 詳細な内訳を確認
print(f"\n{'='*120}")
print("【集計対象の仕訳詳細】")
print(f"{'='*120}")
cur.execute("""
SELECT
je.journal_entry_id,
je.entry_date,
je.description,
jl.debit,
jl.credit,
je.parent_entry_id,
CASE WHEN child.journal_entry_id IS NOT NULL THEN 'Y' ELSE 'N' END as has_child
FROM journal_entries je
JOIN journal_lines jl ON jl.journal_entry_id = je.journal_entry_id
LEFT JOIN journal_entries child ON child.parent_entry_id = je.journal_entry_id
JOIN accounts a ON jl.account_id = a.account_id
WHERE je.entry_date BETWEEN '2025-06-01' AND '2025-06-30'
AND je.description <> '前期残高'
AND je.is_deleted = false
AND a.account_code = '102'
ORDER BY je.journal_entry_id
""")
rows = cur.fetchall()
debit_sum = 0
credit_sum = 0
debit_included = 0
credit_included = 0
print(f"\n{'ID':>3} {'日付':10} {'借方':>13} {'貸方':>13} {'親ID':>5} {'':3} {'集計':4} 摘要")
print("-" * 120)
for r in rows:
is_included = r['has_child'] == 'N'
status = "" if is_included else "×"
debit_sum += r['debit']
credit_sum += r['credit']
if is_included:
debit_included += r['debit']
credit_included += r['credit']
parent_str = str(r['parent_entry_id']) if r['parent_entry_id'] else "-"
# 逆仕訳・修正後をマーク
desc = r['description'][:60]
if '[逆仕訳]' in desc:
desc = f"🔄 {desc}"
elif '【修正後】' in desc:
desc = f"✏️ {desc}"
print(f"{r['journal_entry_id']:3d} {r['entry_date']} {r['debit']:>13,.0f} {r['credit']:>13,.0f} {parent_str:>5} {r['has_child']:3} {status:4} {desc}")
print("-" * 120)
print(f"{'全仕訳合計':62} {debit_sum:>13,.0f} {credit_sum:>13,.0f}")
print(f"{'集計対象(子なし)':60} {debit_included:>13,.0f} {credit_included:>13,.0f}")
# parent_entry_idの問題を確認
print(f"\n{'='*120}")
print("【parent_entry_idチェーン確認】")
print(f"{'='*120}")
cur.execute("""
SELECT
je.journal_entry_id as id,
je.description,
je.parent_entry_id as parent,
(SELECT description FROM journal_entries WHERE journal_entry_id = je.parent_entry_id) as parent_desc,
(SELECT COUNT(*) FROM journal_entries child WHERE child.parent_entry_id = je.journal_entry_id) as child_count
FROM journal_entries je
WHERE (je.description LIKE '%社会保険%' OR je.description LIKE '%遠達ビル%')
AND je.entry_date BETWEEN '2025-06-01' AND '2025-06-30'
ORDER BY je.journal_entry_id
""")
print(f"\n{'ID':>3} {'親ID':>5} {'子数':>4} 摘要 → 親の摘要")
print("-" * 120)
rows = cur.fetchall()
for r in rows:
parent_str = str(r['parent']) if r['parent'] else "-"
parent_desc_str = r['parent_desc'][:40] if r['parent_desc'] else "-"
print(f"{r['id']:3d} {parent_str:>5} {r['child_count']:>4} {r['description'][:50]}")
if r['parent_desc']:
print(f" └→ 親: {parent_desc_str}")
cur.close()
conn.close()
print(f"\n{'='*120}")
print("【結論】")
print(f"{'='*120}")
print("""
正しい集計方法:
1. parent_entry_idチェーンが正しく設定されている場合
→ 最後の修正版のみが「子を持たない」状態になり、それのみが集計される
2. parent_entry_idの設定ミスがある場合
→ 逆仕訳や途中の修正版も「子を持たない」と判定され、重複集計される
対策:
- すべてのparent_entry_idを正しく設定する
- チェーン: 元 → 逆仕訳 → 修正後 → 逆仕訳 → 修正後 → ...
""")