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 }