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.bc.document.service.impl; 017 018 import java.math.BigDecimal; 019 import java.util.ArrayList; 020 import java.util.Collection; 021 import java.util.HashMap; 022 import java.util.List; 023 import java.util.Map; 024 025 import org.apache.commons.lang.StringUtils; 026 import org.kuali.kfs.module.bc.BCConstants; 027 import org.kuali.kfs.module.bc.BCKeyConstants; 028 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAdministrativePost; 029 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAppointmentFundingReason; 030 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionAppointmentFundingReasonCode; 031 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionCalculatedSalaryFoundationTracker; 032 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionIntendedIncumbent; 033 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionOrgReasonSummaryReport; 034 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionOrgReasonSummaryReportTotal; 035 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionOrgSalarySummaryReportTotal; 036 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionPosition; 037 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionReportThresholdSettings; 038 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionSalaryFunding; 039 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionSalarySocialSecurityNumber; 040 import org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionAppointmentFunding; 041 import org.kuali.kfs.module.bc.document.dataaccess.BudgetConstructionSalarySummaryReportDao; 042 import org.kuali.kfs.module.bc.document.service.BudgetConstructionOrganizationReportsService; 043 import org.kuali.kfs.module.bc.document.service.BudgetConstructionReasonSummaryReportService; 044 import org.kuali.kfs.module.bc.document.service.BudgetConstructionReportsServiceHelper; 045 import org.kuali.kfs.module.bc.document.service.impl.BudgetConstructionSalarySummaryReportServiceImpl.OrganizationTotalHolder; 046 import org.kuali.kfs.module.bc.report.BudgetConstructionReportHelper; 047 import org.kuali.kfs.sys.KFSPropertyConstants; 048 import org.kuali.rice.kns.service.BusinessObjectService; 049 import org.kuali.rice.kns.service.KualiConfigurationService; 050 import org.kuali.rice.kns.util.KualiDecimal; 051 import org.kuali.rice.kns.util.KualiInteger; 052 import org.kuali.rice.kns.util.ObjectUtils; 053 import org.springframework.transaction.annotation.Transactional; 054 055 /** 056 * Service implementation of BudgetConstructionReasonSummaryReportService. 057 */ 058 @Transactional 059 public class BudgetConstructionReasonSummaryReportServiceImpl implements BudgetConstructionReasonSummaryReportService { 060 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BudgetConstructionReasonSummaryReportServiceImpl.class); 061 062 BudgetConstructionSalarySummaryReportDao budgetConstructionSalarySummaryReportDao; 063 BudgetConstructionOrganizationReportsService budgetConstructionOrganizationReportsService; 064 private BudgetConstructionReportsServiceHelper budgetConstructionReportsServiceHelper; 065 KualiConfigurationService kualiConfigurationService; 066 BusinessObjectService businessObjectService; 067 068 /** 069 * @see org.kuali.kfs.module.bc.document.service.BudgetConstructionReasonSummaryReportService#updateReasonSummaryReport(java.lang.String, 070 * java.lang.Integer, org.kuali.kfs.module.bc.businessobject.BudgetConstructionReportThresholdSettings) 071 */ 072 public void updateReasonSummaryReport(String principalId, Integer universityFiscalYear, BudgetConstructionReportThresholdSettings budgetConstructionReportThresholdSettings) { 073 boolean selectOnlyGreaterThanOrEqualToThreshold = budgetConstructionReportThresholdSettings.isUseGreaterThanOperator(); 074 KualiDecimal thresholdPercent = budgetConstructionReportThresholdSettings.getThresholdPercent(); 075 076 boolean applyAThreshold = budgetConstructionReportThresholdSettings.isUseThreshold(); 077 if (applyAThreshold) { 078 budgetConstructionSalarySummaryReportDao.updateSalaryAndReasonSummaryReportsWithThreshold(principalId, universityFiscalYear - 1, selectOnlyGreaterThanOrEqualToThreshold, thresholdPercent); 079 } 080 else { 081 budgetConstructionSalarySummaryReportDao.updateSalaryAndReasonSummaryReportsWithoutThreshold(principalId, true); 082 } 083 } 084 085 /** 086 * @see org.kuali.kfs.module.bc.document.service.BudgetConstructionReasonSummaryReportService#buildReports(java.lang.Integer, 087 * java.lang.String, org.kuali.kfs.module.bc.businessobject.BudgetConstructionReportThresholdSettings) 088 */ 089 public Collection<BudgetConstructionOrgReasonSummaryReport> buildReports(Integer universityFiscalYear, String principalId, BudgetConstructionReportThresholdSettings reportThresholdSettings) { 090 Collection<BudgetConstructionOrgReasonSummaryReport> reportSet = new ArrayList<BudgetConstructionOrgReasonSummaryReport>(); 091 092 BudgetConstructionOrgReasonSummaryReport reasonSummaryReport; 093 Collection<BudgetConstructionSalarySocialSecurityNumber> bcSalarySsnList = budgetConstructionReportsServiceHelper.getDataForBuildingReports(BudgetConstructionSalarySocialSecurityNumber.class, principalId, buildOrderByList()); 094 095 Map salaryFundingMap = new HashMap(); 096 for (BudgetConstructionSalarySocialSecurityNumber ssnEntry : bcSalarySsnList) { 097 Collection<BudgetConstructionSalaryFunding> salaryFundingList = budgetConstructionReportsServiceHelper.getSalaryFunding(principalId, ssnEntry.getEmplid()); 098 salaryFundingMap.put(ssnEntry, salaryFundingList); 099 } 100 101 List<BudgetConstructionSalarySocialSecurityNumber> listForCalculateTotalPerson = deleteDuplicated((List) bcSalarySsnList, 1); 102 List<BudgetConstructionSalarySocialSecurityNumber> listForCalculateTotalOrg = deleteDuplicated((List) bcSalarySsnList, 2); 103 104 // Calculate Total Section 105 Collection<BudgetConstructionOrgReasonSummaryReportTotal> reasonSummaryTotalPerson = calculatePersonTotal(universityFiscalYear, bcSalarySsnList, listForCalculateTotalPerson, salaryFundingMap); 106 Collection<BudgetConstructionOrgReasonSummaryReportTotal> reasonSummaryTotalOrg = calculateOrgTotal(reasonSummaryTotalPerson, listForCalculateTotalOrg, salaryFundingMap); 107 108 // get object codes 109 String objectCodes = budgetConstructionReportsServiceHelper.getSelectedObjectCodes(principalId); 110 111 // get reason codes 112 String reasonCodes = budgetConstructionReportsServiceHelper.getSelectedReasonCodes(principalId); 113 114 for (BudgetConstructionSalarySocialSecurityNumber ssnEntry : bcSalarySsnList) { 115 Collection<BudgetConstructionSalaryFunding> salaryFundingList = (Collection) salaryFundingMap.get(ssnEntry); 116 117 for (BudgetConstructionSalaryFunding salaryFundingEntry : salaryFundingList) { 118 reasonSummaryReport = new BudgetConstructionOrgReasonSummaryReport(); 119 buildReportsHeader(universityFiscalYear, objectCodes, reasonCodes, reasonSummaryReport, salaryFundingEntry, ssnEntry, reportThresholdSettings); 120 buildReportsBody(universityFiscalYear, reasonSummaryReport, salaryFundingEntry, ssnEntry); 121 buildReportsTotal(reasonSummaryReport, ssnEntry, reasonSummaryTotalPerson, reasonSummaryTotalOrg); 122 reportSet.add(reasonSummaryReport); 123 } 124 } 125 126 return reportSet; 127 } 128 129 /** 130 * builds report Header 131 */ 132 public void buildReportsHeader(Integer universityFiscalYear, String objectCodes, String reasonCodes, BudgetConstructionOrgReasonSummaryReport reasonSummaryReport, BudgetConstructionSalaryFunding salaryFundingEntry, BudgetConstructionSalarySocialSecurityNumber bcSSN, BudgetConstructionReportThresholdSettings budgetConstructionReportThresholdSettings) { 133 Integer prevFiscalyear = universityFiscalYear - 1; 134 reasonSummaryReport.setFiscalYear(prevFiscalyear + "-" + universityFiscalYear.toString().substring(2, 4)); 135 136 reasonSummaryReport.setOrganizationCode(bcSSN.getOrganizationCode()); 137 String organizationName = bcSSN.getOrganization().getOrganizationName(); 138 if (organizationName == null) { 139 String wrongOrganizationName = kualiConfigurationService.getPropertyString(BCKeyConstants.ERROR_REPORT_GETTING_ORGANIZATION_NAME); 140 reasonSummaryReport.setOrganizationName(wrongOrganizationName); 141 } 142 else { 143 reasonSummaryReport.setOrganizationName(organizationName); 144 } 145 146 reasonSummaryReport.setOrgChartOfAccountsCode(bcSSN.getOrganizationChartOfAccountsCode()); 147 String chartDescription = bcSSN.getOrganizationChartOfAccounts().getFinChartOfAccountDescription(); 148 if (chartDescription == null) { 149 String wrongChartDescription = kualiConfigurationService.getPropertyString(BCKeyConstants.ERROR_REPORT_GETTING_CHART_DESCRIPTION); 150 reasonSummaryReport.setOrgChartOfAccountDescription(wrongChartDescription); 151 } 152 else { 153 reasonSummaryReport.setOrgChartOfAccountDescription(chartDescription); 154 } 155 156 Integer prevPrevFiscalyear = prevFiscalyear - 1; 157 reasonSummaryReport.setReqFy(prevFiscalyear + "-" + universityFiscalYear.toString().substring(2, 4)); 158 reasonSummaryReport.setFinancialObjectCode(salaryFundingEntry.getFinancialObjectCode()); 159 160 reasonSummaryReport.setObjectCodes(objectCodes); 161 162 if (budgetConstructionReportThresholdSettings.isUseThreshold()) { 163 if (budgetConstructionReportThresholdSettings.isUseGreaterThanOperator()) { 164 reasonSummaryReport.setThresholdOrReason(BCConstants.Report.THRESHOLD + BCConstants.Report.THRESHOLD_GREATER + budgetConstructionReportThresholdSettings.getThresholdPercent().toString() + BCConstants.Report.PERCENT); 165 } 166 else { 167 reasonSummaryReport.setThresholdOrReason(BCConstants.Report.THRESHOLD + BCConstants.Report.THRESHOLD_LESS + budgetConstructionReportThresholdSettings.getThresholdPercent().toString() + BCConstants.Report.PERCENT); 168 } 169 } 170 else { 171 reasonSummaryReport.setThresholdOrReason(BCConstants.Report.SELECTED_REASONS + reasonCodes); 172 } 173 174 // reason, amt, desc 175 List<BudgetConstructionAppointmentFundingReason> appointmentFundingReasonList = salaryFundingEntry.getPendingAppointmentFunding().getBudgetConstructionAppointmentFundingReason(); 176 if (ObjectUtils.isNotNull(appointmentFundingReasonList) && !appointmentFundingReasonList.isEmpty()) { 177 BudgetConstructionAppointmentFundingReason appointmentFundingReason = appointmentFundingReasonList.get(0); 178 179 Integer reasonAmount = BudgetConstructionReportHelper.convertKualiInteger(appointmentFundingReason.getAppointmentFundingReasonAmount()); 180 reasonSummaryReport.setAppointmentFundingReasonAmount(reasonAmount); 181 182 BudgetConstructionAppointmentFundingReasonCode reasonCode = appointmentFundingReason.getAppointmentFundingReason(); 183 if (ObjectUtils.isNotNull(reasonCode)) { 184 reasonSummaryReport.setAppointmentFundingReasonDescription(reasonCode.getAppointmentFundingReasonDescription()); 185 } 186 } 187 } 188 189 /** 190 * builds report body 191 */ 192 public void buildReportsBody(Integer fiscalYear, BudgetConstructionOrgReasonSummaryReport reasonSummaryReport, BudgetConstructionSalaryFunding salaryFundingEntry, BudgetConstructionSalarySocialSecurityNumber salarySSN) { 193 int curToInt = -1; 194 double curFteInt = -1.00; 195 196 PendingBudgetConstructionAppointmentFunding appointmentFunding = salaryFundingEntry.getPendingAppointmentFunding(); 197 BudgetConstructionIntendedIncumbent intendedIncumbent = budgetConstructionReportsServiceHelper.getBudgetConstructionIntendedIncumbent(appointmentFunding); 198 if (intendedIncumbent != null) { 199 reasonSummaryReport.setIuClassificationLevel(intendedIncumbent.getIuClassificationLevel()); 200 } 201 202 int nameLength = salarySSN.getName().length(); 203 reasonSummaryReport.setName(salarySSN.getName().substring(0, (nameLength > 35) ? 35 : nameLength)); 204 205 BudgetConstructionAdministrativePost administrativePost = budgetConstructionReportsServiceHelper.getBudgetConstructionAdministrativePost(appointmentFunding); 206 BudgetConstructionPosition budgetConstructionPosition = budgetConstructionReportsServiceHelper.getBudgetConstructionPosition(fiscalYear, appointmentFunding); 207 208 // set report body 209 reasonSummaryReport.setChartOfAccountsCode(salaryFundingEntry.getChartOfAccountsCode()); 210 reasonSummaryReport.setAccountNumber(salaryFundingEntry.getAccountNumber()); 211 reasonSummaryReport.setSubAccountNumber(salaryFundingEntry.getSubAccountNumber()); 212 reasonSummaryReport.setFinancialSubObjectCode(salaryFundingEntry.getFinancialSubObjectCode()); 213 214 if (administrativePost != null) { 215 reasonSummaryReport.setAdministrativePost(administrativePost.getAdministrativePost()); 216 } 217 218 if (budgetConstructionPosition != null) { 219 reasonSummaryReport.setPositionNumber(budgetConstructionPosition.getPositionNumber()); 220 reasonSummaryReport.setNormalWorkMonthsAndiuPayMonths(budgetConstructionPosition.getIuNormalWorkMonths() + "/" + budgetConstructionPosition.getIuPayMonths()); 221 reasonSummaryReport.setPositionFte(BudgetConstructionReportHelper.setDecimalDigit(budgetConstructionPosition.getPositionFullTimeEquivalency(), 5, false)); 222 reasonSummaryReport.setPositionSalaryPlanDefault(budgetConstructionPosition.getPositionSalaryPlanDefault()); 223 reasonSummaryReport.setPositionGradeDefault(budgetConstructionPosition.getPositionGradeDefault()); 224 } 225 226 BudgetConstructionCalculatedSalaryFoundationTracker csfTracker = appointmentFunding.getEffectiveCSFTracker(); 227 if (ObjectUtils.isNotNull(csfTracker)) { 228 reasonSummaryReport.setCsfTimePercent(BudgetConstructionReportHelper.setDecimalDigit(csfTracker.getCsfTimePercent(), 2, false)); 229 reasonSummaryReport.setCsfAmount(csfTracker.getCsfAmount().intValue()); 230 231 // calculate amountChange and percentChange 232 if (appointmentFunding.getAppointmentRequestedFteQuantity().equals(csfTracker.getCsfFullTimeEmploymentQuantity())) { 233 Integer amountChange = appointmentFunding.getAppointmentRequestedAmount().subtract(csfTracker.getCsfAmount()).intValue(); 234 reasonSummaryReport.setAmountChange(amountChange); 235 236 BigDecimal percentChange = BudgetConstructionReportHelper.calculatePercent(new BigDecimal(amountChange), csfTracker.getCsfAmount().bigDecimalValue()); 237 reasonSummaryReport.setPercentChange(percentChange); 238 } 239 } 240 241 if (StringUtils.equals(appointmentFunding.getFinancialSubObjectCode(), BCConstants.Report.BLANK_SUB_OBJECT_CODE)) { 242 reasonSummaryReport.setFinancialSubObjectCode(BCConstants.Report.BLANK); 243 } 244 else { 245 reasonSummaryReport.setFinancialSubObjectCode(appointmentFunding.getFinancialSubObjectCode()); 246 } 247 248 reasonSummaryReport.setEmplid(appointmentFunding.getEmplid()); 249 reasonSummaryReport.setAppointmentFundingDurationCode(appointmentFunding.getAppointmentFundingDurationCode()); 250 reasonSummaryReport.setAppointmentTotalIntendedAmount(appointmentFunding.getAppointmentTotalIntendedAmount().intValue()); 251 252 BigDecimal totalIntendedFteQuantity = BudgetConstructionReportHelper.setDecimalDigit(appointmentFunding.getAppointmentTotalIntendedFteQuantity(), 5, false); 253 reasonSummaryReport.setAppointmentTotalIntendedFteQuantity(totalIntendedFteQuantity); 254 255 if (StringUtils.equals(appointmentFunding.getAppointmentFundingDurationCode(), BCConstants.Report.NONE)) { 256 reasonSummaryReport.setSalaryAmount(appointmentFunding.getAppointmentRequestedAmount().intValue()); 257 reasonSummaryReport.setPercentAmount(appointmentFunding.getAppointmentRequestedTimePercent()); 258 reasonSummaryReport.setSalaryMonths(appointmentFunding.getAppointmentFundingMonth()); 259 } 260 else { 261 reasonSummaryReport.setSalaryAmount(appointmentFunding.getAppointmentRequestedCsfAmount().intValue()); 262 reasonSummaryReport.setPercentAmount(appointmentFunding.getAppointmentRequestedCsfTimePercent()); 263 264 if (budgetConstructionPosition != null) { 265 reasonSummaryReport.setSalaryMonths(budgetConstructionPosition.getIuNormalWorkMonths()); 266 } 267 } 268 269 if (appointmentFunding.isAppointmentFundingDeleteIndicator()) { 270 reasonSummaryReport.setDeleteBox(BCConstants.Report.DELETE_MARK); 271 } 272 else { 273 reasonSummaryReport.setDeleteBox(BCConstants.Report.BLANK); 274 } 275 276 // set tiFlag 277 if (appointmentFunding.isAppointmentFundingDeleteIndicator()) { 278 if (curToInt == -1) { 279 curToInt = appointmentFunding.getAppointmentTotalIntendedAmount().intValue(); 280 } 281 else if (curToInt != appointmentFunding.getAppointmentTotalIntendedAmount().intValue()) { 282 reasonSummaryReport.setTiFlag(BCConstants.Report.PLUS); 283 } 284 285 if (curFteInt == -1.00) { 286 curFteInt = appointmentFunding.getAppointmentTotalIntendedFteQuantity().doubleValue(); 287 } 288 else if (curFteInt != appointmentFunding.getAppointmentTotalIntendedFteQuantity().doubleValue()) { 289 reasonSummaryReport.setTiFlag(BCConstants.Report.PLUS); 290 } 291 } 292 } 293 294 /** 295 * build the total sections for the report 296 */ 297 public void buildReportsTotal(BudgetConstructionOrgReasonSummaryReport reasonSummaryReportEntry, BudgetConstructionSalarySocialSecurityNumber ssnEntry, Collection<BudgetConstructionOrgReasonSummaryReportTotal> reasonSummaryTotalPerson, Collection<BudgetConstructionOrgReasonSummaryReportTotal> reasonSummaryTotalOrg) { 298 299 for (BudgetConstructionOrgReasonSummaryReportTotal totalPersonEntry : reasonSummaryTotalPerson) { 300 if (isSameSsnEntryForTotalPerson(totalPersonEntry.getBudgetConstructionSalarySocialSecurityNumber(), ssnEntry)) { 301 reasonSummaryReportEntry.setPersonPositionNumber(totalPersonEntry.getPersonPositionNumber()); 302 reasonSummaryReportEntry.setPersonFiscalYearTag(totalPersonEntry.getPersonFiscalYearTag()); 303 reasonSummaryReportEntry.setPersonNormalMonthsAndPayMonths(totalPersonEntry.getPersonCsfNormalMonths().toString() + "/" + totalPersonEntry.getPersonCsfPayMonths().toString()); 304 reasonSummaryReportEntry.setPersonCsfAmount(totalPersonEntry.getPersonCsfAmount()); 305 reasonSummaryReportEntry.setPersonCsfPercent(totalPersonEntry.getPersonCsfPercent()); 306 reasonSummaryReportEntry.setPersonSalaryNormalMonths(totalPersonEntry.getPersonSalaryNormalMonths()); 307 reasonSummaryReportEntry.setPersonSalaryAmount(totalPersonEntry.getPersonSalaryAmount()); 308 reasonSummaryReportEntry.setPersonSalaryPercent(totalPersonEntry.getPersonSalaryPercent()); 309 reasonSummaryReportEntry.setPersonSalaryFte(totalPersonEntry.getPersonSalaryFte()); 310 reasonSummaryReportEntry.setPersonTiFlag(totalPersonEntry.getPersonTiFlag()); 311 reasonSummaryReportEntry.setPersonAmountChange(totalPersonEntry.getPersonAmountChange()); 312 reasonSummaryReportEntry.setPersonPercentChange(totalPersonEntry.getPersonPercentChange()); 313 } 314 for (BudgetConstructionOrgReasonSummaryReportTotal totalOrgEntry : reasonSummaryTotalOrg) { 315 if (isSameSsnEntryForTotalOrg(totalOrgEntry.getBudgetConstructionSalarySocialSecurityNumber(), ssnEntry)) { 316 reasonSummaryReportEntry.setNewFte(totalOrgEntry.getNewFte()); 317 reasonSummaryReportEntry.setNewTotalAmount(totalOrgEntry.getNewTotalAmount()); 318 reasonSummaryReportEntry.setConTotalBaseAmount(totalOrgEntry.getConTotalBaseAmount()); 319 reasonSummaryReportEntry.setConFte(totalOrgEntry.getConFte()); 320 reasonSummaryReportEntry.setConTotalRequestAmount(totalOrgEntry.getConTotalRequestAmount()); 321 reasonSummaryReportEntry.setNewAverageAmount(totalOrgEntry.getNewAverageAmount()); 322 reasonSummaryReportEntry.setConAverageBaseAmount(totalOrgEntry.getConAverageBaseAmount()); 323 reasonSummaryReportEntry.setConAverageRequestAmount(totalOrgEntry.getConAverageRequestAmount()); 324 reasonSummaryReportEntry.setConAveragechange(totalOrgEntry.getConAveragechange()); 325 reasonSummaryReportEntry.setConPercentChange(totalOrgEntry.getConPercentChange()); 326 } 327 } 328 } 329 } 330 331 // calculate the totals for the given person 332 protected Collection<BudgetConstructionOrgReasonSummaryReportTotal> calculatePersonTotal(Integer universityFiscalYear, Collection<BudgetConstructionSalarySocialSecurityNumber> bcSalarySsnList, List<BudgetConstructionSalarySocialSecurityNumber> listForCalculateTotalPerson, Map salaryFundingMap) { 333 Collection<BudgetConstructionOrgReasonSummaryReportTotal> returnCollection = new ArrayList<BudgetConstructionOrgReasonSummaryReportTotal>(); 334 335 for (BudgetConstructionSalarySocialSecurityNumber personEntry : listForCalculateTotalPerson) { 336 PersonTotalHolder totalsHolder = new PersonTotalHolder(); 337 totalsHolder.emplid = personEntry.getEmplid(); 338 339 for (BudgetConstructionSalarySocialSecurityNumber salaryFundingEntry : bcSalarySsnList) { 340 if (isSameSsnEntryForTotalPerson(personEntry, salaryFundingEntry)) { 341 Collection<BudgetConstructionSalaryFunding> salaryFundings = (Collection<BudgetConstructionSalaryFunding>) salaryFundingMap.get(personEntry); 342 this.collectPersonTotal(universityFiscalYear, salaryFundings, totalsHolder); 343 } 344 } 345 346 this.adjustPersonTotal(totalsHolder); 347 returnCollection.add(this.createReportTotal(personEntry, totalsHolder)); 348 } 349 350 return returnCollection; 351 } 352 353 // adjust the total amount that just is held by the given holder 354 protected void adjustPersonTotal(PersonTotalHolder totalsHolder) { 355 Integer restatementCsfAmount = 0; 356 if (totalsHolder.salaryPayMonth == 0 || totalsHolder.csfPayMonths == 0 || BigDecimal.ZERO.compareTo(totalsHolder.csfPercent) == 0 || totalsHolder.csfNormalMonths == 0) { 357 restatementCsfAmount = 0; 358 } 359 else { 360 BigDecimal salaryMonthPercent = new BigDecimal(totalsHolder.salaryNormalMonths * 1.0 / totalsHolder.salaryPayMonth); 361 BigDecimal salaryFteQuantity = totalsHolder.salaryPercent.multiply(salaryMonthPercent); 362 363 BigDecimal csfMonthpercent = new BigDecimal(totalsHolder.csfNormalMonths * 1.0 / totalsHolder.csfPayMonths); 364 BigDecimal csfFteQuantity = totalsHolder.csfPercent.multiply(csfMonthpercent); 365 366 BigDecimal restatementCsfPercent = salaryFteQuantity.divide(csfFteQuantity); 367 BigDecimal csfAmount = new BigDecimal(totalsHolder.csfAmount); 368 restatementCsfAmount = csfAmount.multiply(restatementCsfPercent).intValue(); 369 } 370 371 if (totalsHolder.salaryPayMonth == 0) { 372 totalsHolder.salaryFte = BigDecimal.ZERO; 373 } 374 else { 375 BigDecimal salaryFte = totalsHolder.salaryPercent.multiply(new BigDecimal(totalsHolder.salaryNormalMonths * 1.0 / (totalsHolder.salaryPayMonth * 100.0))); 376 totalsHolder.salaryFte = BudgetConstructionReportHelper.setDecimalDigit(salaryFte, 5, false); 377 } 378 379 if (totalsHolder.salaryPayMonth != totalsHolder.csfPayMonths) { 380 if (totalsHolder.csfPayMonths == 0) { 381 restatementCsfAmount = 0; 382 } 383 else { 384 BigDecimal amount = new BigDecimal(restatementCsfAmount * totalsHolder.salaryPayMonth * 1.0 / totalsHolder.csfPayMonths); 385 restatementCsfAmount = BudgetConstructionReportHelper.setDecimalDigit(amount, 0, false).intValue(); 386 } 387 } 388 389 totalsHolder.csfAmount = restatementCsfAmount; 390 totalsHolder.amountChange = totalsHolder.salaryAmount - totalsHolder.csfAmount; 391 392 if (totalsHolder.csfAmount != 0) { 393 totalsHolder.percentChange = BudgetConstructionReportHelper.calculatePercent(totalsHolder.amountChange, totalsHolder.csfAmount); 394 } 395 else { 396 totalsHolder.percentChange = BigDecimal.ZERO; 397 } 398 399 if (totalsHolder.curToInt != 0 && totalsHolder.curToInt != -1 && totalsHolder.curToInt != totalsHolder.salaryAmount.intValue() || totalsHolder.curFteInt != 0 && totalsHolder.curFteInt != -1.00 && totalsHolder.curFteInt != totalsHolder.salaryFte.doubleValue()) { 400 totalsHolder.tiFlag = BCConstants.Report.PLUS; 401 } 402 else { 403 totalsHolder.tiFlag = BCConstants.Report.BLANK; 404 } 405 } 406 407 // collect the total amounts for a single person and save the totals in the given holder 408 protected void collectPersonTotal(Integer universityFiscalYear, Collection<BudgetConstructionSalaryFunding> salaryFundings, PersonTotalHolder totalsHolder) { 409 int maxSalaryAmount = 0; 410 int maxCsfAmount = 0; 411 412 for (BudgetConstructionSalaryFunding salaryFunding : salaryFundings) { 413 PendingBudgetConstructionAppointmentFunding appointmentFunding = salaryFunding.getPendingAppointmentFunding(); 414 BudgetConstructionPosition budgetConstructionPosition = budgetConstructionReportsServiceHelper.getBudgetConstructionPosition(universityFiscalYear, appointmentFunding); 415 416 int salaryAmount = 0; 417 BigDecimal salaryPercent = BigDecimal.ZERO; 418 String durationCode = appointmentFunding.getAppointmentFundingDurationCode(); 419 420 if (StringUtils.equals(durationCode, BCConstants.Report.NONE)) { 421 salaryAmount = appointmentFunding.getAppointmentRequestedAmount().intValue(); 422 totalsHolder.salaryNormalMonths = appointmentFunding.getAppointmentFundingMonth(); 423 salaryPercent = appointmentFunding.getAppointmentRequestedTimePercent(); 424 } 425 else { 426 salaryAmount = appointmentFunding.getAppointmentRequestedCsfAmount().intValue(); 427 totalsHolder.salaryNormalMonths = budgetConstructionPosition.getIuNormalWorkMonths(); 428 429 boolean hasRequestedCsfTimePercent = appointmentFunding.getAppointmentRequestedCsfTimePercent() != null; 430 salaryPercent = hasRequestedCsfTimePercent ? appointmentFunding.getAppointmentRequestedCsfTimePercent() : BigDecimal.ZERO; 431 } 432 433 if (salaryAmount > maxSalaryAmount) { 434 maxSalaryAmount = totalsHolder.salaryAmount; 435 totalsHolder.salaryPayMonth = budgetConstructionPosition.getIuPayMonths(); 436 totalsHolder.salaryNormalMonths = appointmentFunding.getAppointmentFundingMonth(); 437 } 438 439 totalsHolder.salaryAmount += salaryAmount; 440 totalsHolder.salaryPercent = totalsHolder.salaryPercent.add(salaryPercent); 441 442 BudgetConstructionCalculatedSalaryFoundationTracker csfTracker = appointmentFunding.getEffectiveCSFTracker(); 443 if (csfTracker == null) { 444 continue; 445 } 446 447 KualiInteger effectiveCsfAmount = csfTracker.getCsfAmount(); 448 if (effectiveCsfAmount == null || effectiveCsfAmount.isZero()) { 449 continue; 450 } 451 452 if (effectiveCsfAmount.intValue() > maxCsfAmount) { 453 maxCsfAmount = effectiveCsfAmount.intValue(); 454 } 455 456 totalsHolder.csfAmount += effectiveCsfAmount.intValue(); 457 totalsHolder.csfPercent = totalsHolder.csfPercent.add(csfTracker.getCsfTimePercent()); 458 459 // data for previous year, position table has two data, one is for current year and another is for previous year. 460 Integer previousFiscalYear = universityFiscalYear - 1; 461 BudgetConstructionPosition previousYearBudgetConstructionPosition = budgetConstructionReportsServiceHelper.getBudgetConstructionPosition(previousFiscalYear, appointmentFunding); 462 463 totalsHolder.csfPayMonths = previousYearBudgetConstructionPosition.getIuPayMonths(); 464 totalsHolder.csfNormalMonths = previousYearBudgetConstructionPosition.getIuNormalWorkMonths(); 465 466 totalsHolder.positionNumber = budgetConstructionPosition.getPositionNumber(); 467 totalsHolder.fiscalYearTag = previousFiscalYear.toString() + ":"; 468 469 if (!appointmentFunding.isAppointmentFundingDeleteIndicator()) { 470 if (totalsHolder.curToInt <= -1) { 471 totalsHolder.curToInt = appointmentFunding.getAppointmentTotalIntendedAmount().intValue(); 472 } 473 474 if (totalsHolder.curFteInt <= -1.00) { 475 totalsHolder.curFteInt = appointmentFunding.getAppointmentTotalIntendedFteQuantity().doubleValue(); 476 } 477 } 478 } 479 } 480 481 // calculate the totals for the given organization 482 protected Collection<BudgetConstructionOrgReasonSummaryReportTotal> calculateOrgTotal(Collection<BudgetConstructionOrgReasonSummaryReportTotal> reasonSummaryTotalPerson, List<BudgetConstructionSalarySocialSecurityNumber> listForCalculateTotalOrg, Map salaryFundingMap) { 483 Collection<BudgetConstructionOrgReasonSummaryReportTotal> returnCollection = new ArrayList<BudgetConstructionOrgReasonSummaryReportTotal>(); 484 485 for (BudgetConstructionSalarySocialSecurityNumber totalOrgEntry : listForCalculateTotalOrg) { 486 OrganizationTotalHolder totalsHolder = new OrganizationTotalHolder(); 487 488 for (BudgetConstructionOrgReasonSummaryReportTotal reportTotalPersonEntry : reasonSummaryTotalPerson) { 489 if (isSameSsnEntryForTotalOrg(totalOrgEntry, reportTotalPersonEntry.getBudgetConstructionSalarySocialSecurityNumber())) { 490 if (reportTotalPersonEntry.getPersonCsfAmount() == 0) { 491 totalsHolder.newFte = totalsHolder.newFte.add(reportTotalPersonEntry.getPersonSalaryFte()); 492 totalsHolder.newTotalAmount += reportTotalPersonEntry.getPersonSalaryAmount(); 493 } 494 else { 495 totalsHolder.conTotalBaseAmount += reportTotalPersonEntry.getPersonCsfAmount(); 496 totalsHolder.conFte = totalsHolder.conFte.add(reportTotalPersonEntry.getPersonSalaryFte()); 497 totalsHolder.conTotalRequestAmount += reportTotalPersonEntry.getPersonSalaryAmount(); 498 } 499 } 500 } 501 502 // calculate average and change 503 if (BigDecimal.ZERO.compareTo(totalsHolder.newFte) != 0) { 504 BigDecimal averageAmount = BudgetConstructionReportHelper.calculateDivide(new BigDecimal(totalsHolder.newTotalAmount), totalsHolder.newFte); 505 totalsHolder.newAverageAmount = BudgetConstructionReportHelper.setDecimalDigit(averageAmount, 0, false).intValue(); 506 } 507 508 if (BigDecimal.ZERO.compareTo(totalsHolder.conFte) != 0) { 509 BigDecimal averageAmount = BudgetConstructionReportHelper.calculateDivide(new BigDecimal(totalsHolder.conTotalBaseAmount), totalsHolder.conFte); 510 totalsHolder.conAverageBaseAmount = BudgetConstructionReportHelper.setDecimalDigit(averageAmount, 0, false).intValue(); 511 512 BigDecimal averageRequestAmount = BudgetConstructionReportHelper.calculateDivide(new BigDecimal(totalsHolder.conTotalRequestAmount), totalsHolder.conFte); 513 totalsHolder.conAverageRequestAmount = BudgetConstructionReportHelper.setDecimalDigit(averageRequestAmount, 0, false).intValue(); 514 } 515 516 totalsHolder.conAveragechange = totalsHolder.conAverageRequestAmount - totalsHolder.conAverageBaseAmount; 517 518 if (totalsHolder.conAverageBaseAmount != 0) { 519 totalsHolder.conPercentChange = BudgetConstructionReportHelper.calculatePercent(totalsHolder.conAveragechange, totalsHolder.conAverageBaseAmount); 520 } 521 522 returnCollection.add(this.createReportTotal(totalOrgEntry, totalsHolder)); 523 } 524 525 return returnCollection; 526 } 527 528 // create a report total for the given organization with the values in the given total holder 529 protected BudgetConstructionOrgReasonSummaryReportTotal createReportTotal(BudgetConstructionSalarySocialSecurityNumber totalOrgEntry, OrganizationTotalHolder totalsHolder) { 530 BudgetConstructionOrgReasonSummaryReportTotal reportTotal = new BudgetConstructionOrgReasonSummaryReportTotal(); 531 532 reportTotal.setBudgetConstructionSalarySocialSecurityNumber(totalOrgEntry); 533 reportTotal.setNewFte(totalsHolder.newFte); 534 reportTotal.setNewTotalAmount(totalsHolder.newTotalAmount); 535 reportTotal.setConTotalBaseAmount(totalsHolder.conTotalBaseAmount); 536 reportTotal.setConFte(totalsHolder.conFte); 537 reportTotal.setConTotalRequestAmount(totalsHolder.conTotalRequestAmount); 538 reportTotal.setNewAverageAmount(totalsHolder.newAverageAmount); 539 reportTotal.setConAverageBaseAmount(totalsHolder.conAverageBaseAmount); 540 reportTotal.setConAverageRequestAmount(totalsHolder.conAverageRequestAmount); 541 reportTotal.setConAveragechange(totalsHolder.conAveragechange); 542 reportTotal.setConPercentChange(totalsHolder.conPercentChange); 543 544 return reportTotal; 545 } 546 547 548 // create a report total for the given person with the values in the given total holder 549 protected BudgetConstructionOrgReasonSummaryReportTotal createReportTotal(BudgetConstructionSalarySocialSecurityNumber totalPersonEntry, PersonTotalHolder totalsHolder) { 550 BudgetConstructionOrgReasonSummaryReportTotal reportTotal = new BudgetConstructionOrgReasonSummaryReportTotal(); 551 552 reportTotal.setBudgetConstructionSalarySocialSecurityNumber(totalPersonEntry); 553 reportTotal.setPersonPositionNumber(totalsHolder.positionNumber); 554 reportTotal.setPersonFiscalYearTag(totalsHolder.fiscalYearTag); 555 reportTotal.setPersonCsfNormalMonths(totalsHolder.csfNormalMonths); 556 reportTotal.setPersonCsfPayMonths(totalsHolder.csfPayMonths); 557 reportTotal.setPersonCsfAmount(totalsHolder.csfAmount); 558 reportTotal.setPersonCsfPercent(totalsHolder.csfPercent); 559 reportTotal.setPersonSalaryNormalMonths(totalsHolder.salaryNormalMonths); 560 reportTotal.setPersonSalaryAmount(totalsHolder.salaryAmount); 561 reportTotal.setPersonSalaryPercent(totalsHolder.salaryPercent); 562 reportTotal.setPersonSalaryFte(BudgetConstructionReportHelper.setDecimalDigit(totalsHolder.salaryFte, 5, false)); 563 reportTotal.setPersonTiFlag(totalsHolder.tiFlag); 564 reportTotal.setPersonAmountChange(totalsHolder.amountChange); 565 reportTotal.setPersonPercentChange(totalsHolder.percentChange); 566 567 return reportTotal; 568 } 569 570 571 // a total holder that contains the totals for a single person 572 protected class PersonTotalHolder { 573 String emplid = StringUtils.EMPTY; 574 String positionNumber = StringUtils.EMPTY; 575 String fiscalYearTag = StringUtils.EMPTY; 576 String tiFlag = StringUtils.EMPTY; 577 578 Integer csfNormalMonths = 0; 579 Integer csfPayMonths = 0; 580 Integer csfAmount = 0; 581 BigDecimal csfPercent = BigDecimal.ZERO; 582 583 Integer salaryNormalMonths = 0; 584 Integer salaryPayMonth = 0; 585 Integer salaryAmount = 0; 586 BigDecimal salaryPercent = BigDecimal.ZERO; 587 BigDecimal salaryFte = BigDecimal.ZERO; 588 589 Integer amountChange = 0; 590 BigDecimal percentChange = BigDecimal.ZERO; 591 592 int curToInt = -1; 593 double curFteInt = -1.00; 594 } 595 596 // a total holder that contains the totals for an organization 597 protected class OrganizationTotalHolder { 598 BigDecimal newFte = BigDecimal.ZERO; 599 Integer newTotalAmount = 0; 600 Integer newAverageAmount = 0; 601 BigDecimal conFte = BigDecimal.ZERO; 602 Integer conTotalBaseAmount = 0; 603 Integer conTotalRequestAmount = 0; 604 Integer conAverageBaseAmount = 0; 605 Integer conAverageRequestAmount = 0; 606 Integer conAveragechange = 0; 607 BigDecimal conPercentChange = BigDecimal.ZERO; 608 } 609 610 /** 611 * builds orderByList for sort order. 612 * 613 * @return returnList 614 */ 615 public List<String> buildOrderByList() { 616 List<String> returnList = new ArrayList<String>(); 617 returnList.add(KFSPropertyConstants.ORGANIZATION_CHART_OF_ACCOUNTS_CODE); 618 returnList.add(KFSPropertyConstants.ORGANIZATION_CODE); 619 returnList.add(KFSPropertyConstants.PERSON_NAME); 620 returnList.add(KFSPropertyConstants.EMPLID); 621 622 return returnList; 623 } 624 625 /** 626 * Deletes duplicated entry from list 627 * 628 * @param List list 629 * @return a list that all duplicated entries were deleted 630 */ 631 protected List deleteDuplicated(List list, int mode) { 632 // mode 1 is for getting a list of total object 633 // mode 2 is for getting a list of total account 634 int count = 0; 635 BudgetConstructionSalarySocialSecurityNumber ssnEntry = null; 636 BudgetConstructionSalarySocialSecurityNumber ssnEntryAux = null; 637 List returnList = new ArrayList(); 638 if ((list != null) && (list.size() > 0)) { 639 ssnEntry = (BudgetConstructionSalarySocialSecurityNumber) list.get(count); 640 ssnEntryAux = (BudgetConstructionSalarySocialSecurityNumber) list.get(count); 641 returnList.add(ssnEntry); 642 count++; 643 while (count < list.size()) { 644 ssnEntry = (BudgetConstructionSalarySocialSecurityNumber) list.get(count); 645 switch (mode) { 646 case 1: { 647 if (!isSameSsnEntryForTotalPerson(ssnEntry, ssnEntryAux)) { 648 returnList.add(ssnEntry); 649 ssnEntryAux = ssnEntry; 650 } 651 } 652 case 2: { 653 if (!isSameSsnEntryForTotalOrg(ssnEntry, ssnEntryAux)) { 654 returnList.add(ssnEntry); 655 ssnEntryAux = ssnEntry; 656 } 657 } 658 } 659 count++; 660 } 661 } 662 return returnList; 663 } 664 665 protected boolean isSameSsnEntryForTotalPerson(BudgetConstructionSalarySocialSecurityNumber firstSsn, BudgetConstructionSalarySocialSecurityNumber secondSsn) { 666 if (firstSsn.getOrganizationChartOfAccountsCode().equals(secondSsn.getOrganizationChartOfAccountsCode()) && firstSsn.getOrganizationCode().equals(secondSsn.getOrganizationCode()) && firstSsn.getEmplid().equals(secondSsn.getEmplid())) { 667 return true; 668 } 669 else 670 return false; 671 } 672 673 protected boolean isSameSsnEntryForTotalOrg(BudgetConstructionSalarySocialSecurityNumber firstSsn, BudgetConstructionSalarySocialSecurityNumber secondSsn) { 674 if (firstSsn.getOrganizationChartOfAccountsCode().equals(secondSsn.getOrganizationChartOfAccountsCode()) && firstSsn.getOrganizationCode().equals(secondSsn.getOrganizationCode())) { 675 return true; 676 } 677 else 678 return false; 679 } 680 681 /** 682 * Sets the budgetConstructionSalarySummaryReportDao attribute value. 683 * 684 * @param budgetConstructionSalarySummaryReportDao The budgetConstructionSalarySummaryReportDao to set. 685 */ 686 public void setBudgetConstructionSalarySummaryReportDao(BudgetConstructionSalarySummaryReportDao budgetConstructionSalarySummaryReportDao) { 687 this.budgetConstructionSalarySummaryReportDao = budgetConstructionSalarySummaryReportDao; 688 } 689 690 /** 691 * Sets the budgetConstructionOrganizationReportsService attribute value. 692 * 693 * @param budgetConstructionOrganizationReportsService The budgetConstructionOrganizationReportsService to set. 694 */ 695 public void setBudgetConstructionOrganizationReportsService(BudgetConstructionOrganizationReportsService budgetConstructionOrganizationReportsService) { 696 this.budgetConstructionOrganizationReportsService = budgetConstructionOrganizationReportsService; 697 } 698 699 /** 700 * Sets the budgetConstructionReportsServiceHelper attribute value. 701 * 702 * @param budgetConstructionReportsServiceHelper The budgetConstructionReportsServiceHelper to set. 703 */ 704 public void setBudgetConstructionReportsServiceHelper(BudgetConstructionReportsServiceHelper budgetConstructionReportsServiceHelper) { 705 this.budgetConstructionReportsServiceHelper = budgetConstructionReportsServiceHelper; 706 } 707 708 /** 709 * Sets the kualiConfigurationService attribute value. 710 * 711 * @param kualiConfigurationService The kualiConfigurationService to set. 712 */ 713 public void setKualiConfigurationService(KualiConfigurationService kualiConfigurationService) { 714 this.kualiConfigurationService = kualiConfigurationService; 715 } 716 717 /** 718 * Sets the businessObjectService attribute value. 719 * 720 * @param businessObjectService The businessObjectService to set. 721 */ 722 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 723 this.businessObjectService = businessObjectService; 724 } 725 }