From 68a4df5aaf077c71ac0a658ef298910627be59da Mon Sep 17 00:00:00 2001 From: forge-bot Date: Mon, 13 Jul 2026 10:36:00 +0000 Subject: [PATCH] =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=EC=A0=95=EC=82=B0=20?= =?UTF-8?q?=EC=97=85=EB=AC=B4=20=EA=B7=9C=EC=B9=99=EA=B3=BC=20=EC=A0=84?= =?UTF-8?q?=ED=99=98=20=EB=B6=88=EB=B3=80=EC=8B=9D=20=EC=B6=94=EC=B6=9C=20?= =?UTF-8?q?(codex-bais-final3-20260713-192718-BAIS-SPRING-ANA-CARD-001)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../card/settlement/SettlementInvariant.java | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 card-settlement-migration/src/main/java/com/bais/card/settlement/SettlementInvariant.java diff --git a/card-settlement-migration/src/main/java/com/bais/card/settlement/SettlementInvariant.java b/card-settlement-migration/src/main/java/com/bais/card/settlement/SettlementInvariant.java new file mode 100644 index 0000000..1f835b6 --- /dev/null +++ b/card-settlement-migration/src/main/java/com/bais/card/settlement/SettlementInvariant.java @@ -0,0 +1,86 @@ +package com.bais.card.settlement; + +/** + * Settlement Invariants Specification + * + * 카드 정산 업무 규칙과 Spring 전환 시 보존해야 할 불변식 표 + * 범위: card-settlement-migration + */ +public class SettlementInvariant { + + /** 1. 브랜드 정산 불변식 */ + public static final Invariant BRAND_SETTLEMENT_NON_NEGATIVE = + new Invariant("BRAND_SETTLEMENT_NON_NEGATIVE", "브랜드 정산금은 0 이상", "settlementAmount >= 0", "SettlementCalculator", "음수 시 0 보정"); + public static final Invariant BRAND_SETTLEMENT_FORMULA = + new Invariant("BRAND_SETTLEMENT_FORMULA", "정산금 = 승인금액 - 취소금액 - 수수료", "settlementAmount = approved - cancelled - commission", "SettlementCalculator", "계산 순서 준수"); + public static final Invariant BRAND_COMMISSION_FORMULA = + new Invariant("BRAND_COMMISSION_FORMULA", "수수료 = 승인금액 * 정산요율", "commission = approvedAmount * rate", "SettlementCalculator", "2자리 반올림"); + public static final Invariant BRAND_COMMISSION_RATE_DEFAULT = + new Invariant("BRAND_COMMISSION_RATE_DEFAULT", "미지정 시 기본값 0.02(2%)", "rate = 0.02 when null", "SettlementCalculator", "DEFAULT_COMMISSION_RATE"); + + /** 2. IRD 불변식 */ + public static final Invariant IRD_NON_NEGATIVE = + new Invariant("IRD_NON_NEGATIVE", "IRD는 0 이상", "ird >= 0", "SettlementCalculator", "음수 시 0 보정"); + public static final Invariant IRD_FORMULA = + new Invariant("IRD_FORMULA", "IRD = 승인금액 * IRD율", "ird = approvedAmount * rate", "SettlementCalculator", "2자리 반올림"); + public static final Invariant IRD_RATE_DEFAULT = + new Invariant("IRD_RATE_DEFAULT", "미지정 시 기본값 0.015(1.5%)", "rate = 0.015 when null", "SettlementCalculator", "DEFAULT_IRD_RATE"); + + /** 3. 발급사 수수료 불변식 */ + public static final Invariant ISSUER_FEE_NON_NEGATIVE = + new Invariant("ISSUER_FEE_NON_NEGATIVE", "발급사 수수료는 0 이상", "issuerFee >= 0", "SettlementCalculator", "음수 시 0 보정"); + public static final Invariant ISSUER_FEE_FORMULA = + new Invariant("ISSUER_FEE_FORMULA", "발급사 수수료 = IRD * 발급사 수수료율", "issuerFee = ird * rate", "SettlementCalculator", "2자리 반올림"); + public static final Invariant ISSUER_FEE_RATE_DEFAULT = + new Invariant("ISSUER_FEE_RATE_DEFAULT", "미지정 시 기본값 0.005(0.5%)", "rate = 0.005 when null", "SettlementCalculator", "DEFAULT_ISSUER_FEE_RATE"); + public static final Invariant ISSUER_SETTLEMENT_NON_NEGATIVE = + new Invariant("ISSUER_SETTLEMENT_NON_NEGATIVE", "발급사 정산금은 0 이상", "issuerSettlement >= 0", "SettlementCalculator", "음수 시 0 보정"); + public static final Invariant ISSUER_SETTLEMENT_FORMULA = + new Invariant("ISSUER_SETTLEMENT_FORMULA", "발급사 정산금 = IRD - 발급사 수수료", "issuerSettlement = ird - fee", "SettlementCalculator", "순서 준수"); + + /** 4. 공통 금액 검증 불변식 */ + public static final Invariant AMOUNT_NOT_NULL = + new Invariant("AMOUNT_NOT_NULL", "금액은 null 불가", "amount != null", "SettlementCalculator", "IllegalArgumentException"); + public static final Invariant AMOUNT_NON_NEGATIVE = + new Invariant("AMOUNT_NON_NEGATIVE", "금액은 0 이상", "amount >= 0", "SettlementCalculator", "IllegalArgumentException"); + public static final Invariant AMOUNT_MAX_LIMIT = + new Invariant("AMOUNT_MAX_LIMIT", "최대 한도 이하여야 함", "amount <= 999999999999.99", "SettlementCalculator", "IllegalArgumentException"); + + /** 5. 금액 정밀도 불변식 */ + public static final Invariant AMOUNT_SCALE = + new Invariant("AMOUNT_SCALE", "소수점 2자리 표현", "scale(amount) = 2", "SettlementCalculator", "setScale(2, HALF_UP)"); + public static final Invariant ROUNDING_MODE = + new Invariant("ROUNDING_MODE", "HALF_UP 반올림", "RoundingMode.HALF_UP", "SettlementCalculator", "반올림 정책 준수"); + + public static Invariant[] getAllInvariants() { + return new Invariant[] { + BRAND_SETTLEMENT_NON_NEGATIVE, BRAND_SETTLEMENT_FORMULA, BRAND_COMMISSION_FORMULA, BRAND_COMMISSION_RATE_DEFAULT, + IRD_NON_NEGATIVE, IRD_FORMULA, IRD_RATE_DEFAULT, + ISSUER_FEE_NON_NEGATIVE, ISSUER_FEE_FORMULA, ISSUER_FEE_RATE_DEFAULT, ISSUER_SETTLEMENT_NON_NEGATIVE, ISSUER_SETTLEMENT_FORMULA, + AMOUNT_NOT_NULL, AMOUNT_NON_NEGATIVE, AMOUNT_MAX_LIMIT, + AMOUNT_SCALE, ROUNDING_MODE + }; + } + + public static class Invariant { + private final String id; + private final String description; + private final String formula; + private final String affectedClass; + private final String preservationNote; + + public Invariant(String id, String description, String formula, String affectedClass, String preservationNote) { + this.id = id; + this.description = description; + this.formula = formula; + this.affectedClass = affectedClass; + this.preservationNote = preservationNote; + } + + public String getId() { return id; } + public String getDescription() { return description; } + public String getFormula() { return formula; } + public String getAffectedClass() { return affectedClass; } + public String getPreservationNote() { return preservationNote; } + } +}