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.ec.util; 017 018 import java.util.ArrayList; 019 import java.util.HashMap; 020 import java.util.List; 021 import java.util.Map; 022 023 import org.kuali.kfs.module.ec.EffortConstants; 024 import org.kuali.kfs.module.ec.EffortPropertyConstants; 025 import org.kuali.kfs.module.ec.businessobject.EffortCertificationDetail; 026 import org.kuali.kfs.sys.DynamicCollectionComparator; 027 import org.kuali.kfs.sys.ObjectUtil; 028 import org.kuali.kfs.sys.DynamicCollectionComparator.SortOrder; 029 import org.kuali.rice.kns.util.KualiDecimal; 030 031 /** 032 * grouping a set of detail lines. The class is implemented to manage: summary line and delegating line. 033 */ 034 public class DetailLineGroup { 035 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DetailLineGroup.class); 036 037 EffortCertificationDetail summaryDetailLine; 038 EffortCertificationDetail delegateDetailLine; 039 List<EffortCertificationDetail> detailLines; 040 041 /** 042 * Constructs a DetailLineGroup.java. 043 */ 044 public DetailLineGroup() { 045 this(null); 046 } 047 048 /** 049 * Constructs a DetailLineGroup.java. 050 * 051 * @param detailLine the given detail line 052 */ 053 public DetailLineGroup(EffortCertificationDetail newDetailLine) { 054 detailLines = new ArrayList<EffortCertificationDetail>(); 055 summaryDetailLine = new EffortCertificationDetail(); 056 057 if (newDetailLine != null) { 058 String groupId = getKeysAsString(newDetailLine); 059 ObjectUtil.buildObject(summaryDetailLine, newDetailLine); 060 summaryDetailLine.setGroupId(groupId); 061 062 this.addNewLineIntoGroup(newDetailLine, groupId); 063 } 064 065 summaryDetailLine.setFinancialObjectCode(null); 066 summaryDetailLine.setPositionNumber(null); 067 } 068 069 /** 070 * update the effort percent of the delegate detail line if the effort on the summary line has been changed 071 */ 072 public void updateDelegateDetailLineEffort() { 073 Integer difference = this.getEffortPercentChanged(); 074 if (difference != 0) { 075 Integer effortPercent = delegateDetailLine.getEffortCertificationUpdatedOverallPercent() + difference; 076 delegateDetailLine.setEffortCertificationUpdatedOverallPercent(effortPercent); 077 } 078 } 079 080 /** 081 * update the effort percents of the detail lines if the effort on the summary line has been changed 082 */ 083 public void updateDetailLineEffortPercent() { 084 int totalDifference = this.getEffortPercentChanged(); 085 086 List<EffortCertificationDetail> detailLines = this.getDetailLines(); 087 DynamicCollectionComparator.sort(detailLines, SortOrder.DESC, EffortPropertyConstants.PERSISED_PAYROLL_AMOUNT); 088 089 // restore the intial effort percents before update the detail lines 090 for (EffortCertificationDetail detailLine : detailLines) { 091 detailLine.setEffortCertificationUpdatedOverallPercent(detailLine.getPersistedEffortPercent()); 092 } 093 094 for (EffortCertificationDetail detailLine : detailLines) { 095 if (totalDifference == 0) { 096 break; 097 } 098 099 int currentPercent = detailLine.getPersistedEffortPercent(); 100 int currentDifference = currentPercent + totalDifference; 101 boolean needUpdateMultipleLines = (currentDifference < 0); 102 103 int effortPercent = needUpdateMultipleLines ? 0 : currentDifference; 104 detailLine.setEffortCertificationUpdatedOverallPercent(effortPercent); 105 106 totalDifference = needUpdateMultipleLines ? currentDifference : 0; 107 } 108 } 109 110 /** 111 * update the payroll amounts of the detail lines if the payroll amount on the summary line has been changed 112 */ 113 public void updateDetailLinePayrollAmount() { 114 KualiDecimal totalDifference = this.getPayrollAmountChanged(); 115 if (totalDifference.isZero()) { 116 return; 117 } 118 119 List<EffortCertificationDetail> detailLines = this.getDetailLines(); 120 DynamicCollectionComparator.sort(detailLines, SortOrder.DESC, EffortPropertyConstants.PERSISED_PAYROLL_AMOUNT); 121 122 // restore the intial payroll amounts before update the detail lines 123 for (EffortCertificationDetail detailLine : detailLines) { 124 detailLine.setEffortCertificationPayrollAmount(detailLine.getPersistedPayrollAmount()); 125 } 126 127 for (EffortCertificationDetail detailLine : detailLines) { 128 if (totalDifference.isZero()) { 129 break; 130 } 131 132 KualiDecimal currentAmount = detailLine.getPersistedPayrollAmount(); 133 KualiDecimal currentDifference = currentAmount.add(totalDifference); 134 boolean needUpdateMultipleLines = currentDifference.isNegative(); 135 136 KualiDecimal payrollAmount = needUpdateMultipleLines ? KualiDecimal.ZERO : currentDifference; 137 detailLine.setEffortCertificationPayrollAmount(payrollAmount); 138 139 totalDifference = needUpdateMultipleLines ? currentDifference : KualiDecimal.ZERO; 140 } 141 } 142 143 /** 144 * group the given detail lines by the key fields 145 * 146 * @param detailLines the given detail lines 147 * @param keyFields the given key fields 148 * @return the groups of detail lines 149 */ 150 public static Map<String, DetailLineGroup> groupDetailLines(List<EffortCertificationDetail> detailLines) { 151 Map<String, DetailLineGroup> detailLineGroupMap = new HashMap<String, DetailLineGroup>(); 152 153 for (EffortCertificationDetail line : detailLines) { 154 String groupId = getKeysAsString(line); 155 156 if (detailLineGroupMap.containsKey(groupId)) { 157 DetailLineGroup group = detailLineGroupMap.get(groupId); 158 group.addNewLineIntoGroup(line, groupId); 159 } 160 else { 161 DetailLineGroup group = new DetailLineGroup(line); 162 detailLineGroupMap.put(groupId, group); 163 } 164 } 165 166 return detailLineGroupMap; 167 } 168 169 /** 170 * concat the keys of the given detail line as a single string 171 * 172 * @param line the given detail line 173 * @return a single string built from the keys of the given detail line 174 */ 175 public static String getKeysAsString(EffortCertificationDetail line) { 176 return ObjectUtil.concatPropertyAsString(line, EffortConstants.DETAIL_LINES_GROUPING_FILEDS); 177 } 178 179 /** 180 * get the difference between the updated effort amount and the current effort amount 181 * 182 * @return the difference between the updated effort amount and the current effort amount 183 */ 184 private Integer getEffortPercentChanged() { 185 Integer currentEffortPercent = EffortCertificationDetail.getTotalPersistedEffortPercent(detailLines); 186 Integer updatedEffortPercent = summaryDetailLine.getEffortCertificationUpdatedOverallPercent(); 187 188 return updatedEffortPercent - currentEffortPercent; 189 } 190 191 /** 192 * get the difference between the updated payroll amount and the current payroll amount 193 * 194 * @return the difference between the updated payroll amount and the current payroll amount 195 */ 196 private KualiDecimal getPayrollAmountChanged() { 197 KualiDecimal currentAmount = EffortCertificationDetail.getTotalPersistedPayrollAmount(detailLines); 198 KualiDecimal updatedAmount = summaryDetailLine.getEffortCertificationPayrollAmount(); 199 200 return updatedAmount.subtract(currentAmount); 201 } 202 203 /** 204 * update the group when a new detail line is added 205 * 206 * @param line the new detail line 207 */ 208 private void addNewLineIntoGroup(EffortCertificationDetail newDetailLine, String groupId) { 209 if (detailLines.contains(newDetailLine)) { 210 return; 211 } 212 213 newDetailLine.setGroupId(groupId); 214 215 detailLines.add(newDetailLine); 216 delegateDetailLine = this.getDetailLineWithMaxPayrollAmount(detailLines); 217 218 this.updateSummaryDetailLineAmount(); 219 } 220 221 /** 222 * update the payroll amounts and effort percents based on current detail lines 223 */ 224 private void updateSummaryDetailLineAmount() { 225 Integer originalEffortPercent = EffortCertificationDetail.getTotalOriginalEffortPercent(detailLines); 226 summaryDetailLine.setEffortCertificationCalculatedOverallPercent(originalEffortPercent); 227 228 Integer effortPercent = EffortCertificationDetail.getTotalEffortPercent(detailLines); 229 summaryDetailLine.setEffortCertificationUpdatedOverallPercent(effortPercent); 230 231 Integer persistedEffortPercent = EffortCertificationDetail.getTotalPersistedEffortPercent(detailLines); 232 summaryDetailLine.setPersistedEffortPercent(persistedEffortPercent); 233 234 KualiDecimal originalPayrollAmount = EffortCertificationDetail.getTotalOriginalPayrollAmount(detailLines); 235 summaryDetailLine.setEffortCertificationOriginalPayrollAmount(originalPayrollAmount); 236 237 KualiDecimal payrollAmount = EffortCertificationDetail.getTotalPayrollAmount(detailLines); 238 summaryDetailLine.setEffortCertificationPayrollAmount(payrollAmount); 239 240 KualiDecimal persistedPayrollAmount = EffortCertificationDetail.getTotalPersistedPayrollAmount(detailLines); 241 summaryDetailLine.setPersistedPayrollAmount(persistedPayrollAmount); 242 } 243 244 /** 245 * find the detail lines that have max payroll amount 246 * 247 * @return the detail lines that have max payroll amount 248 */ 249 private EffortCertificationDetail getDetailLineWithMaxPayrollAmount(List<EffortCertificationDetail> detailLines) { 250 KualiDecimal maxAmount = null; 251 EffortCertificationDetail detailLineWithMaxPayrollAmount = null; 252 253 for (EffortCertificationDetail line : detailLines) { 254 KualiDecimal currentAmount = line.getEffortCertificationOriginalPayrollAmount(); 255 256 if (detailLineWithMaxPayrollAmount == null) { 257 maxAmount = currentAmount; 258 detailLineWithMaxPayrollAmount = line; 259 continue; 260 } 261 262 if (maxAmount.isLessThan(currentAmount)) { 263 maxAmount = currentAmount; 264 detailLineWithMaxPayrollAmount = line; 265 } 266 } 267 268 return detailLineWithMaxPayrollAmount; 269 } 270 271 /** 272 * Gets the summaryDetailLine attribute. 273 * 274 * @return Returns the summaryDetailLine. 275 */ 276 public EffortCertificationDetail getSummaryDetailLine() { 277 return summaryDetailLine; 278 } 279 280 /** 281 * Sets the summaryDetailLine attribute value. 282 * 283 * @param summaryDetailLine The summaryDetailLine to set. 284 */ 285 public void setSummaryDetailLine(EffortCertificationDetail summaryDetailLine) { 286 this.summaryDetailLine = summaryDetailLine; 287 } 288 289 /** 290 * Gets the detailLines attribute. 291 * 292 * @return Returns the detailLines. 293 */ 294 public List<EffortCertificationDetail> getDetailLines() { 295 return detailLines; 296 } 297 298 /** 299 * Sets the detailLines attribute value. 300 * 301 * @param detailLines The detailLines to set. 302 */ 303 public void setDetailLines(List<EffortCertificationDetail> detailLines) { 304 this.detailLines = detailLines; 305 } 306 307 /** 308 * Gets the delegateDetailLine attribute. 309 * 310 * @return Returns the delegateDetailLine. 311 */ 312 public EffortCertificationDetail getDelegateDetailLine() { 313 return delegateDetailLine; 314 } 315 316 /** 317 * Sets the delegateDetailLine attribute value. 318 * 319 * @param delegateDetailLine The delegateDetailLine to set. 320 */ 321 public void setDelegateDetailLine(EffortCertificationDetail delegateDetailLine) { 322 this.delegateDetailLine = delegateDetailLine; 323 } 324 }