feat: P11(#1) 시상/신인시상 환수 — award_ledger 환수 처리 (PL 자율진행)

incar 유지율시상환수/신인도입유치자시상환수 대응. award_ledger(V92)는 지급만 있고
환수가 없던 갭. 정착지원금/생보운영지원/지점장수당의 clawback_amount+net_amount 패턴으로
통일(신인시상=award_type NEW_RECRUIT로 기존재 → 별도 테이블 불필요).

- DB(V114): award_ledger에 clawback_amount/net_amount 컬럼 추가 + net=award 백필 +
  CHECK(clawback>=0) + status CHECK에 CLAWED_BACK 추가(pg_constraint 동적 탐색 DROP/재생성).
- core: AwardLedgerVO/Resp/SaveReq에 clawbackAmount/netAmount. AwardLedgerMapper
  aggregateByAgent SUM(award_amount)→SUM(net_amount), insert에 두 컬럼, applyClawback UPDATE.
- api: AwardService.createLedger가 net=award−clawback 계산(clawback≤award 검증). 신규
  applyClawback(ledgerId, {clawbackAmount,reason}) — 초과/취소상태 E411, status=CLAWED_BACK.
  PUT /api/awards/ledgers/{id}/clawback.
- frontend: Award 원장 그리드에 환수액/실지급 컬럼 + 합계 + 환수처리 모달(PermissionButton UPDATE).
- AggregateStep 무변경: aggregateByAgent가 net 반환 → 환수가 other_commission 자동 차감,
  net<0이면 P9 환수채권 이월에 자연 연계.

검증: build+test SUCCESSFUL, Flyway V114(schema v114). 라이브: award 100000 원장 →
clawback 30000 → net 70000·CLAWED_BACK, 초과환수 200000 → E411, aggregate net=70000 반영
확인. 테스트 데이터 정리. 스펙 docs/DOMAIN_GAP_P11.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
GA Pro
2026-06-05 00:59:48 +09:00
parent 284ecc4203
commit 934e45d295
12 changed files with 307 additions and 18 deletions
+9
View File
@@ -262,9 +262,16 @@ export interface AwardLedgerRow extends Record<string, unknown> {
awardType: string;
baseAmount: number;
awardAmount: number;
clawbackAmount: number;
netAmount: number;
status: string;
}
export interface AwardClawbackReq {
clawbackAmount: number;
reason: string;
}
// ── P7: LifeSupport ───────────────────────────────
export interface LifeSupportRuleRow extends Record<string, unknown> {
ruleId: number;
@@ -472,6 +479,8 @@ export const commissionApi = {
unwrap<PageResponse<AwardLedgerRow>>(
api.get('/api/awards/ledgers', { params: p }),
),
awardLedgerClawback: (ledgerId: number, body: AwardClawbackReq) =>
unwrap<void>(api.put(`/api/awards/ledgers/${ledgerId}/clawback`, body)),
// ── P7: LifeSupport ───────────────────────────────
lifeSupportRules: (p?: Partial<CommissionSearchParam>) =>