fix: 적대적 코드리뷰 후속 — 신규 도메인 5건 버그 수정
서브에이전트 4영역 적대적 리뷰(P7/P8 서비스·매퍼·배치·어댑터)에서 확정된 결함 수정.
- [HIGH] HqSettleItem update 시 status가 NULL로 덮어써짐(SaveReq에 status 없음)
→ status = COALESCE(#{status}, status) 로 수정 불변 보장.
- [MED] 소개·이관수수료 RATE/FIXED 분기를 요청 commissionRate 유무로 판정 → 활성 룰의
calc_type 을 권위로 사용(FIXED=fixed_amount, RATE=요청rate||룰rate), 룰 없을 때만 요청rate 폴백.
- [MED] 지점장수당 cap 미적용(주석-코드 불일치) → SaveReq.capAmount 추가 + allowance = min(base×rate, cap).
- [MED] PUSH 외부호출 감사로그 요약 누락 → ExternalCallLoggingAspect applyRequest/applyResponse 에
PushRequest/PushResponse 분기 추가(토큰 마스킹, messageId/sent/resultCode).
- [LOW] 공동계약 update 지분율 검증 키 불일치 → 기존 레코드 contractId 기준으로 검증/갱신(계약 이동 불가).
배치 통합 리뷰 결과 CLEAN(무결성·집계·upsert 정확). 전체 ./gradlew build(test 포함) SUCCESSFUL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -116,6 +116,15 @@ public class ExternalCallLoggingAspect {
|
||||
m.put("refUserId", mr.getRefUserId());
|
||||
m.put("contentPreview", truncate(mr.getContent(), 80));
|
||||
vo.setRequestSummary(toJson(m));
|
||||
} else if (a0 instanceof com.ga.common.adapter.push.PushRequest pr) {
|
||||
vo.setTargetRefType(pr.getRefType());
|
||||
vo.setTargetRefId(pr.getRefId());
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("tokenMasked", maskToken(pr.getDeviceToken()));
|
||||
m.put("title", pr.getTitle());
|
||||
m.put("refUserId", pr.getRefUserId());
|
||||
m.put("bodyPreview", truncate(pr.getBody(), 80));
|
||||
vo.setRequestSummary(toJson(m));
|
||||
} else if (a0 instanceof String s) {
|
||||
// BankTransferAdapter.queryStatus(txId)
|
||||
vo.setRequestSummary("{\"arg\":\"" + safeJsonString(s) + "\"}");
|
||||
@@ -139,6 +148,14 @@ public class ExternalCallLoggingAspect {
|
||||
m.put("sent", mr.isSent());
|
||||
m.put("sentAt", mr.getSentAt());
|
||||
vo.setResponseSummary(toJson(m));
|
||||
} else if (result instanceof com.ga.common.adapter.push.PushResponse pr) {
|
||||
vo.setResultCode(pr.getResultCode());
|
||||
vo.setResultMessage(truncate(pr.getResultMessage(), 1000));
|
||||
Map<String, Object> m = new LinkedHashMap<>();
|
||||
m.put("messageId", pr.getMessageId());
|
||||
m.put("sent", pr.isSent());
|
||||
m.put("sentAt", pr.getSentAt());
|
||||
vo.setResponseSummary(toJson(m));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +190,11 @@ public class ExternalCallLoggingAspect {
|
||||
return name.charAt(0) + "*".repeat(Math.max(0, name.length() - 1));
|
||||
}
|
||||
|
||||
private String maskToken(String token) {
|
||||
if (token == null) return null;
|
||||
return token.length() <= 8 ? "****" : token.substring(0, 8) + "****";
|
||||
}
|
||||
|
||||
private String truncate(String s, int max) {
|
||||
if (s == null) return null;
|
||||
return s.length() <= max ? s : s.substring(0, max);
|
||||
|
||||
@@ -88,9 +88,9 @@ public class BranchAllowanceService {
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
BigDecimal clawback = req.getClawbackAmount() != null ? req.getClawbackAmount() : BigDecimal.ZERO;
|
||||
|
||||
// cap_amount는 SaveReq에 없으므로 allowanceRate와 동일 룰에서 cap 조회
|
||||
// positionCode가 req에 없어 단순 구현: raw 그대로 사용 (배치에서 룰 참조 시 위임)
|
||||
BigDecimal allowanceAmount = raw;
|
||||
// cap 적용: allowance = min(base×rate, cap). cap 미지정(NULL)이면 상한 없음.
|
||||
BigDecimal cap = req.getCapAmount();
|
||||
BigDecimal allowanceAmount = (cap != null && raw.compareTo(cap) > 0) ? cap : raw;
|
||||
|
||||
BranchMgrAllowanceLedgerVO vo = new BranchMgrAllowanceLedgerVO();
|
||||
vo.setManagerAgentId(req.getManagerAgentId());
|
||||
|
||||
@@ -56,10 +56,11 @@ public class JointContractService {
|
||||
public void update(Long jointId, JointContractSaveReq req) {
|
||||
JointContractResp resp = jointContractMapper.selectById(jointId);
|
||||
if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
|
||||
validateShareRate(req.getContractId(), jointId, req.getShareRate());
|
||||
// 계약 이동은 허용하지 않음 — 검증/갱신 모두 기존 레코드의 contractId 기준
|
||||
validateShareRate(resp.getContractId(), jointId, req.getShareRate());
|
||||
JointContractVO vo = new JointContractVO();
|
||||
vo.setJointId(jointId);
|
||||
vo.setContractId(req.getContractId());
|
||||
vo.setContractId(resp.getContractId());
|
||||
vo.setAgentId(req.getAgentId());
|
||||
vo.setRole(req.getRole());
|
||||
vo.setShareRate(req.getShareRate());
|
||||
|
||||
@@ -92,20 +92,30 @@ public class ReferralCommissionService {
|
||||
vo.setBaseAmount(req.getBaseAmount());
|
||||
vo.setCommissionRate(req.getCommissionRate());
|
||||
|
||||
// 소개·이관수수료 = base × rate (RATE) 또는 fixed_amount (FIXED)
|
||||
// 소개·이관수수료 계산: 활성 룰의 calc_type 이 권위(RATE=base×rate / FIXED=fixed_amount).
|
||||
// 룰이 없을 때만 요청 commissionRate 로 폴백(수동 등록 호환).
|
||||
ReferralCommissionRuleVO rule = ruleMapper.selectActiveRule(
|
||||
req.getReferralType(), java.time.LocalDate.now());
|
||||
BigDecimal commissionAmount;
|
||||
if (req.getCommissionRate() != null) {
|
||||
if (rule != null) {
|
||||
if ("FIXED".equals(rule.getCalcType())) {
|
||||
if (rule.getFixedAmount() == null) throw new BizException(ErrorCode.NOT_FOUND);
|
||||
commissionAmount = rule.getFixedAmount().setScale(2, RoundingMode.HALF_UP);
|
||||
vo.setCommissionRate(null);
|
||||
} else { // RATE
|
||||
BigDecimal rate = req.getCommissionRate() != null
|
||||
? req.getCommissionRate() : rule.getCommissionRate();
|
||||
if (rate == null) throw new BizException(ErrorCode.NOT_FOUND);
|
||||
vo.setCommissionRate(rate);
|
||||
commissionAmount = req.getBaseAmount().multiply(rate).setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
} else if (req.getCommissionRate() != null) {
|
||||
// 활성 룰 없음 → 요청 rate 로 수동 계산
|
||||
commissionAmount = req.getBaseAmount()
|
||||
.multiply(req.getCommissionRate())
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
} else {
|
||||
// FIXED: 룰에서 fixed_amount 조회
|
||||
ReferralCommissionRuleVO rule = ruleMapper.selectActiveRule(
|
||||
req.getReferralType(), java.time.LocalDate.now());
|
||||
if (rule == null || rule.getFixedAmount() == null) {
|
||||
throw new BizException(ErrorCode.NOT_FOUND);
|
||||
}
|
||||
commissionAmount = rule.getFixedAmount().setScale(2, RoundingMode.HALF_UP);
|
||||
throw new BizException(ErrorCode.NOT_FOUND);
|
||||
}
|
||||
vo.setCommissionAmount(commissionAmount);
|
||||
vo.setStatus("CALCULATED");
|
||||
|
||||
@@ -36,4 +36,8 @@ public class BranchMgrAllowanceLedgerSaveReq {
|
||||
|
||||
@DecimalMin("0")
|
||||
private BigDecimal clawbackAmount;
|
||||
|
||||
/** 수당 상한(룰의 cap_amount). 지정 시 allowance_amount = min(base×rate, cap). NULL이면 상한 없음. */
|
||||
@DecimalMin("0")
|
||||
private BigDecimal capAmount;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
item_name = #{itemName},
|
||||
amount = #{amount},
|
||||
memo = #{memo},
|
||||
status = #{status},
|
||||
status = COALESCE(#{status}, status),
|
||||
updated_at = NOW()
|
||||
WHERE item_id = #{itemId}
|
||||
</update>
|
||||
|
||||
Reference in New Issue
Block a user