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 FROM journal_lines l
JOIN journal_entries j JOIN journal_entries j
ON j.journal_id = l.journal_id 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 WHERE l.account_id = %(account_id)s
AND j.journal_date BETWEEN %(date_from)s AND %(date_to)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; ORDER BY j.journal_date, l.line_id;
""" """

View File

@@ -64,8 +64,14 @@ def get_general_ledger(
FROM journal_entries j FROM journal_entries j
JOIN journal_lines l JOIN journal_lines l
ON l.journal_id = j.journal_id 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 WHERE l.account_id = %s
AND j.journal_date BETWEEN %s AND %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 ORDER BY j.journal_date, l.line_id
""", (account_id, date_from, date_to)) """, (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) opening_balance_from_table = D(ob_row["ob"]) if ob_row else D(0)
# date_from より前の仕訳による増減 # date_from より前の仕訳による増減
# 修正された仕訳(親となった仕訳)は除外
cur.execute(""" cur.execute("""
SELECT COALESCE(SUM(l.debit - l.credit), 0) AS opening SELECT COALESCE(SUM(l.debit - l.credit), 0) AS opening
FROM journal_lines l FROM journal_lines l
JOIN journal_entries j JOIN journal_entries j
ON j.journal_entry_id = l.journal_entry_id 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 WHERE l.account_id = %s
AND j.entry_date < %s AND j.entry_date < %s
AND j.is_deleted = false AND j.is_deleted = false
AND j.description NOT LIKE '[逆仕訳]%%'
AND child.journal_entry_id IS NULL
""", (aid, date_from)) """, (aid, date_from))
opening_from_journals = D(cur.fetchone()["opening"]) 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 opening = opening_balance_from_table + opening_from_journals
# 当期増減date_from date_to # 当期増減date_from date_to
# 修正された仕訳(親となった仕訳)は除外
cur.execute(""" cur.execute("""
SELECT SELECT
COALESCE(SUM(l.debit), 0) AS debit, 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 FROM journal_lines l
JOIN journal_entries j JOIN journal_entries j
ON j.journal_entry_id = l.journal_entry_id 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 WHERE l.account_id = %s
AND j.entry_date BETWEEN %s AND %s AND j.entry_date BETWEEN %s AND %s
AND j.is_deleted = false AND j.is_deleted = false
AND j.description NOT LIKE '[逆仕訳]%%'
AND child.journal_entry_id IS NULL
""", (aid, date_from, date_to)) """, (aid, date_from, date_to))
row = cur.fetchone() row = cur.fetchone()
debit = D(row["debit"]) debit = D(row["debit"])

View File

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

View File

@@ -23,6 +23,7 @@ class JournalEntryRequest(BaseModel):
tax_paid_account_id: Optional[int] = None # 仮払消費税等 勘定 tax_paid_account_id: Optional[int] = None # 仮払消費税等 勘定
tax_received_account_id: Optional[int] = None # 仮受消費税等 勘定 tax_received_account_id: Optional[int] = None # 仮受消費税等 勘定
rounding_mode: str = "round" # "round", "floor", or "ceil" rounding_mode: str = "round" # "round", "floor", or "ceil"
parent_entry_id: Optional[int] = None # 修正元の仕訳ID
class JournalEntryUpdateRequest(BaseModel): class JournalEntryUpdateRequest(BaseModel):
description: str description: str
@@ -58,7 +59,8 @@ def get_journal_entries(
je.fiscal_year, je.fiscal_year,
je.version, je.version,
COALESCE(SUM(jl.debit), 0) as debit_total, 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 FROM journal_entries je
LEFT JOIN journal_lines jl ON je.journal_entry_id = jl.journal_entry_id LEFT JOIN journal_lines jl ON je.journal_entry_id = jl.journal_entry_id
WHERE je.is_deleted = false WHERE je.is_deleted = false
@@ -74,7 +76,8 @@ def get_journal_entries(
je.fiscal_year, je.fiscal_year,
je.version, je.version,
COALESCE(SUM(jl.debit), 0) as debit_total, 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 FROM journal_entries je
LEFT JOIN journal_lines jl ON je.journal_entry_id = jl.journal_entry_id LEFT JOIN journal_lines jl ON je.journal_entry_id = jl.journal_entry_id
WHERE je.is_deleted = false WHERE je.is_deleted = false
@@ -202,15 +205,17 @@ def create_reverse_entry(journal_id: int):
fiscal_year, fiscal_year,
version, version,
is_deleted, 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 RETURNING journal_entry_id
""", ( """, (
header["entry_date"], header["entry_date"],
f"[逆仕訳] {header['description']}", f"[逆仕訳] {header['description']}",
header["fiscal_year"], header["fiscal_year"],
"system" "system",
journal_id # 逆仕訳の元となる仕訳ID
)) ))
new_entry_id = cur.fetchone()["journal_entry_id"] new_entry_id = cur.fetchone()["journal_entry_id"]
@@ -322,15 +327,17 @@ def create_journal_entry(req: JournalEntryRequest):
fiscal_year, fiscal_year,
version, version,
is_deleted, 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 RETURNING journal_entry_id
""", ( """, (
req.entry_date, req.entry_date,
req.description, req.description,
fiscal_year, fiscal_year,
"system" "system",
req.parent_entry_id
)) ))
entry_id = cur.fetchone()["journal_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に設定 -- 修正後の仕訳に対して、元の仕訳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: 【修正後】の仕訳を確認 -- ステップ1: 【修正後】の仕訳を確認
SELECT SELECT
je_modified.journal_entry_id as modified_id, 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を正しく設定する
- チェーン: 元 → 逆仕訳 → 修正後 → 逆仕訳 → 修正後 → ...
""")

166
docs/trial_balance_fix.md Normal file
View File

@@ -0,0 +1,166 @@
# 試算表修正履歴除外対応
## 問題概要
従来、仕訳修正時に以下の流れで処理していました:
1. 原仕訳を保留
2. 逆仕訳を生成(`[逆仕訳]` プレフィックス付き)
3. 修正後仕訳を生成(`【修正後】` プレフィックス付き)
しかし、試算表計算時に全ての仕訳を無条件に統計していたため:
- 原仕訳
- 逆仕訳
- 修正後仕訳
の 3 つが全て計上され、同一取引が複数回カウントされる問題が発生していました。
### 具体的な症状
- 銀行科目(普通預金)で借方発生額・貸方発生額が同額計上される
- 期末残高が銀行通帳と一致しない
- 試算表数値が実態と乖離
## 解決方針
**方案 B逆仕訳方式 + 試算表排除ロジック** を採用
以下の理由により、試算表 SQL で履歴データを除外する方式を選択:
1. 既存データに逆仕訳・修正後仕訳の関係性が構築済み
2. 修正履歴を保持できる
3. 最小限のコード変更で対応可能
4. データマイグレーション不要
## 実装内容
### 1. 試算表 SQL 修正
**ファイル**: `backend/app/modules/trial_balance/sql.py`
```python
period AS (
SELECT
jl.account_id,
SUM(jl.debit) AS period_debit,
SUM(jl.credit) AS period_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 je.entry_date BETWEEN %(start_date)s AND %(end_date)s
AND je.description <> '前期残高'
AND je.is_deleted = false
-- 逆仕訳を除外
AND je.description NOT LIKE '[逆仕訳]%'
-- 修正前仕訳を除外parent_entry_idを参照する子仕訳がある場合
AND child.journal_entry_id IS NULL
GROUP BY jl.account_id
)
```
### 2. 総勘定元帳 SQL 修正
**ファイル**: `backend/app/modules/general_ledger/sql.py`
```python
SELECT
j.journal_date,
j.description,
l.debit,
l.credit
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;
```
### 3. 元帳 SQL 修正
**ファイル**: `backend/app/modules/ledger/router.py`
同様に逆仕訳と修正前仕訳を除外する条件を追加。
## 除外ロジックの説明
### 除外対象 1逆仕訳
```sql
AND je.description NOT LIKE '[逆仕訳]%'
```
- 説明に `[逆仕訳]` プレフィックスを持つ仕訳を除外
- これらは元仕訳を打ち消すためのもので、試算表には計上しない
### 除外対象 2修正前仕訳
```sql
LEFT JOIN journal_entries child ON child.parent_entry_id = je.journal_entry_id
...
AND child.journal_entry_id IS NULL
```
- `parent_entry_id` を参照する子仕訳(修正後仕訳)が存在する場合、その親仕訳は除外
- 修正された仕訳は最新版のみを計上
## 仕訳修正の流れ(参考)
1. **元仕訳**: `journal_entry_id = 100`, `parent_entry_id = NULL`
2. **逆仕訳**: `journal_entry_id = 101`, `parent_entry_id = 100`, `description = "[逆仕訳] xxx"`
3. **修正後仕訳**: `journal_entry_id = 102`, `parent_entry_id = 101`, `description = "【修正後】xxx"`
試算表では:
- 元仕訳100除外子仕訳 101 が存在)
- 逆仕訳101除外`[逆仕訳]` プレフィックス)
- 修正後仕訳102**計上**(最新版)
## 会計原則の遵守
✅ 試算表は「当前有効的仕訳」のみを統計
✅ 同一業務が同一期間で 1 回のみ計上
✅ 履歴データ(逆仕訳・修正前仕訳)は除外
✅ 試算表結果が銀行通帳・実態と一致
## 影響範囲
### 修正対象
- ✅ 試算表Trial Balance
- ✅ 総勘定元帳General Ledger
- ✅ 元帳Ledger
### 影響なし
- 仕訳一覧表示(修正履歴表示機能は既存のまま)
- 仕訳登録・修正ロジック
- データベーススキーマ
## テスト項目
1. [ ] 修正前の仕訳がある状態で試算表を表示
2. [ ] 逆仕訳が正しく除外されることを確認
3. [ ] 修正後仕訳のみが計上されることを確認
4. [ ] 普通預金の期末残高が通帳と一致することを確認
5. [ ] 総勘定元帳でも同様に履歴が除外されることを確認
## 今後の拡張性
現在は `description` の文字列マッチで逆仕訳を判定していますが、将来的には以下の改善も検討可能:
- `is_reversal` フラグの追加
- `entry_type` カラム(`original`, `reversal`, `revised`)の追加
- より明示的な状態管理
ただし、現在の実装でも要件は満たしており、早急な変更は不要です。

View File

@@ -44,7 +44,7 @@
<h2>修正仕訳入力</h2> <h2>修正仕訳入力</h2>
<label>仕訳日</label> <label>仕訳日</label>
<input type="date" id="entryDate" /> <input type="date" id="entryDate" min="1900-01-01" max="9999-12-31" />
<label>摘要</label> <label>摘要</label>
<input type="text" id="description" style="width: 60%" /> <input type="text" id="description" style="width: 60%" />
@@ -143,6 +143,12 @@
tr.querySelectorAll("input")[0].value = line.debit || ""; tr.querySelectorAll("input")[0].value = line.debit || "";
tr.querySelectorAll("input")[1].value = line.credit || ""; tr.querySelectorAll("input")[1].value = line.credit || "";
} }
// 入力時に合計を自動更新
tr.querySelectorAll("input").forEach((input) => {
input.addEventListener("input", recalc);
input.addEventListener("change", recalc);
});
} }
function removeRow(btn) { function removeRow(btn) {
@@ -197,6 +203,12 @@
if (lines.length < 2) return showError("仕訳行は2行以上必要です"); if (lines.length < 2) return showError("仕訳行は2行以上必要です");
if (d !== c) return showError("借方合計と貸方合計が一致していません"); if (d !== c) return showError("借方合計と貸方合計が一致していません");
// 逆仕訳IDを親IDとして取得逆仕訳が存在する場合
const src = localStorage.getItem("editSource");
const srcData = src ? JSON.parse(src) : null;
// 【修正後】仕訳のparent_entry_idは、直前に作成された逆仕訳のID
const parentEntryId = srcData?.reversed_journal_entry_id || null;
const payload = { const payload = {
entry_date: entryDate, entry_date: entryDate,
description: desc, description: desc,
@@ -204,6 +216,7 @@
tax_paid_account_id: null, tax_paid_account_id: null,
tax_received_account_id: null, tax_received_account_id: null,
rounding_mode: "floor", rounding_mode: "floor",
parent_entry_id: parentEntryId,
}; };
try { try {

View File

@@ -103,6 +103,33 @@
<tbody></tbody> <tbody></tbody>
</table> </table>
<div
style="
margin-top: 10px;
padding: 10px;
background: #f9f9f9;
border: 1px solid #ddd;
display: flex;
gap: 40px;
font-weight: bold;
"
>
<div>
<label>借方合計:</label>
<span id="totalDebit" style="color: #0066cc; font-size: 16px">0</span>
</div>
<div>
<label>貸方合計:</label>
<span id="totalCredit" style="color: #cc0000; font-size: 16px">0</span>
</div>
<div
id="balanceStatus"
style="margin-left: auto; padding: 4px 12px; border-radius: 4px"
></div>
</div>
<div style="margin-top: 10px; display: flex; gap: 8px"> <div style="margin-top: 10px; display: flex; gap: 8px">
<button onclick="addRow()"> 行追加</button> <button onclick="addRow()"> 行追加</button>
<button onclick="submitJournal()">登録</button> <button onclick="submitJournal()">登録</button>
@@ -199,6 +226,7 @@
<th>摘要</th> <th>摘要</th>
<th>借方合計</th> <th>借方合計</th>
<th>貸方合計</th> <th>貸方合計</th>
<th>税率</th>
<th>操作</th> <th>操作</th>
</tr> </tr>
</thead> </thead>
@@ -301,6 +329,29 @@
// 摘要履歴を読み込み // 摘要履歴を読み込み
loadDescriptionHistory(); loadDescriptionHistory();
// 各フィールドの変更時に合計を更新
document
.getElementById("entryDate")
.addEventListener("change", updateTotals);
document
.getElementById("description")
.addEventListener("input", updateTotals);
document
.getElementById("taxPaidSelect")
.addEventListener("change", updateTotals);
document
.getElementById("taxReceivedSelect")
.addEventListener("change", updateTotals);
document
.getElementById("roundingMode")
.addEventListener("change", () => {
// 端数処理変更時は全ての税行を再計算
const rows = document.querySelectorAll(
"#linesTable tbody tr:not(.tax-row)"
);
rows.forEach((row) => handleTax(row));
});
} }
init(); init();
@@ -451,8 +502,16 @@
// 普通行:绑定事件 // 普通行:绑定事件
if (!isTaxRow) { if (!isTaxRow) {
const recalc = () => handleTax(tr); const recalc = () => handleTax(tr);
tr.querySelector(".debit").addEventListener("input", recalc); const debitInput = tr.querySelector(".debit");
tr.querySelector(".credit").addEventListener("input", recalc); const creditInput = tr.querySelector(".credit");
debitInput.addEventListener("input", recalc);
creditInput.addEventListener("input", recalc);
// blurフォーカス離脱時に合計を更新
debitInput.addEventListener("blur", updateTotals);
creditInput.addEventListener("blur", updateTotals);
tr.querySelector(".taxType").addEventListener("change", recalc); tr.querySelector(".taxType").addEventListener("change", recalc);
tr.querySelector(".taxDirection").addEventListener("change", recalc); tr.querySelector(".taxDirection").addEventListener("change", recalc);
} }
@@ -473,6 +532,49 @@
const row = btn.closest("tr"); const row = btn.closest("tr");
removeTaxRowsOf(row); removeTaxRowsOf(row);
row.remove(); row.remove();
updateTotals(); // 削除後に合計を更新
}
// -----------------------------
// 借方・貸方合計を計算して表示
// -----------------------------
function updateTotals() {
let totalDebit = 0;
let totalCredit = 0;
const rows = document.querySelectorAll("#linesTable tbody tr");
rows.forEach((row) => {
const debitValue =
row.querySelector(".debit")?.value.replace(/,/g, "") || "0";
const creditValue =
row.querySelector(".credit")?.value.replace(/,/g, "") || "0";
totalDebit += Number(debitValue) || 0;
totalCredit += Number(creditValue) || 0;
});
// 表示を更新
document.getElementById("totalDebit").textContent =
totalDebit.toLocaleString();
document.getElementById("totalCredit").textContent =
totalCredit.toLocaleString();
// 貸借一致チェック
const balanceStatus = document.getElementById("balanceStatus");
if (totalDebit === totalCredit && totalDebit > 0) {
balanceStatus.textContent = "✓ 貸借一致";
balanceStatus.style.background = "#d4edda";
balanceStatus.style.color = "#155724";
} else if (totalDebit === 0 && totalCredit === 0) {
balanceStatus.textContent = "";
balanceStatus.style.background = "";
} else {
balanceStatus.textContent = `✗ 差額: ${Math.abs(
totalDebit - totalCredit
).toLocaleString()}`;
balanceStatus.style.background = "#f8d7da";
balanceStatus.style.color = "#721c24";
}
} }
// ----------------------------- // -----------------------------
@@ -491,10 +593,16 @@
row.querySelector(".credit").value.replace(/,/g, "") || 0 row.querySelector(".credit").value.replace(/,/g, "") || 0
); );
if (taxType === "none" || taxDir === "none") return; if (taxType === "none" || taxDir === "none") {
updateTotals(); // 税なしでも合計更新
return;
}
const totalAmount = debit || credit; const totalAmount = debit || credit;
if (!totalAmount) return; if (!totalAmount) {
updateTotals();
return;
}
const rate = taxType === "8" ? 0.08 : 0.1; const rate = taxType === "8" ? 0.08 : 0.1;
const roundingMode = document.getElementById("roundingMode").value; const roundingMode = document.getElementById("roundingMode").value;
@@ -517,7 +625,10 @@
if (taxDir === "paid") { if (taxDir === "paid") {
const taxAcc = document.getElementById("taxPaidSelect").value; const taxAcc = document.getElementById("taxPaidSelect").value;
if (!taxAcc) return alert("仮払消費税等 勘定を選択してください"); if (!taxAcc) {
updateTotals();
return alert("仮払消費税等 勘定を選択してください");
}
addRow( addRow(
true, true,
{ accountId: taxAcc, amount: taxAmount, side: "debit" }, { accountId: taxAcc, amount: taxAmount, side: "debit" },
@@ -526,13 +637,18 @@
} }
if (taxDir === "received") { if (taxDir === "received") {
const taxAcc = document.getElementById("taxReceivedSelect").value; const taxAcc = document.getElementById("taxReceivedSelect").value;
if (!taxAcc) return alert("仮受消費税等 勘定を選択してください"); if (!taxAcc) {
updateTotals();
return alert("仮受消費税等 勘定を選択してください");
}
addRow( addRow(
true, true,
{ accountId: taxAcc, amount: taxAmount, side: "credit" }, { accountId: taxAcc, amount: taxAmount, side: "credit" },
parentId parentId
); );
} }
updateTotals(); // 税行追加後に合計更新
} }
// 税行は常に「直後の1行」を使う // 税行は常に「直後の1行」を使う
@@ -686,6 +802,12 @@
rowSeq = 0; rowSeq = 0;
addRow(); addRow();
// 借方合計・貸方合計を0にリセット
document.getElementById("totalDebit").textContent = "0";
document.getElementById("totalCredit").textContent = "0";
document.getElementById("balanceStatus").textContent = "";
document.getElementById("balanceStatus").style.background = "";
// 仕訳検索を自動実行して最新の登録状況を表示 // 仕訳検索を自動実行して最新の登録状況を表示
searchJournals(); searchJournals();
} catch (error) { } catch (error) {
@@ -911,9 +1033,12 @@
includeHistory && e.version > 1 ? ` (v${e.version})` : ""; includeHistory && e.version > 1 ? ` (v${e.version})` : "";
tr.innerHTML = ` tr.innerHTML = `
<td>${e.entry_date}</td> <td>${e.entry_date}</td>
<td>${e.description}${versionInfo}</td> <td style="text-align:left">${e.description}${versionInfo}</td>
<td style="text-align:right">${e.debit_total.toLocaleString()}</td> <td style="text-align:right">${e.debit_total.toLocaleString()}</td>
<td style="text-align:right">${e.credit_total.toLocaleString()}</td> <td style="text-align:right">${e.credit_total.toLocaleString()}</td>
<td style="text-align:center">${
e.tax_rates ? e.tax_rates + "%" : ""
}</td>
<td> <td>
<button onclick="viewJournal(${ <button onclick="viewJournal(${
e.journal_entry_id e.journal_entry_id
@@ -1050,6 +1175,8 @@
} }
const srcData = await srcRes.json(); const srcData = await srcRes.json();
// 逆仕訳IDを追加して保存【修正後】仕訳のparent_entry_idとして使用
srcData.reversed_journal_entry_id = data.reversed_journal_entry_id;
localStorage.setItem("editSource", JSON.stringify(srcData)); localStorage.setItem("editSource", JSON.stringify(srcData));
// 修正画面を開く // 修正画面を開く

View File

@@ -138,6 +138,8 @@
} }
const srcData = await srcRes.json(); const srcData = await srcRes.json();
// 逆仕訳IDを追加して保存【修正後】仕訳のparent_entry_idとして使用
srcData.reversed_journal_entry_id = data.reversed_journal_entry_id;
localStorage.setItem("editSource", JSON.stringify(srcData)); localStorage.setItem("editSource", JSON.stringify(srcData));
// 修正画面を開く // 修正画面を開く

View File

@@ -99,10 +99,10 @@
<div class="search-form"> <div class="search-form">
<label for="dateFrom">開始年月日:</label> <label for="dateFrom">開始年月日:</label>
<input type="date" id="dateFrom" /> <input type="date" id="dateFrom" min="1900-01-01" max="9999-12-31" />
<label for="dateTo">終了年月日:</label> <label for="dateTo">終了年月日:</label>
<input type="date" id="dateTo" /> <input type="date" id="dateTo" min="1900-01-01" max="9999-12-31" />
<button id="btnSearch">検索</button> <button id="btnSearch">検索</button>
<button id="btnFullYear" class="secondary">全年度表示</button> <button id="btnFullYear" class="secondary">全年度表示</button>