feat: P5-W3 본론 완료 — 회계결산/이상치예측/연말명세서 (V74~V78)

P5-W2 원천세·부가세 분기신고 미커밋분 + P5-W3 메뉴/권한 보강(V74) + P5-W3 본론(V75~V78)을 일괄 정리.

- V75 accounting_close / account_balance_snapshot (회계 결산)
- V76 retention_anomaly_alert / forecast_kpi_monthly (이상치·예측 KPI)
- V77 year_end_statement (연말 지급명세서)
- V78 P5-W3 본론 메뉴 4 + 권한 + 공통코드 7그룹 + 테스트데이터
- api: AccountingClose/YearEndStatement/ForecastKpi/RetentionAnomaly Service+Controller
- batch: BatchConfig Step 11/12 (원천세·부가세 분기) 연결
- frontend: 4화면(AccountingClose/YearEndStatement/RetentionAnomaly/ForecastKpi) + API 모듈 4 + 라우트
- frontend: usePermission/PermissionButton EXECUTE 권한 누락 보강
- fix: YearEndStatementMapper.xml 미존재 컬럼 a.agent_code 참조 제거

통합검증: Flyway V74~V78 운영DB 적용(v78), 4모듈 compileJava + 프론트 build PASS,
스모크 GET 8/8 + 쓰기 4/4 PASS, verify_v74.py 20/20 PASS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
GA Pro
2026-05-21 22:22:34 +09:00
parent d5ed642c80
commit 49f08f001d
80 changed files with 4506 additions and 62 deletions
@@ -0,0 +1,33 @@
-- V77: 설계사 연말 지급명세서 (사업소득 지급명세서)
-- agent_annual_income(V63) 의 연 집계 데이터를 기반으로 설계사별 PDF/Excel 발급 마스터.
CREATE TABLE year_end_statement (
statement_id BIGSERIAL PRIMARY KEY,
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
statement_year INTEGER NOT NULL, -- 신고 연도 (예: 2025)
statement_type VARCHAR(20) NOT NULL DEFAULT 'INCOME_DEDUCTION',
-- INCOME_DEDUCTION=사업소득 지급명세서
total_income NUMERIC(18,2) NOT NULL DEFAULT 0, -- agent_annual_income.total_income 캐시
total_withheld NUMERIC(18,2) NOT NULL DEFAULT 0, -- agent_annual_income.total_withheld 캐시
total_local_tax NUMERIC(18,2) NOT NULL DEFAULT 0,
file_path VARCHAR(500), -- 생성된 PDF/Excel 경로
file_format VARCHAR(10) NOT NULL DEFAULT 'XLSX', -- XLSX / PDF
file_status VARCHAR(15) NOT NULL DEFAULT 'DRAFT', -- DRAFT / GENERATED / SENT
generated_at TIMESTAMP,
sent_at TIMESTAMP,
sent_to VARCHAR(200), -- 발송처(이메일/내부공유 등)
created_at TIMESTAMP NOT NULL DEFAULT now(),
created_by BIGINT,
updated_at TIMESTAMP NOT NULL DEFAULT now(),
updated_by BIGINT,
UNIQUE (agent_id, statement_year, statement_type),
CONSTRAINT chk_yes_format CHECK (file_format IN ('XLSX','PDF')),
CONSTRAINT chk_yes_status CHECK (file_status IN ('DRAFT','GENERATED','SENT'))
);
COMMENT ON TABLE year_end_statement IS '설계사 연말 지급명세서 발급 마스터';
COMMENT ON COLUMN year_end_statement.statement_type IS 'INCOME_DEDUCTION=사업소득 지급명세서';
COMMENT ON COLUMN year_end_statement.file_status IS 'DRAFT=대기, GENERATED=파일생성, SENT=발송완료';
CREATE INDEX idx_yes_year ON year_end_statement(statement_year);
CREATE INDEX idx_yes_status ON year_end_statement(file_status);
CREATE INDEX idx_yes_agent ON year_end_statement(agent_id, statement_year);