All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.crazyyak.dev.domain.money.Money Maven / Gradle / Ivy

/*
 * Copyright 2012 Jacob D Parr
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.crazyyak.dev.domain.money;

import java.io.Serializable;
import java.math.*;

import static java.lang.String.format;

public class Money extends Number implements Serializable, Comparable {

  private static final String errorTemplate = format("The value %%s could not be converted to a %s: %%s", BigDecimal.class.getSimpleName());
  private static final java.text.DecimalFormat DollarFormat = new java.text.DecimalFormat("0.00");
  
  private long internalValue;

  /** @deprecated Use Money.ZERO() instead. */
  @Deprecated
  public Money() {
    internalValue = 0;
  }
  
  /**
   * Creates a new money value from a double value.
   * @param value the value to initialize from
   * @deprecated Use {@link #Money(String)} or {@link #Money(java.math.BigDecimal)} instead in that double value are inherently unsafe.
   */
  @Deprecated
  public Money(double value) {
    this(convert(value));
  }

  /**
   * Creates a new money value from a double value.
   * @param value the value to initialize from
   * @deprecated Use {@link #Money(String)} or {@link #Money(java.math.BigDecimal)} instead in that double value are inherently unsafe.
   */
  @Deprecated
  public Money(double value, RoundingMode roundingMode) {
    this(convert(value), roundingMode);
  }

  public Money(String value) {
    this(convert(value));
  }

  public Money(String value, RoundingMode roundingMode) {
    this(convert(value), roundingMode);
  }

  public Money(final BigDecimal value) {
    this(value, RoundingMode.UNNECESSARY);
  }

  public Money(final BigDecimal value, RoundingMode roundingMode) {
    try {
      BigDecimal newValue = value.setScale(2, roundingMode);
      newValue = newValue.multiply(new BigDecimal(100));
      newValue = newValue.setScale(2);
      this.internalValue = newValue.longValueExact();

    } catch (Throwable ex) {
      throw new MoneyException(format(errorTemplate, value, ex.getMessage()), ex);
    }
  }

  public Money(Money copy) {
    this.internalValue = copy.internalValue;
  }

  private static BigDecimal convert(String value) {
    try {
      value = value.replace(",", "").replace("$", "");
      return new BigDecimal(value);

    } catch (Throwable ex) {
      throw new MoneyException(format(errorTemplate, value), ex);
    }
  }

  private static BigDecimal convert(double value) {
    try {
      return BigDecimal.valueOf(value);

    } catch (Throwable ex) {
      throw new MoneyException(format(errorTemplate, value), ex);
    }
  }

  private Money(long internalValue) {
    this.internalValue = internalValue;
  }

  public long getInternalValue() {
    return internalValue;
  }

  public String getShortForm() {

    String retVal = toString();
    if (retVal.endsWith(".00")) {
      retVal = retVal.substring(0, retVal.length()-3);
    }

    return retVal;
  }

  public String toString() {
    return DollarFormat.format(doubleValue());
  }

  public Money getAbsolute() {
    return isPositive() ? this : multiply(-1);
  }

  public Money add(Money amount) {
    return plus(amount);
  }

  public Money plus(Money amount) {
    return new Money(internalValue + amount.getInternalValue());
  }

  public Money subtract(Money amount) {
    return minus(amount);
  }
  
  public Money minus(Money amount) {
    return new Money(internalValue - amount.getInternalValue());
  }

  public Money multiply(long multiplier) {
    long longValue = (internalValue * multiplier);
    return new Money(longValue);
  }

  public Money multiply(double multiplier) {
    long longValue = (long)(internalValue * multiplier);
    return new Money(longValue);
  }

  public Money multiply(BigDecimal multiplier) {
    BigDecimal value = new BigDecimal(internalValue).divide(new BigDecimal(100));
    value = value.multiply(multiplier);
    return new Money(value, RoundingMode.HALF_EVEN);
  }

  public Money divide (double divisor) {
    long longValue = (long)(internalValue / divisor);
    return new Money(longValue);
  }

  public boolean equals(Object object) {
    if (object instanceof Money) {
      Money amount = (Money)object;
      return internalValue == amount.getInternalValue();
    }
    return false;
  }

  public boolean greaterThan(Money that) {
    return this.internalValue > that.getInternalValue();
  }

  public boolean lessThan(Money that) {
    return this.internalValue < that.getInternalValue();
  }

  public boolean isNegative() {
    return internalValue < 0;
  }
  public boolean isNonNegative() {
    return isNegative() == false;
  }

  public boolean isPositive() {
    return internalValue > 0;
  }
  public boolean isNonPositive() {
    return isPositive() == false;
  }

  public boolean isZero() {
    return internalValue == 0;
  }

  public boolean isNonZero() {
    return internalValue != 0;
  }

  public BigDecimal getWholeNumber() {
    BigDecimal value = new BigDecimal(internalValue/100);
    value = value.setScale(0, RoundingMode.HALF_EVEN);
    return value;
  }

  public BigDecimal getBigDecimalValue() {
    BigDecimal value = new BigDecimal(internalValue/100d);
    value = value.setScale(2, RoundingMode.HALF_EVEN);
    return value;
  }
  
  @Override
  public double doubleValue() {
    return getBigDecimalValue().doubleValue();
  }

  @Override
  public int intValue() {
    return getBigDecimalValue().intValue();
  }

  @Override
  public long longValue() {
    return getBigDecimalValue().longValue();
  }

  @Override
  public float floatValue() {
    return getBigDecimalValue().floatValue();
  }

  @Override
  public int compareTo(Money amount) {
    return getBigDecimalValue().compareTo(amount.getBigDecimalValue());
  }

  private static BigDecimal toBigDecimal(String value) {
    try {
      return new BigDecimal(value);
    } catch (NumberFormatException ex) {
      String msg = format("Cannot convert \"%s\" to an instance of %s.", value, Money.class.getSimpleName());
      throw new NumberFormatException(msg);
    }
  }

  public static Money ZERO() {
    return new Money("0.00");
  }
  public static Money MIN_VALUE() {
    return new Money(String.valueOf(Integer.MIN_VALUE));
  }
  public static Money MAX_VALUE() {
    return new Money(String.valueOf(Integer.MAX_VALUE));
  }

  public Money negate() {
    return this.multiply(new BigDecimal(-1));
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy