001 /* 002 * Copyright 2011 The Kuali Foundation. 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.kfs.module.cam.util; 017 018 import java.util.Currency; 019 020 import org.apache.commons.lang.ArrayUtils; 021 import org.kuali.rice.kns.util.KualiDecimal; 022 023 /** 024 * Utility class that divides currency into equal targets with remainder to cents in some buckets.<br> 025 */ 026 public class KualiDecimalUtils { 027 028 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiDecimalUtils.class); 029 private static final int[] cents = new int[] { 1, 10, 100, 1000 }; 030 031 private long totalAmount; 032 private Currency currencyCode; 033 034 /** 035 * Default constructor. 036 */ 037 public KualiDecimalUtils() { 038 } 039 040 /** 041 * Constructs a KualiDecimalService. 042 * 043 * @param amount 044 * @param currency 045 */ 046 public KualiDecimalUtils(KualiDecimal totalAmount, Currency currencyCode) { 047 this.currencyCode = currencyCode; 048 this.totalAmount = Math.round(totalAmount.multiply(new KualiDecimal(centFactor())).floatValue()); 049 } 050 051 /** 052 * Gets the default number of fraction digits used with the given currency. 053 * 054 * @return int 055 */ 056 private int centFactor() { 057 return cents[currencyCode.getDefaultFractionDigits()]; 058 } 059 060 /** 061 * Sets a new amount. 062 * 063 * @param amount 064 * @return KualiDecimalService 065 */ 066 private KualiDecimalUtils setNewAmount(long amount) { 067 KualiDecimalUtils kds = new KualiDecimalUtils(); 068 kds.totalAmount = amount; 069 return kds; 070 } 071 072 /** 073 * Allocate a sum of money amongst many targets by quantity. 074 * 075 * @param divisor 076 * @return KualiDecimal[] 077 */ 078 public KualiDecimal[] allocateByQuantity(int divisor) { 079 // calculate lowest and highest amount 080 KualiDecimalUtils lowAmount = setNewAmount(totalAmount / divisor); 081 KualiDecimalUtils highAmount = setNewAmount(lowAmount.totalAmount + 1); 082 083 int remainder = (int) totalAmount % divisor; 084 085 // allocate amounts into array 086 KualiDecimal[] amountsArray = new KualiDecimal[divisor]; 087 088 // set the lowest amount into array 089 KualiDecimal low = new KualiDecimal(lowAmount.totalAmount); 090 for (int i = remainder; i < divisor; i++) { 091 amountsArray[i] = low.divide(new KualiDecimal(centFactor())); 092 } 093 094 // set the highest amount into array 095 KualiDecimal high = new KualiDecimal(highAmount.totalAmount); 096 for (int i = 0; i < remainder; i++) { 097 amountsArray[i] = high.divide(new KualiDecimal(centFactor())); 098 } 099 100 ArrayUtils.reverse(amountsArray); 101 102 return amountsArray; 103 } 104 105 /** 106 * Allocate a sum of money amongst many targets by ratio. 107 * 108 * @param divisor 109 * @return KualiDecimal[] 110 */ 111 public static KualiDecimal[] allocateByRatio(KualiDecimal amount, double[] ratios) { 112 113 if (ratios == null || ratios.length == 0 || amount == null) { 114 return amount == null ? null : new KualiDecimal[] { amount }; 115 } 116 double value = amount.doubleValue(); 117 118 // if just one ratio, apply and return 119 if (ratios.length == 1) { 120 return new KualiDecimal[] { new KualiDecimal(value * ratios[0]) }; 121 } 122 KualiDecimal allocated = KualiDecimal.ZERO; 123 // allocate amounts into array 124 KualiDecimal[] amountsArray = new KualiDecimal[ratios.length]; 125 for (int i = 0; i < ratios.length - 1; i++) { 126 KualiDecimal currAmount = new KualiDecimal(value * ratios[i]); 127 amountsArray[i] = currAmount; 128 allocated = allocated.add(currAmount); 129 } 130 // adjust the last one with remaining value 131 amountsArray[ratios.length - 1] = new KualiDecimal(value).subtract(allocated); 132 return amountsArray; 133 } 134 135 /** 136 * Makes sure no null pointer exception occurs on fields that can accurately be null when multiplying. If either field are null 137 * the value is returned. 138 * 139 * @param value 140 * @param multiplier 141 * @return 142 */ 143 public KualiDecimal safeMultiply(KualiDecimal value, double multiplier) { 144 if (value == null) { 145 return value; 146 } 147 else { 148 return new KualiDecimal(value.doubleValue() * multiplier); 149 } 150 } 151 152 /** 153 * Makes sure no null pointer exception occurs on fields that can accurately be null when subtracting. If either field are null 154 * the value is returned. 155 * 156 * @param value 157 * @param subtrahend 158 * @return 159 */ 160 public KualiDecimal safeSubtract(KualiDecimal value, KualiDecimal subtrahend) { 161 if (subtrahend == null || value == null) { 162 return value; 163 } 164 165 return value.subtract(subtrahend); 166 } 167 }