[공통] util → framework 유틸 (ACM-CM-002)

This commit is contained in:
forge-bot 2026-07-18 11:03:12 +00:00
parent 3fdaa56fab
commit 45406e9974

View file

@ -0,0 +1,438 @@
package com.klaro.acquirecore.framework.util;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Objects;
/**
* Static utility class for amount/money operations migrated from legacy/util_amount.c
* Uses java.math.BigDecimal for precise monetary calculations.
*/
public final class AmountUtil {
public static final int DEFAULT_SCALE = 2;
public static final RoundingMode DEFAULT_ROUNDING_MODE = RoundingMode.HALF_UP;
public static final String KOREAN_WON_SYMBOL = "";
public static final String USDollar_SYMBOL = "$";
public static final String EURO_SYMBOL = "";
private static final DecimalFormat KOREAN_WON_FORMAT = new DecimalFormat("#,###");
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#,###.##");
private static final DecimalFormat CURRENCY_FORMAT = new DecimalFormat("#,###.00");
private AmountUtil() {
throw new UnsupportedOperationException("Utility class cannot be instantiated");
}
/**
* Creates a BigDecimal from a string value.
*
* @param value the string value to convert
* @return the BigDecimal value
* @throws NumberFormatException if the string is not a valid number
*/
public static BigDecimal of(String value) {
Objects.requireNonNull(value, "value must not be null");
return new BigDecimal(value.trim());
}
/**
* Creates a BigDecimal from a long value.
*
* @param value the long value to convert
* @return the BigDecimal value
*/
public static BigDecimal of(long value) {
return BigDecimal.valueOf(value);
}
/**
* Creates a BigDecimal from a double value.
*
* @param value the double value to convert
* @return the BigDecimal value
*/
public static BigDecimal of(double value) {
return BigDecimal.valueOf(value);
}
/**
* Adds two BigDecimal values.
*
* @param a the first operand
* @param b the second operand
* @return the sum
*/
public static BigDecimal add(BigDecimal a, BigDecimal b) {
Objects.requireNonNull(a, "a must not be null");
Objects.requireNonNull(b, "b must not be null");
return a.add(b);
}
/**
* Subtracts the second BigDecimal from the first.
*
* @param a the minuend
* @param b the subtrahend
* @return the difference
*/
public static BigDecimal subtract(BigDecimal a, BigDecimal b) {
Objects.requireNonNull(a, "a must not be null");
Objects.requireNonNull(b, "b must not be null");
return a.subtract(b);
}
/**
* Multiplies two BigDecimal values.
*
* @param a the first operand
* @param b the second operand
* @return the product
*/
public static BigDecimal multiply(BigDecimal a, BigDecimal b) {
Objects.requireNonNull(a, "a must not be null");
Objects.requireNonNull(b, "b must not be null");
return a.multiply(b);
}
/**
* Divides the first BigDecimal by the second.
*
* @param dividend the dividend
* @param divisor the divisor
* @return the quotient
* @throws ArithmeticException if divisor is zero
*/
public static BigDecimal divide(BigDecimal dividend, BigDecimal divisor) {
Objects.requireNonNull(dividend, "dividend must not be null");
Objects.requireNonNull(divisor, "divisor must not be null");
if (BigDecimal.ZERO.compareTo(divisor) == 0) {
throw new ArithmeticException("Division by zero");
}
return dividend.divide(divisor, DEFAULT_SCALE, DEFAULT_ROUNDING_MODE);
}
/**
* Divides the first BigDecimal by the second with specified scale and rounding mode.
*
* @param dividend the dividend
* @param divisor the divisor
* @param scale the scale
* @param roundingMode the rounding mode
* @return the quotient
* @throws ArithmeticException if divisor is zero
*/
public static BigDecimal divide(BigDecimal dividend, BigDecimal divisor, int scale, RoundingMode roundingMode) {
Objects.requireNonNull(dividend, "dividend must not be null");
Objects.requireNonNull(divisor, "divisor must not be null");
Objects.requireNonNull(roundingMode, "roundingMode must not be null");
if (BigDecimal.ZERO.compareTo(divisor) == 0) {
throw new ArithmeticException("Division by zero");
}
return dividend.divide(divisor, scale, roundingMode);
}
/**
* Rounds a BigDecimal to the default scale (2) using default rounding mode (HALF_UP).
*
* @param value the value to round
* @return the rounded value
*/
public static BigDecimal round(BigDecimal value) {
Objects.requireNonNull(value, "value must not be null");
return value.setScale(DEFAULT_SCALE, DEFAULT_ROUNDING_MODE);
}
/**
* Rounds a BigDecimal to the specified scale using the specified rounding mode.
*
* @param value the value to round
* @param scale the scale
* @param roundingMode the rounding mode
* @return the rounded value
*/
public static BigDecimal round(BigDecimal value, int scale, RoundingMode roundingMode) {
Objects.requireNonNull(value, "value must not be null");
Objects.requireNonNull(roundingMode, "roundingMode must not be null");
return value.setScale(scale, roundingMode);
}
/**
* Calculates percentage of a value.
*
* @param value the base value
* @param percentage the percentage (e.g., 10 for 10%)
* @return the percentage amount
*/
public static BigDecimal percentage(BigDecimal value, BigDecimal percentage) {
Objects.requireNonNull(value, "value must not be null");
Objects.requireNonNull(percentage, "percentage must not be null");
return value.multiply(percentage).divide(BigDecimal.valueOf(100), DEFAULT_SCALE, DEFAULT_ROUNDING_MODE);
}
/**
* Calculates percentage of a value and adds it.
*
* @param value the base value
* @param percentage the percentage to add
* @return the value plus percentage amount
*/
public static BigDecimal addPercentage(BigDecimal value, BigDecimal percentage) {
Objects.requireNonNull(value, "value must not be null");
Objects.requireNonNull(percentage, "percentage must not be null");
return value.add(percentage(value, percentage));
}
/**
* Calculates percentage of a value and subtracts it.
*
* @param value the base value
* @param percentage the percentage to subtract
* @return the value minus percentage amount
*/
public static BigDecimal subtractPercentage(BigDecimal value, BigDecimal percentage) {
Objects.requireNonNull(value, "value must not be null");
Objects.requireNonNull(percentage, "percentage must not be null");
return value.subtract(percentage(value, percentage));
}
/**
* Formats a BigDecimal as a Korean Won amount (e.g., "₩1,000").
*
* @param amount the amount to format
* @return the formatted string
*/
public static String formatKoreanWon(BigDecimal amount) {
Objects.requireNonNull(amount, "amount must not be null");
return KOREAN_WON_SYMBOL + KOREAN_WON_FORMAT.format(amount.setScale(0, RoundingMode.DOWN));
}
/**
* Formats a BigDecimal as a currency amount with 2 decimal places.
*
* @param amount the amount to format
* @return the formatted string
*/
public static String formatCurrency(BigDecimal amount) {
Objects.requireNonNull(amount, "amount must not be null");
return CURRENCY_FORMAT.format(amount);
}
/**
* Formats a BigDecimal as a decimal number.
*
* @param amount the amount to format
* @return the formatted string
*/
public static String formatDecimal(BigDecimal amount) {
Objects.requireNonNull(amount, "amount must not be null");
return DECIMAL_FORMAT.format(amount);
}
/**
* Formats a BigDecimal with a custom pattern.
*
* @param amount the amount to format
* @param pattern the DecimalFormat pattern
* @return the formatted string
*/
public static String format(BigDecimal amount, String pattern) {
Objects.requireNonNull(amount, "amount must not be null");
Objects.requireNonNull(pattern, "pattern must not be null");
DecimalFormat formatter = new DecimalFormat(pattern);
return formatter.format(amount);
}
/**
* Compares two BigDecimal values.
*
* @param a the first value
* @param b the second value
* @return -1 if a < b, 0 if a == b, 1 if a > b
*/
public static int compare(BigDecimal a, BigDecimal b) {
Objects.requireNonNull(a, "a must not be null");
Objects.requireNonNull(b, "b must not be null");
return a.compareTo(b);
}
/**
* Checks if the first value is greater than the second.
*
* @param a the first value
* @param b the second value
* @return true if a > b
*/
public static boolean isGreaterThan(BigDecimal a, BigDecimal b) {
return compare(a, b) > 0;
}
/**
* Checks if the first value is less than the second.
*
* @param a the first value
* @param b the second value
* @return true if a < b
*/
public static boolean isLessThan(BigDecimal a, BigDecimal b) {
return compare(a, b) < 0;
}
/**
* Checks if the first value is greater than or equal to the second.
*
* @param a the first value
* @param b the second value
* @return true if a >= b
*/
public static boolean isGreaterThanOrEqual(BigDecimal a, BigDecimal b) {
return compare(a, b) >= 0;
}
/**
* Checks if the first value is less than or equal to the second.
*
* @param a the first value
* @param b the second value
* @return true if a <= b
*/
public static boolean isLessThanOrEqual(BigDecimal a, BigDecimal b) {
return compare(a, b) <= 0;
}
/**
* Checks if the value is zero.
*
* @param value the value to check
* @return true if value is zero
*/
public static boolean isZero(BigDecimal value) {
Objects.requireNonNull(value, "value must not be null");
return BigDecimal.ZERO.compareTo(value) == 0;
}
/**
* Checks if the value is positive (greater than zero).
*
* @param value the value to check
* @return true if value > 0
*/
public static boolean isPositive(BigDecimal value) {
return compare(value, BigDecimal.ZERO) > 0;
}
/**
* Checks if the value is negative (less than zero).
*
* @param value the value to check
* @return true if value < 0
*/
public static boolean isNegative(BigDecimal value) {
return compare(value, BigDecimal.ZERO) < 0;
}
/**
* Returns the absolute value.
*
* @param value the value
* @return the absolute value
*/
public static BigDecimal abs(BigDecimal value) {
Objects.requireNonNull(value, "value must not be null");
return value.abs();
}
/**
* Negates the value.
*
* @param value the value
* @return the negated value
*/
public static BigDecimal negate(BigDecimal value) {
Objects.requireNonNull(value, "value must not be null");
return value.negate();
}
/**
* Returns the maximum of two values.
*
* @param a the first value
* @param b the second value
* @return the maximum value
*/
public static BigDecimal max(BigDecimal a, BigDecimal b) {
Objects.requireNonNull(a, "a must not be null");
Objects.requireNonNull(b, "b must not be null");
return a.max(b);
}
/**
* Returns the minimum of two values.
*
* @param a the first value
* @param b the second value
* @return the minimum value
*/
public static BigDecimal min(BigDecimal a, BigDecimal b) {
Objects.requireNonNull(a, "a must not be null");
Objects.requireNonNull(b, "b must not be null");
return a.min(b);
}
/**
* Parses a string that may contain currency symbols and commas.
*
* @param value the string to parse
* @return the parsed BigDecimal
*/
public static BigDecimal parseAmount(String value) {
Objects.requireNonNull(value, "value must not be null");
String cleaned = value.replace(KOREAN_WON_SYMBOL, "")
.replace(USDollar_SYMBOL, "")
.replace(EURO_SYMBOL, "")
.replace(",", "")
.replace(" ", "")
.trim();
return new BigDecimal(cleaned);
}
/**
* Validates if a string is a valid amount.
*
* @param value the string to validate
* @return true if valid, false otherwise
*/
public static boolean isValidAmount(String value) {
if (value == null || value.isEmpty()) {
return false;
}
try {
parseAmount(value);
return true;
} catch (NumberFormatException e) {
return false;
}
}
/**
* Converts cents/won to decimal amount.
*
* @param cents the amount in cents
* @return the decimal amount
*/
public static BigDecimal fromCents(long cents) {
return BigDecimal.valueOf(cents).divide(BigDecimal.valueOf(100), DEFAULT_SCALE, DEFAULT_ROUNDING_MODE);
}
/**
* Converts decimal amount to cents/won.
*
* @param amount the decimal amount
* @return the amount in cents
*/
public static long toCents(BigDecimal amount) {
Objects.requireNonNull(amount, "amount must not be null");
return amount.multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.DOWN).longValue();
}
}