fix: 잔여 백로그 전건 처리 — 회계 예수금/1200%clip/환수가드/net경보 (PL 자율진행)

- fix(a, MED): 회계 분개에 원천세 예수금 leg 분리. (차)8350 지급수수료 gross /
  (대)2530 미지급금 net + (대)2540 예수금 원천세. 기존엔 미지급금에 gross 계상 +
  원천세 분개 누락. account_code '2540' 예수금 추가(V110), 분개쿼리 2-leg 전환.
- fix(b, HIGH): 1200%룰 1차년 한도초과 시 clip+이연. 한도잔여까지만 당월 지급,
  초과분만 분급(7년)으로 이연. 전액 이연 시 당월 원장 미생성 + 세액 재계산.
  (기존: 전액지급 + 전액 분급계획 → 설계 불일치)
- fix(e/f, HIGH/MED): 정착지원금/생보운영지원 환수액 ≤ 지원금 검증으로 net 음수 차단.
  AggregateStep net 음수(공제>지급) 경보 로깅 추가.
- (g) 검토결과 무변경: TaxCalculator/BatchTaxCalculator는 의도된 동일로직 쌍둥이,
  V80 매직팩터는 샘플시드일 뿐 계산경로 아님. 두 쌍둥이 모두 음수가드 적용됨.
- (d) 무변경: 승계 "최신 to_agent=현재귀속자"는 다단계체인에 정합, from==agent_id
  가드는 체인 회귀 유발하므로 정책확정 전 보류(문서화).
- test: CalcRecruitStepTest(clip+이연), SettlingSupportServiceTest(환수>지원 거부).
- 전체 build+test GREEN: 155건 0실패.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
GA Pro
2026-06-03 11:27:53 +09:00
parent 60c4cbae78
commit e2fdc88754
8 changed files with 207 additions and 30 deletions
@@ -85,6 +85,12 @@ public class LifeSupportService {
.multiply(req.getSupportRate())
.setScale(2, RoundingMode.HALF_UP);
BigDecimal clawback = req.getClawbackAmount() != null ? req.getClawbackAmount() : BigDecimal.ZERO;
// 환수액은 음수 불가, 지원수수료 초과 불가 (net 음수 방지)
if (clawback.signum() < 0 || clawback.compareTo(supportAmount) > 0) {
throw new BizException(ErrorCode.BAD_REQUEST,
String.format("환수액(%s)은 0 이상이며 지원수수료(%s)를 초과할 수 없습니다",
clawback, supportAmount));
}
// 실지급액 = support - clawback
BigDecimal netAmount = supportAmount.subtract(clawback).setScale(2, RoundingMode.HALF_UP);
@@ -85,6 +85,12 @@ public class SettlingSupportService {
@Transactional
public Long createLedger(SettlingSupportLedgerSaveReq req) {
BigDecimal clawback = req.getClawbackAmount() != null ? req.getClawbackAmount() : BigDecimal.ZERO;
// 환수액은 음수 불가, 지원금 초과 불가 (net 음수 방지)
if (clawback.signum() < 0 || clawback.compareTo(req.getSupportAmount()) > 0) {
throw new BizException(ErrorCode.BAD_REQUEST,
String.format("환수액(%s)은 0 이상이며 지원금(%s)을 초과할 수 없습니다",
clawback, req.getSupportAmount()));
}
// 실지급액 = support_amount - clawback_amount
BigDecimal netAmount = req.getSupportAmount()
.subtract(clawback)
@@ -14,7 +14,13 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import com.ga.common.exception.BizException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
@@ -62,4 +68,18 @@ class SettlingSupportServiceTest {
assertThat(saved.getNetAmount()).isEqualByComparingTo("300000.00");
assertThat(saved.getClawbackAmount()).isEqualByComparingTo("0");
}
@Test
@DisplayName("createLedger: 환수액이 지원금을 초과하면 거부(net 음수 방지) — 원장 미생성")
void createLedger_clawbackExceedsSupport_rejected() {
SettlingSupportLedgerSaveReq req = new SettlingSupportLedgerSaveReq();
req.setAgentId(1L);
req.setSettleMonth("202506");
req.setSupportAmount(new BigDecimal("300000"));
req.setClawbackAmount(new BigDecimal("400000")); // 지원금 초과
assertThatThrownBy(() -> service.createLedger(req))
.isInstanceOf(BizException.class);
verify(ledgerMapper, never()).insert(any());
}
}