From 44dbbf37daa246117819549efa429950fa1d49c3 Mon Sep 17 00:00:00 2001 From: GA Pro Date: Wed, 13 May 2026 00:53:47 +0900 Subject: [PATCH] =?UTF-8?q?feat(core):=20ChargebackGrade=20VO=20=EC=84=B8?= =?UTF-8?q?=ED=8A=B8=20+=20Mapper=20(=EB=8F=84=EB=A9=94=EC=9D=B8=20P1-3-b)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V28 chargeback_grade와 ga-core 동기화. 차등 환수 비즈니스 로직은 P1-3-c. 신규 패키지: com.ga.core.vo.chargeback, com.ga.core.mapper.chargeback VO 세트: - ChargebackGradeVO (BaseVO 상속, monthsFrom/monthsTo NULL=무한대) - ChargebackGradeResp (productCategoryName + monthsRange 표시 문자열) - ChargebackGradeSaveReq (@Valid: @Min(0) monthsFrom/percent) - ChargebackGradeSearchParam (productCategory/monthsElapsed/effectiveDate) ChargebackGradeMapper: - 표준 CRUD - selectByMonths(productCategory, monthsElapsed, baseDate) → 해당 경과월에 적용되는 환수 비율 1건 (months_from <= monthsElapsed AND (months_to IS NULL OR months_to >= monthsElapsed)) + 유효기간 + product_category NULL 안전 비교 + LIMIT 1 최신 우선 - selectAll(baseDate) — months_from ASC + product_category NULLS FIRST - selectByCategory(productCategory, baseDate) XML 공통 activeCondition SQL fragment로 중복 제거. --- .../chargeback/ChargebackGradeMapper.java | 37 ++++ .../vo/chargeback/ChargebackGradeResp.java | 20 ++ .../vo/chargeback/ChargebackGradeSaveReq.java | 30 +++ .../ChargebackGradeSearchParam.java | 13 ++ .../core/vo/chargeback/ChargebackGradeVO.java | 24 +++ .../chargeback/ChargebackGradeMapper.xml | 188 ++++++++++++++++++ 6 files changed, 312 insertions(+) create mode 100644 ga-core/src/main/java/com/ga/core/mapper/chargeback/ChargebackGradeMapper.java create mode 100644 ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeResp.java create mode 100644 ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeSaveReq.java create mode 100644 ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeSearchParam.java create mode 100644 ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeVO.java create mode 100644 ga-core/src/main/resources/mapper/chargeback/ChargebackGradeMapper.xml diff --git a/ga-core/src/main/java/com/ga/core/mapper/chargeback/ChargebackGradeMapper.java b/ga-core/src/main/java/com/ga/core/mapper/chargeback/ChargebackGradeMapper.java new file mode 100644 index 0000000..bbcc5f1 --- /dev/null +++ b/ga-core/src/main/java/com/ga/core/mapper/chargeback/ChargebackGradeMapper.java @@ -0,0 +1,37 @@ +package com.ga.core.mapper.chargeback; + +import com.ga.core.vo.chargeback.ChargebackGradeResp; +import com.ga.core.vo.chargeback.ChargebackGradeSearchParam; +import com.ga.core.vo.chargeback.ChargebackGradeVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface ChargebackGradeMapper { + + List selectList(ChargebackGradeSearchParam param); + + ChargebackGradeResp selectDetailById(@Param("gradeId") Long gradeId); + + ChargebackGradeVO selectById(@Param("gradeId") Long gradeId); + + /** 해약 경과월에 적용되는 환수 비율 구간 1건 조회 (차등 환수 계산 핵심) */ + ChargebackGradeVO selectByMonths(@Param("productCategory") String productCategory, + @Param("monthsElapsed") Integer monthsElapsed, + @Param("baseDate") String baseDate); + + /** 특정 시점 활성 전체 구간 조회 (months_from ASC) */ + List selectAll(@Param("baseDate") String baseDate); + + /** 카테고리별 활성 구간 조회 */ + List selectByCategory(@Param("productCategory") String productCategory, + @Param("baseDate") String baseDate); + + int insert(ChargebackGradeVO vo); + + int update(ChargebackGradeVO vo); + + int updateStatus(@Param("gradeId") Long gradeId, @Param("isActive") Boolean isActive); +} diff --git a/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeResp.java b/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeResp.java new file mode 100644 index 0000000..e4edca9 --- /dev/null +++ b/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeResp.java @@ -0,0 +1,20 @@ +package com.ga.core.vo.chargeback; + +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; + +@Data +public class ChargebackGradeResp { + private Long gradeId; + private String productCategory; + private String productCategoryName; + private Integer monthsFrom; + private Integer monthsTo; + private String monthsRange; // "1~12개월", "85개월 이상" 형태 표시용 + private BigDecimal chargebackPercent; + private LocalDate effectiveFrom; + private LocalDate effectiveTo; + private Boolean isActive; +} diff --git a/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeSaveReq.java b/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeSaveReq.java new file mode 100644 index 0000000..3f8c118 --- /dev/null +++ b/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeSaveReq.java @@ -0,0 +1,30 @@ +package com.ga.core.vo.chargeback; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; + +@Data +public class ChargebackGradeSaveReq { + + private String productCategory; // NULL = 전체 상품 + + @NotNull(message = "경과월 시작은 필수입니다") + @Min(value = 0, message = "경과월 시작은 0 이상이어야 합니다") + private Integer monthsFrom; + + private Integer monthsTo; // NULL = 무한대 + + @NotNull(message = "환수율은 필수입니다") + @Min(value = 0, message = "환수율은 0 이상이어야 합니다") + private BigDecimal chargebackPercent; + + @NotNull(message = "적용 시작일은 필수입니다") + private LocalDate effectiveFrom; + + private LocalDate effectiveTo; +} diff --git a/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeSearchParam.java b/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeSearchParam.java new file mode 100644 index 0000000..5eed351 --- /dev/null +++ b/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeSearchParam.java @@ -0,0 +1,13 @@ +package com.ga.core.vo.chargeback; + +import com.ga.common.model.SearchParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ChargebackGradeSearchParam extends SearchParam { + private String productCategory; + private Integer monthsElapsed; // 해당 경과월에 해당하는 구간 필터 + private String effectiveDate; // YYYY-MM-DD — 해당 날짜 유효 구간 필터 +} diff --git a/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeVO.java b/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeVO.java new file mode 100644 index 0000000..23ea627 --- /dev/null +++ b/ga-core/src/main/java/com/ga/core/vo/chargeback/ChargebackGradeVO.java @@ -0,0 +1,24 @@ +package com.ga.core.vo.chargeback; + +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Data +public class ChargebackGradeVO { + private Long gradeId; + private String productCategory; // NULL = ALL 상품 + private Integer monthsFrom; // 해약 경과월 시작 (이상) + private Integer monthsTo; // 해약 경과월 종료 (이하), NULL = 무한대 + private BigDecimal chargebackPercent; + private LocalDate effectiveFrom; + private LocalDate effectiveTo; // NULL = 현재 유효 + private Boolean isActive; + + private LocalDateTime createdAt; + private Long createdBy; + private LocalDateTime updatedAt; + private Long updatedBy; +} diff --git a/ga-core/src/main/resources/mapper/chargeback/ChargebackGradeMapper.xml b/ga-core/src/main/resources/mapper/chargeback/ChargebackGradeMapper.xml new file mode 100644 index 0000000..2cb9882 --- /dev/null +++ b/ga-core/src/main/resources/mapper/chargeback/ChargebackGradeMapper.xml @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g.grade_id, + g.product_category, + (SELECT cc.code_name FROM common_code cc + WHERE cc.group_code = 'PRODUCT_CATEGORY' AND cc.code = g.product_category) AS product_category_name, + g.months_from, + g.months_to, + CASE + WHEN g.months_to IS NULL THEN g.months_from || '개월 이상' + ELSE g.months_from || '~' || g.months_to || '개월' + END AS months_range, + g.chargeback_percent, + g.effective_from, + g.effective_to, + g.is_active + + + + + AND g.is_active = TRUE + AND g.effective_from <= #{baseDate}::DATE + AND (g.effective_to IS NULL OR g.effective_to >= #{baseDate}::DATE) + + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO chargeback_grade ( + product_category, months_from, months_to, + chargeback_percent, effective_from, effective_to, + is_active, created_at, created_by + ) VALUES ( + #{productCategory}, #{monthsFrom}, #{monthsTo}, + #{chargebackPercent}, #{effectiveFrom}, #{effectiveTo}, + COALESCE(#{isActive}, TRUE), NOW(), #{createdBy} + ) + + + + + + UPDATE chargeback_grade + + months_from = #{monthsFrom}, + months_to = #{monthsTo}, + chargeback_percent = #{chargebackPercent}, + effective_from = #{effectiveFrom}, + effective_to = #{effectiveTo}, + is_active = #{isActive}, + updated_at = NOW(), + updated_by = #{updatedBy} + + WHERE grade_id = #{gradeId} + + + + + UPDATE chargeback_grade + SET is_active = #{isActive}, updated_at = NOW() + WHERE grade_id = #{gradeId} + + +