feat(core): ChargebackGrade VO 세트 + Mapper (도메인 P1-3-b)
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로 중복 제거.
This commit is contained in:
@@ -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<ChargebackGradeResp> 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<ChargebackGradeVO> selectAll(@Param("baseDate") String baseDate);
|
||||||
|
|
||||||
|
/** 카테고리별 활성 구간 조회 */
|
||||||
|
List<ChargebackGradeVO> 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);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 — 해당 날짜 유효 구간 필터
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.ga.core.mapper.chargeback.ChargebackGradeMapper">
|
||||||
|
|
||||||
|
<!-- ==================== ResultMap ==================== -->
|
||||||
|
|
||||||
|
<!-- chargeback_grade 테이블 1:1 매핑 (CUD용) -->
|
||||||
|
<resultMap id="VOMap" type="com.ga.core.vo.chargeback.ChargebackGradeVO">
|
||||||
|
<id property="gradeId" column="grade_id"/>
|
||||||
|
<result property="productCategory" column="product_category"/>
|
||||||
|
<result property="monthsFrom" column="months_from"/>
|
||||||
|
<result property="monthsTo" column="months_to"/>
|
||||||
|
<result property="chargebackPercent" column="chargeback_percent"/>
|
||||||
|
<result property="effectiveFrom" column="effective_from"/>
|
||||||
|
<result property="effectiveTo" column="effective_to"/>
|
||||||
|
<result property="isActive" column="is_active"/>
|
||||||
|
<result property="createdAt" column="created_at"/>
|
||||||
|
<result property="createdBy" column="created_by"/>
|
||||||
|
<result property="updatedAt" column="updated_at"/>
|
||||||
|
<result property="updatedBy" column="updated_by"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- 코드명 + monthsRange 포함 API 응답용 -->
|
||||||
|
<resultMap id="RespMap" type="com.ga.core.vo.chargeback.ChargebackGradeResp">
|
||||||
|
<id property="gradeId" column="grade_id"/>
|
||||||
|
<result property="productCategory" column="product_category"/>
|
||||||
|
<result property="productCategoryName" column="product_category_name"/>
|
||||||
|
<result property="monthsFrom" column="months_from"/>
|
||||||
|
<result property="monthsTo" column="months_to"/>
|
||||||
|
<result property="monthsRange" column="months_range"/>
|
||||||
|
<result property="chargebackPercent" column="chargeback_percent"/>
|
||||||
|
<result property="effectiveFrom" column="effective_from"/>
|
||||||
|
<result property="effectiveTo" column="effective_to"/>
|
||||||
|
<result property="isActive" column="is_active"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- ==================== 공통 SELECT 컬럼 ==================== -->
|
||||||
|
|
||||||
|
<sql id="selectRespCols">
|
||||||
|
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
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<!-- 활성 유효기간 공통 조건 -->
|
||||||
|
<sql id="activeCondition">
|
||||||
|
AND g.is_active = TRUE
|
||||||
|
AND g.effective_from <= #{baseDate}::DATE
|
||||||
|
AND (g.effective_to IS NULL OR g.effective_to >= #{baseDate}::DATE)
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<!-- ==================== SELECT ==================== -->
|
||||||
|
|
||||||
|
<!-- 목록 조회 (검색 조건 + 페이징) -->
|
||||||
|
<select id="selectList" parameterType="com.ga.core.vo.chargeback.ChargebackGradeSearchParam"
|
||||||
|
resultMap="RespMap">
|
||||||
|
SELECT <include refid="selectRespCols"/>
|
||||||
|
FROM chargeback_grade g
|
||||||
|
<where>
|
||||||
|
<if test="productCategory != null and productCategory != ''">
|
||||||
|
AND g.product_category = #{productCategory}
|
||||||
|
</if>
|
||||||
|
<if test="monthsElapsed != null">
|
||||||
|
AND g.months_from <= #{monthsElapsed}
|
||||||
|
AND (g.months_to IS NULL OR g.months_to >= #{monthsElapsed})
|
||||||
|
</if>
|
||||||
|
<if test="effectiveDate != null and effectiveDate != ''">
|
||||||
|
AND g.effective_from <= #{effectiveDate}::DATE
|
||||||
|
AND (g.effective_to IS NULL OR g.effective_to >= #{effectiveDate}::DATE)
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
ORDER BY g.months_from, g.effective_from DESC
|
||||||
|
<if test="pageSize != null and pageSize > 0">
|
||||||
|
LIMIT #{pageSize} OFFSET #{offset}
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 단건 조회 (Resp: 코드명 포함) -->
|
||||||
|
<select id="selectDetailById" resultMap="RespMap">
|
||||||
|
SELECT <include refid="selectRespCols"/>
|
||||||
|
FROM chargeback_grade g
|
||||||
|
WHERE g.grade_id = #{gradeId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 단건 조회 (VO: CUD용) -->
|
||||||
|
<select id="selectById" resultMap="VOMap">
|
||||||
|
SELECT grade_id, product_category, months_from, months_to,
|
||||||
|
chargeback_percent, effective_from, effective_to, is_active,
|
||||||
|
created_at, created_by, updated_at, updated_by
|
||||||
|
FROM chargeback_grade
|
||||||
|
WHERE grade_id = #{gradeId}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
해약 경과월에 적용되는 환수 비율 구간 1건 조회.
|
||||||
|
months_from <= monthsElapsed AND (months_to IS NULL OR months_to >= monthsElapsed)
|
||||||
|
product_category NULL은 전체 상품 적용 행이므로 NULL 안전 비교 처리.
|
||||||
|
effective_from DESC로 최신 개정본 우선 반환.
|
||||||
|
-->
|
||||||
|
<select id="selectByMonths" resultMap="VOMap">
|
||||||
|
SELECT grade_id, product_category, months_from, months_to,
|
||||||
|
chargeback_percent, effective_from, effective_to, is_active,
|
||||||
|
created_at, created_by, updated_at, updated_by
|
||||||
|
FROM chargeback_grade g
|
||||||
|
WHERE g.months_from <= #{monthsElapsed}
|
||||||
|
AND (g.months_to IS NULL OR g.months_to >= #{monthsElapsed})
|
||||||
|
AND (g.product_category = #{productCategory}
|
||||||
|
OR (#{productCategory} IS NULL AND g.product_category IS NULL))
|
||||||
|
<include refid="activeCondition"/>
|
||||||
|
ORDER BY g.effective_from DESC
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 특정 시점 활성 전체 구간 (months_from ASC 정렬) -->
|
||||||
|
<select id="selectAll" resultMap="VOMap">
|
||||||
|
SELECT grade_id, product_category, months_from, months_to,
|
||||||
|
chargeback_percent, effective_from, effective_to, is_active,
|
||||||
|
created_at, created_by, updated_at, updated_by
|
||||||
|
FROM chargeback_grade g
|
||||||
|
WHERE 1=1
|
||||||
|
<include refid="activeCondition"/>
|
||||||
|
ORDER BY g.product_category NULLS FIRST, g.months_from
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 카테고리별 활성 구간 (months_from ASC) -->
|
||||||
|
<select id="selectByCategory" resultMap="VOMap">
|
||||||
|
SELECT grade_id, product_category, months_from, months_to,
|
||||||
|
chargeback_percent, effective_from, effective_to, is_active,
|
||||||
|
created_at, created_by, updated_at, updated_by
|
||||||
|
FROM chargeback_grade g
|
||||||
|
WHERE (g.product_category = #{productCategory}
|
||||||
|
OR (#{productCategory} IS NULL AND g.product_category IS NULL))
|
||||||
|
<include refid="activeCondition"/>
|
||||||
|
ORDER BY g.months_from
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- ==================== INSERT ==================== -->
|
||||||
|
|
||||||
|
<insert id="insert" parameterType="com.ga.core.vo.chargeback.ChargebackGradeVO"
|
||||||
|
useGeneratedKeys="true" keyProperty="gradeId">
|
||||||
|
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}
|
||||||
|
)
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<!-- ==================== UPDATE ==================== -->
|
||||||
|
|
||||||
|
<update id="update" parameterType="com.ga.core.vo.chargeback.ChargebackGradeVO">
|
||||||
|
UPDATE chargeback_grade
|
||||||
|
<set>
|
||||||
|
<if test="monthsFrom != null">months_from = #{monthsFrom},</if>
|
||||||
|
<if test="monthsTo != null">months_to = #{monthsTo},</if>
|
||||||
|
<if test="chargebackPercent != null">chargeback_percent = #{chargebackPercent},</if>
|
||||||
|
<if test="effectiveFrom != null">effective_from = #{effectiveFrom},</if>
|
||||||
|
<if test="effectiveTo != null">effective_to = #{effectiveTo},</if>
|
||||||
|
<if test="isActive != null">is_active = #{isActive},</if>
|
||||||
|
updated_at = NOW(),
|
||||||
|
updated_by = #{updatedBy}
|
||||||
|
</set>
|
||||||
|
WHERE grade_id = #{gradeId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- 활성 여부만 변경 -->
|
||||||
|
<update id="updateStatus">
|
||||||
|
UPDATE chargeback_grade
|
||||||
|
SET is_active = #{isActive}, updated_at = NOW()
|
||||||
|
WHERE grade_id = #{gradeId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Reference in New Issue
Block a user