diff --git a/ga-api/src/main/java/com/ga/api/aop/ExternalCallLoggingAspect.java b/ga-api/src/main/java/com/ga/api/aop/ExternalCallLoggingAspect.java index d626526..c94722b 100644 --- a/ga-api/src/main/java/com/ga/api/aop/ExternalCallLoggingAspect.java +++ b/ga-api/src/main/java/com/ga/api/aop/ExternalCallLoggingAspect.java @@ -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 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 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); diff --git a/ga-api/src/main/java/com/ga/api/service/commission/BranchAllowanceService.java b/ga-api/src/main/java/com/ga/api/service/commission/BranchAllowanceService.java index d59cb07..d29adf7 100644 --- a/ga-api/src/main/java/com/ga/api/service/commission/BranchAllowanceService.java +++ b/ga-api/src/main/java/com/ga/api/service/commission/BranchAllowanceService.java @@ -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()); diff --git a/ga-api/src/main/java/com/ga/api/service/commission/JointContractService.java b/ga-api/src/main/java/com/ga/api/service/commission/JointContractService.java index 8655adf..17db645 100644 --- a/ga-api/src/main/java/com/ga/api/service/commission/JointContractService.java +++ b/ga-api/src/main/java/com/ga/api/service/commission/JointContractService.java @@ -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()); diff --git a/ga-api/src/main/java/com/ga/api/service/commission/ReferralCommissionService.java b/ga-api/src/main/java/com/ga/api/service/commission/ReferralCommissionService.java index b93acc0..8c84747 100644 --- a/ga-api/src/main/java/com/ga/api/service/commission/ReferralCommissionService.java +++ b/ga-api/src/main/java/com/ga/api/service/commission/ReferralCommissionService.java @@ -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"); diff --git a/ga-core/src/main/java/com/ga/core/vo/commission/BranchMgrAllowanceLedgerSaveReq.java b/ga-core/src/main/java/com/ga/core/vo/commission/BranchMgrAllowanceLedgerSaveReq.java index 091089b..d0ede2c 100644 --- a/ga-core/src/main/java/com/ga/core/vo/commission/BranchMgrAllowanceLedgerSaveReq.java +++ b/ga-core/src/main/java/com/ga/core/vo/commission/BranchMgrAllowanceLedgerSaveReq.java @@ -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; } diff --git a/ga-core/src/main/resources/mapper/commission/HqSettleItemMapper.xml b/ga-core/src/main/resources/mapper/commission/HqSettleItemMapper.xml index cfd0c36..731f5d8 100644 --- a/ga-core/src/main/resources/mapper/commission/HqSettleItemMapper.xml +++ b/ga-core/src/main/resources/mapper/commission/HqSettleItemMapper.xml @@ -72,7 +72,7 @@ item_name = #{itemName}, amount = #{amount}, memo = #{memo}, - status = #{status}, + status = COALESCE(#{status}, status), updated_at = NOW() WHERE item_id = #{itemId}