LabHub
배우기 러닝패스 코스

The Language of Banking

Finding a Debit/Credit Imbalance in the Ledger

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

복식부기 원장에서 시작해, 차대변이 맞지 않는 전표 1건을 분개행 한 줄까지 좁혀 내고, 원 기록을 지우지 않는 방식으로 바로잡은 뒤, 잔액 표까지 원장에 맞춰 놓을 수 있게 됩니다.

왜 중요한가

은행 시스템에서 잔액은 저장된 값이 아니라 원장에서 계산해 내는 값입니다. 성능 때문에 계정마다 잔액 컬럼을 함께 들고 있지만, 그것은 원장의 사본이지 원본이 아닙니다.

이 구분이 조사에서 결정적인 이유는 이렇습니다. 잔액 하나는 그냥 숫자라서, 그 숫자만 보고는 맞는지 틀린지 알 방법이 없습니다. 반면 복식부기 원장은 자기 자신을 검증합니다 — 모든 거래가 차변과 대변 양쪽에 기록되므로 원장 전체의 차변 합과 대변 합은 반드시 같아야 하고, 이 항등식이 깨지면 그 자체가 사고 신호입니다. 그리고 그 신호는 전표 단위로 한 번 더 좁혀집니다.

이번 사건은 이렇습니다. 고객사 운영 담당자가 "결산 잔액이 안 맞는다" 고 연락해 왔습니다. 사흘치 원장에 어긋남이 두 군데 있는데, 성질이 서로 정반대입니다. 한쪽은 원장이 틀렸고 잔액 표가 맞으며, 다른 한쪽은 원장이 맞고 잔액 표가 틀렸습니다. 이 둘을 가르지 않고 손대면 고치는 쪽이 반대가 됩니다.

정정 방법도 일반 서비스와 다릅니다. 틀린 전표를 UPDATE 로 고치면 안 됩니다. 원 전표를 거울처럼 뒤집은 역분개를 넣어 상쇄하고, 올바른 전표를 새로 기표합니다. 원장에 세 장이 나란히 남아야 두 달 뒤 감사에서 무슨 일이 있었는지 설명할 수 있습니다.

단계

  1. /root/bank/gen_ledger.py 를 만들어 실행해 /root/bank/ledger.db 를 만드세요. 계정 10개, 전표 201건, 분개행 430줄이 들어갑니다.
  2. /root/bank/trial_balance.csv 에 계정별 시산표를 뽑으세요. 머리글은 code,name,debit,credit,balance 이고 balance 는 차변합 빼기 대변합입니다. 한 번도 안 움직인 계정도 남깁니다.
  3. /root/bank/tb_totals.txt 에 네 줄을 적으세요. debit_total=, credit_total=, gap= 은 원장에서, cached_sum=accounts.cached_balance 의 합입니다.
  4. 전표별로 차변 합과 대변 합을 비교해 어긋난 전표를 찾고, /root/bank/broken_entry.txtentry_id=, debit=, credit=, gap= 을 적으세요. 그 전표의 분개행은 /root/bank/broken_lines.csvline_id,entry_id,account_code,dc,amount 머리글과 함께 그대로 뜹니다.
  5. /root/bank/balance_diff.csvcode,cached,ledger,gap 머리글로 잔액 표와 원장 합산이 다른 계정만 남기세요. gapcached 에서 ledger 를 뺀 값입니다.
  6. 원 전표를 손대지 말고 정정 전표 두 장을 넣으세요. 역분개는 JE-20260826-0134-R, 재기표는 JE-20260826-0134-C 로 등록하고 journaljournal_line 양쪽에 넣습니다.
  7. accounts.cached_balance 를 원장 합산으로 다시 계산해 덮고, /root/bank/recheck.txtdebit_total=, credit_total=, gap=, unbalanced_entries=, original_credit=, cached_sum=, balance_diff_rows= 일곱 줄을 적으세요.
  8. /root/bank/ledger_report.md## 무엇이 틀렸나, ## 어떻게 찾았나, ## 어떻게 고쳤나, ## 잔액 표는 왜 못 잡았나, ## 재발 방지 다섯 절로 보고서를 쓰세요.

참고

원장 스냅샷 만들기

/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.txtentry_id=, debit=, credit=, gap= 을 적으세요. 그 전표의 분개행은 /root/bank/broken_lines.csvline_id,entry_id,account_code,dc,amount 머리글과 함께 그대로 뜹니다.

전표별로 묶어 차변 합과 대변 합을 비교하세요. HAVING 절에 차이가 0 이 아니라는 조건을 걸면 한 건만 남습니다. 분개행은 값을 고치지 말고 있는 그대로 뜨세요.

잔액 표와 원장 합산 대사하기

/root/bank/balance_diff.csvcode,cached,ledger,gap 머리글로 잔액 표와 원장 합산이 다른 계정만 남기세요. gapcached 에서 ledger 를 뺀 값입니다.

계정별로 accounts.cached_balance 와 원장 합산값을 나란히 놓고 다른 것만 남기세요. gap 은 cached 에서 ledger 를 뺀 값입니다. 두 줄이 나오는데 어긋난 이유가 서로 정반대입니다.

역분개와 재기표로 바로잡기

원 전표를 손대지 말고 정정 전표 두 장을 넣으세요. 역분개는 JE-20260826-0134-R, 재기표는 JE-20260826-0134-C 로 등록하고 journaljournal_line 양쪽에 넣습니다.

원 전표는 한 줄도 건드리지 않습니다. 역분개는 원 전표의 차변과 대변만 바꾸고 금액은 기록된 그대로 쓰세요. 그다음 올바른 금액으로 전표를 하나 더 넣습니다.

잔액 표를 원장에서 다시 만들기

accounts.cached_balance 를 원장 합산으로 다시 계산해 덮고, /root/bank/recheck.txtdebit_total=, credit_total=, gap=, unbalanced_entries=, original_credit=, cached_sum=, balance_diff_rows= 일곱 줄을 적으세요.

어긋나면 언제나 사본을 고칩니다. accounts.cached_balance 를 원장 합산으로 덮으세요. 그리고 전표 단위 불일치가 0 이 되기를 기대하지 마세요 — 역분개가 원 전표와 짝을 이뤄 남습니다.

원장 정합성 보고서 쓰기

/root/bank/ledger_report.md## 무엇이 틀렸나, ## 어떻게 찾았나, ## 어떻게 고쳤나, ## 잔액 표는 왜 못 잡았나, ## 재발 방지 다섯 절로 보고서를 쓰세요.

다섯 절이 필요합니다. 무엇이 틀렸나 절에는 전표 번호와 차이 금액을, 어떻게 고쳤나 절에는 역분개 전표 번호를, 잔액 표는 왜 못 잡았나 절에는 잔액만 어긋난 계정 번호와 금액을 적으세요.