元帳から借方貸方の不一致を見つけ出す
한국어 원문으로 표시합니다.
목표
복식부기 원장에서 시작해, 차대변이 맞지 않는 전표 1건을 분개행 한 줄까지 좁혀 내고, 원 기록을 지우지 않는 방식으로 바로잡은 뒤, 잔액 표까지 원장에 맞춰 놓을 수 있게 됩니다.
왜 중요한가
은행 시스템에서 잔액은 저장된 값이 아니라 원장에서 계산해 내는 값입니다. 성능 때문에 계정마다 잔액 컬럼을 함께 들고 있지만, 그것은 원장의 사본이지 원본이 아닙니다.
이 구분이 조사에서 결정적인 이유는 이렇습니다. 잔액 하나는 그냥 숫자라서, 그 숫자만 보고는 맞는지 틀린지 알 방법이 없습니다. 반면 복식부기 원장은 자기 자신을 검증합니다 — 모든 거래가 차변과 대변 양쪽에 기록되므로 원장 전체의 차변 합과 대변 합은 반드시 같아야 하고, 이 항등식이 깨지면 그 자체가 사고 신호입니다. 그리고 그 신호는 전표 단위로 한 번 더 좁혀집니다.
이번 사건은 이렇습니다. 고객사 운영 담당자가 "결산 잔액이 안 맞는다" 고 연락해 왔습니다. 사흘치 원장에 어긋남이 두 군데 있는데, 성질이 서로 정반대입니다. 한쪽은 원장이 틀렸고 잔액 표가 맞으며, 다른 한쪽은 원장이 맞고 잔액 표가 틀렸습니다. 이 둘을 가르지 않고 손대면 고치는 쪽이 반대가 됩니다.
정정 방법도 일반 서비스와 다릅니다. 틀린 전표를 UPDATE 로 고치면 안 됩니다. 원 전표를 거울처럼 뒤집은 역분개를 넣어 상쇄하고, 올바른 전표를 새로 기표합니다. 원장에 세 장이 나란히 남아야 두 달 뒤 감사에서 무슨 일이 있었는지 설명할 수 있습니다.
단계
/root/bank/gen_ledger.py를 만들어 실행해/root/bank/ledger.db를 만드세요. 계정 10개, 전표 201건, 분개행 430줄이 들어갑니다./root/bank/trial_balance.csv에 계정별 시산표를 뽑으세요. 머리글은code,name,debit,credit,balance이고balance는 차변합 빼기 대변합입니다. 한 번도 안 움직인 계정도 남깁니다./root/bank/tb_totals.txt에 네 줄을 적으세요.debit_total=,credit_total=,gap=은 원장에서,cached_sum=은accounts.cached_balance의 합입니다.- 전표별로 차변 합과 대변 합을 비교해 어긋난 전표를 찾고,
/root/bank/broken_entry.txt에entry_id=,debit=,credit=,gap=을 적으세요. 그 전표의 분개행은/root/bank/broken_lines.csv에line_id,entry_id,account_code,dc,amount머리글과 함께 그대로 뜹니다. /root/bank/balance_diff.csv에code,cached,ledger,gap머리글로 잔액 표와 원장 합산이 다른 계정만 남기세요.gap은cached에서ledger를 뺀 값입니다.- 원 전표를 손대지 말고 정정 전표 두 장을 넣으세요. 역분개는
JE-20260826-0134-R, 재기표는JE-20260826-0134-C로 등록하고journal과journal_line양쪽에 넣습니다. accounts.cached_balance를 원장 합산으로 다시 계산해 덮고,/root/bank/recheck.txt에debit_total=,credit_total=,gap=,unbalanced_entries=,original_credit=,cached_sum=,balance_diff_rows=일곱 줄을 적으세요./root/bank/ledger_report.md에## 무엇이 틀렸나,## 어떻게 찾았나,## 어떻게 고쳤나,## 잔액 표는 왜 못 잡았나,## 재발 방지다섯 절로 보고서를 쓰세요.
참고
sqlite3 -readonly <파일> "<쿼리>"로 읽으면 조사 중에 실수로 쓰는 일을 막을 수 있습니다.- CSV 로 뽑을 때는 표준입력으로
.headers on과.mode csv를 먼저 넘기세요:sqlite3 -readonly ledger.db > out.csv <<'SQL' ... SQL. - 부호 있는 잔액은
SUM(CASE dc WHEN 'D' THEN amount ELSE -amount END)로 한 번에 냅니다. - 흔한 실수 1: 2단계에서 움직임이 없는 계정을 표에서 빼는 것. 그러면 '움직임이 없다' 와 '계정이 없다' 가 구별되지 않습니다.
- 흔한 실수 2: 6단계에서 역분개 금액을 올바른 금액으로 쓰는 것. 기록된 금액 그대로 뒤집어야 틀림이 정확히 상쇄됩니다.
- 흔한 실수 3: 7단계에서 전표 단위 불일치가 0 이 되기를 기대하는 것. 원 전표와 역분개가 짝을 이뤄 남는 것이 정상입니다.
원장 스냅샷 만들기
/root/bank/gen_ledger.py 를 만들어 실행해 /root/bank/ledger.db 를 만드세요. 계정 10개, 전표 201건, 분개행 430줄이 들어갑니다.
먼저 /root/bank 를 만들고, 그 안에서 python3 로 sqlite DB 를 만듭니다. 표는 accounts, journal, journal_line 세 개이고 분개행은 430줄입니다.
시산표 만들기
/root/bank/trial_balance.csv 에 계정별 시산표를 뽑으세요. 머리글은 code,name,debit,credit,balance 이고 balance 는 차변합 빼기 대변합입니다. 한 번도 안 움직인 계정도 남깁니다.
계정마다 차변 금액의 합과 대변 금액의 합을 따로 내고, balance 는 차변합 빼기 대변합입니다. 이 사흘 동안 한 번도 안 움직인 계정도 표에 남아야 하니 LEFT JOIN 을 쓰세요.
원장과 잔액 표를 각각 세기
/root/bank/tb_totals.txt 에 네 줄을 적으세요. debit_total=, credit_total=, gap= 은 원장에서, cached_sum= 은 accounts.cached_balance 의 합입니다.
네 숫자입니다. 앞의 셋은 journal_line 에서, 마지막 하나는 accounts.cached_balance 에서 나옵니다. 두 표가 어긋난 크기가 다르다는 것이 이 단계의 발견입니다.
전표 한 건, 분개행 한 줄까지 좁히기
전표별로 차변 합과 대변 합을 비교해 어긋난 전표를 찾고, /root/bank/broken_entry.txt 에 entry_id=, debit=, credit=, gap= 을 적으세요. 그 전표의 분개행은 /root/bank/broken_lines.csv 에 line_id,entry_id,account_code,dc,amount 머리글과 함께 그대로 뜹니다.
전표별로 묶어 차변 합과 대변 합을 비교하세요. HAVING 절에 차이가 0 이 아니라는 조건을 걸면 한 건만 남습니다. 분개행은 값을 고치지 말고 있는 그대로 뜨세요.
잔액 표와 원장 합산 대사하기
/root/bank/balance_diff.csv 에 code,cached,ledger,gap 머리글로 잔액 표와 원장 합산이 다른 계정만 남기세요. gap 은 cached 에서 ledger 를 뺀 값입니다.
계정별로 accounts.cached_balance 와 원장 합산값을 나란히 놓고 다른 것만 남기세요. gap 은 cached 에서 ledger 를 뺀 값입니다. 두 줄이 나오는데 어긋난 이유가 서로 정반대입니다.
역분개와 재기표로 바로잡기
원 전표를 손대지 말고 정정 전표 두 장을 넣으세요. 역분개는 JE-20260826-0134-R, 재기표는 JE-20260826-0134-C 로 등록하고 journal 과 journal_line 양쪽에 넣습니다.
원 전표는 한 줄도 건드리지 않습니다. 역분개는 원 전표의 차변과 대변만 바꾸고 금액은 기록된 그대로 쓰세요. 그다음 올바른 금액으로 전표를 하나 더 넣습니다.
잔액 표를 원장에서 다시 만들기
accounts.cached_balance 를 원장 합산으로 다시 계산해 덮고, /root/bank/recheck.txt 에 debit_total=, credit_total=, gap=, unbalanced_entries=, original_credit=, cached_sum=, balance_diff_rows= 일곱 줄을 적으세요.
어긋나면 언제나 사본을 고칩니다. accounts.cached_balance 를 원장 합산으로 덮으세요. 그리고 전표 단위 불일치가 0 이 되기를 기대하지 마세요 — 역분개가 원 전표와 짝을 이뤄 남습니다.
원장 정합성 보고서 쓰기
/root/bank/ledger_report.md 에 ## 무엇이 틀렸나, ## 어떻게 찾았나, ## 어떻게 고쳤나, ## 잔액 표는 왜 못 잡았나, ## 재발 방지 다섯 절로 보고서를 쓰세요.
다섯 절이 필요합니다. 무엇이 틀렸나 절에는 전표 번호와 차이 금액을, 어떻게 고쳤나 절에는 역분개 전표 번호를, 잔액 표는 왜 못 잡았나 절에는 잔액만 어긋난 계정 번호와 금액을 적으세요.