- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경 - DB 연결 하드코딩 → .env 기반으로 변경 - MySQL strict mode DATE 오류 수정
계좌별 잔액 계산 로직 (개발자 문서)
목적
- 본 문서는
account/list.php에서 구현된 계좌별 잔액 계산 원리를 정리합니다. - 다른 회사(다른 DB/스키마)에도 동일한 원리로 구현할 수 있도록 단계별 절차와 AI 지시 템플릿을 제공합니다.
전제 및 데이터 모델 요약
- 테이블:
account(변수$_POST['tablename']또는$tablename으로 주입) - 핵심 컬럼
registDate: 거래 등록일자 (yyyy-mm-dd)inoutsep: 구분 (수입 | 지출 | 최초전월이월)amount: 금액 (문자열 저장, 천단위 콤마 포함 가능)bankbook: 계좌 표시명 (예: 기업은행 123-456-7890 (법인), 전자어음 등)dueDate: 만기일자 (어음성 항목에 사용, 없는 경우 '0000-00-00' 또는 NULL 또는 빈문자)endorsementDate: 배서일자 (전자어음 지출 시 사용)is_deleted: 논리 삭제 여부 (0만 유효 데이터)
- 금액 계산 시 DB 내
amount가 문자열+콤마 형태이므로 SQL에서REPLACE(amount, ',', '')로 숫자 변환 후 합산합니다. - 어음 처리: 기본 합산에서 어음(만기설정)의 잔액 반영을 제한하고, 전자어음은 별도 규칙을 적용합니다(아래 참조).
전체(기간 기반) 집계 로직
- 기간 시작 이전의 초기 잔액
SELECT
SUM(CASE WHEN inoutsep = '수입' THEN REPLACE(amount, ',', '') ELSE 0 END) +
SUM(CASE WHEN inoutsep = '최초전월이월' THEN REPLACE(amount, ',', '') ELSE 0 END) -
SUM(CASE WHEN inoutsep = '지출' THEN REPLACE(amount, ',', '') ELSE 0 END) AS balance
FROM account
WHERE is_deleted = '0'
AND registDate < :fromdate
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
- 기간 내 수입 합계(최초전월이월 포함)
SELECT SUM(REPLACE(amount, ',', '')) AS totalIncome
FROM account
WHERE is_deleted = '0'
AND (inoutsep = '수입' OR inoutsep = '최초전월이월')
AND registDate BETWEEN :fromdate AND :todate
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
- 기간 내 지출 합계
SELECT SUM(REPLACE(amount, ',', '')) AS totalExpense
FROM account
WHERE is_deleted = '0'
AND inoutsep = '지출'
AND registDate BETWEEN :fromdate AND :todate
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
- 최종 잔액 계산
$finalBalance = $initialBalance + $totalIncome - $totalExpense;
요점
- 초기 잔액은 기간 시작 이전의 누적(수입+전월이월-지출)입니다.
- 기간 내 수입/지출은 어음 미반영(만기 미설정 또는 공백만 포함) 기준으로 합산합니다.
- 최종 잔액은 초기 + (기간 내 수입) - (기간 내 지출) 입니다.
계좌별 집계(전체 기간 최종 잔액)
- 모든 기간을 대상으로 계좌별 순증감(수입+전월이월-지출)을 합산합니다.
SELECT
(SUM(CASE WHEN inoutsep IN ('수입','최초전월이월') THEN REPLACE(amount, ',', '') ELSE 0 END) -
SUM(CASE WHEN inoutsep = '지출' THEN REPLACE(amount, ',', '') ELSE 0 END)) AS balance
FROM account
WHERE is_deleted = '0'
AND bankbook = :bankbook
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')
표시 규칙
- 계좌명에 'USD'가 포함되면 금액 앞에
$를 붙여 표시합니다(회사 설정에 따라 변경 가능).
계좌별 기간 요약(초기/기간 내 수입/지출/최종)
각 계좌별로 아래 4단계를 수행합니다.
- 기간 시작 이전 잔액(초기)
- 기간 내 수입 (수입, 최초전월이월)
- 기간 내 지출
- 최종 = 초기 + 수입 - 지출
각 단계는 위의 전체 집계와 동일한 필터를 사용하며 bankbook = :bankbook 조건만 추가하면 됩니다.
목록 테이블의 행별 러닝 잔액(계좌별)
- 페이지 로딩 시, 각 계좌별로 "기간 시작 이전" 기준의 초기 잔액을 구해
runningBalances[계좌명]에 저장합니다. - 목록을 순차로 렌더링하며, (어음이 아닌 경우에 한해) 해당 계좌의 수입/지출에 따라 러닝 잔액을 가감합니다.
- 전자어음은 계좌명이 '전자어음'인 경우에 한해 별도 규칙으로 러닝 잔액 반영을 허용합니다.
어음 반영 조건
// dueDate가 비어있거나 '0000-00-00'이면 현금성으로 간주하여 러닝 잔액에 반영
// 또는 계좌가 '전자어음'이면 러닝 잔액에 반영
if ($dueDate === '0000-00-00' || !$dueDate || $dueDate === '' || $bankbook === '전자어음') {
if ($row['inoutsep'] === '수입' || $row['inoutsep'] === '최초전월이월') {
$runningBalances[$bankbook] += $amount;
} else {
$runningBalances[$bankbook] -= $amount;
}
}
계좌 목록 소스
- 파일:
/account/accoutlist.json(오타 주의: accoutlist.json) - 구조 예시
[
{ "company": "기업은행", "number": "123-456-7890", "memo": "법인" },
{ "company": "신한은행", "number": "111-222-3333", "memo": "일반" }
]
- 화면 및 계산 시 표기는
company + ' ' + number (+ ' (' + memo + ')')조합 문자열을 사용합니다.
표시 포맷 규칙
- 금액은
number_format()으로 천단위 콤마 표시 - 계좌명이 'USD'를 포함하면
$' + number_format()으로 표기
구현 체크리스트 (PHP 7.3 호환)
- 모든 합산 SQL에서
REPLACE(amount, ',', '')로 문자열 금액을 정수로 변환 is_deleted = 0필터 일관 유지- 어음성 거래 제외 조건:
(dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '') - 러닝 잔액 반영 시 전자어음(
bankbook === '전자어음') 예외 허용 accoutlist.json파싱 및 표기 문자열 일치- USD 계좌 표기 시
$접두사 적용 - PDO 바인딩 사용 및 SQL 인젝션 방지
- PHP 7.3 문법/함수만 사용 (타입힌트 과도 사용 지양, 최신 문법 미사용)
다른 회사 코드에 이식하기 (필드명/테이블명 상이 시)
- 테이블/컬럼 매핑 정의
TABLE_ACCOUNT,COL_DATE,COL_INOUT,COL_AMOUNT,COL_BANKBOOK,COL_DUE,COL_DELETE
- 모든 SQL에서 위 매핑을 사용하여 동등한 쿼리 작성
- 금액은 문자열+콤마 저장 전제 →
REPLACE()사용 또는 마이그레이션 - 어음 제외 조건/전자어음 예외를 비즈니스 규칙에 맞게 조정
- 계좌 표기 포맷(회사명/계좌번호/메모) 규칙 수립
- 통화 표기(USD 등) 접두사/접미사 정책 정의 후 적용
예시 의사코드
-- 초기 잔액 (기간 시작 이전)
SELECT
SUM(CASE WHEN COL_INOUT IN ('수입','최초전월이월') THEN REPLACE(COL_AMOUNT, ',', '') ELSE 0 END) -
SUM(CASE WHEN COL_INOUT = '지출' THEN REPLACE(COL_AMOUNT, ',', '') ELSE 0 END) AS balance
FROM TABLE_ACCOUNT
WHERE COL_DELETE = 0 AND COL_DATE < :fromdate
AND (COL_DUE = '0000-00-00' OR COL_DUE IS NULL OR COL_DUE = '')
-- 기간 내 수입/지출 및 최종 잔액, 계좌별 요약은 동일한 패턴
인공지능(AI) 지시 템플릿
아래 지시문을 프로젝트 상황에 맞게 값만 치환하여 사용하세요.
당신은 PHP 7.3 호환 코드를 작성하는 백엔드 개발자입니다.
목표: [TABLE_ACCOUNT]에서 기간별 전체 잔액과 계좌별 잔액 요약, 목록용 러닝 잔액을 계산하는 기능을 구현하세요.
요구사항:
- 공통 필터: is_deleted = 0. 어음 제외 조건: (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '').
- 초기 잔액: 기간 시작 이전의 (수입 + 최초전월이월 - 지출).
- 기간 내 합계: 수입(수입 + 최초전월이월), 지출.
- 최종 잔액: 초기 + 수입 - 지출.
- 계좌별 요약: 각 계좌에 대해 초기/수입/지출/최종을 별도 계산.
- 목록용 러닝 잔액: 각 계좌의 초기 잔액으로 시작하여 행을 순회하며 가감. 단, 전자어음은 계좌명이 '전자어음'이면 반영 허용.
- 금액은 문자열+콤마 저장 전제이므로 SQL에서 REPLACE로 정수 변환.
- 표기: 천단위 콤마, 계좌명이 'USD' 포함 시 금액 앞에 '$' 접두사.
입력 변수:
- fromdate, todate (yyyy-mm-dd), 선택 필터: inoutsep_select, content_select
출력:
- finalBalance, accountFinalBalances[], accountSummaries[], 목록 행별 runningBalances 적용 결과
검증:
- 샘플 데이터로 수작업 계산값과 SQL 집계 결과 일치 검증
- dueDate가 설정된 어음 거래가 합계에서 적절히 제외되는지 확인
성능/운영 팁
registDate,inoutsep,bankbook,is_deleted,dueDate에 조합 인덱스 고려- 금액은 가능하면 정수 컬럼으로 정규화(문자열 저장 유지 시
REPLACE비용 감안) - 대용량 환경에서 계좌 요약은 캐시 또는 미리 집계 테이블 고려
관련 파일
account/list.php: 화면 및 집계 로직 구현account/accoutlist.json: 계좌 목록 소스account/fetch_modal.php: 항목/세부항목 옵션 로딩account/insert.php,account/insert_bulk.php: 등록/대량등록 처리