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