001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.module.labor.service.impl;
017:
018: import static org.kuali.module.gl.bo.OriginEntrySource.LABOR_YEAR_END_BALANCE_FORWARD;
019: import static org.kuali.module.labor.LaborConstants.DestinationNames.LEDGER_BALANCE;
020: import static org.kuali.module.labor.LaborConstants.DestinationNames.ORIGN_ENTRY;
021:
022: import java.math.BigDecimal;
023: import java.sql.Date;
024: import java.util.ArrayList;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029:
030: import org.kuali.core.service.BusinessObjectService;
031: import org.kuali.core.service.DateTimeService;
032: import org.kuali.core.service.KualiConfigurationService;
033: import org.kuali.core.util.KualiDecimal;
034: import org.kuali.kfs.KFSConstants;
035: import org.kuali.kfs.KFSPropertyConstants;
036: import org.kuali.kfs.bo.Options;
037: import org.kuali.kfs.context.SpringContext;
038: import org.kuali.kfs.service.OptionsService;
039: import org.kuali.kfs.service.ParameterService;
040: import org.kuali.kfs.service.impl.ParameterConstants;
041: import org.kuali.module.gl.GLConstants;
042: import org.kuali.module.gl.bo.OriginEntryGroup;
043: import org.kuali.module.gl.bo.Transaction;
044: import org.kuali.module.gl.service.OriginEntryGroupService;
045: import org.kuali.module.gl.util.Message;
046: import org.kuali.module.gl.util.Summary;
047: import org.kuali.module.labor.LaborConstants;
048: import org.kuali.module.labor.LaborKeyConstants;
049: import org.kuali.module.labor.LaborConstants.YearEnd;
050: import org.kuali.module.labor.batch.LaborYearEndBalanceForwardStep;
051: import org.kuali.module.labor.bo.LaborOriginEntry;
052: import org.kuali.module.labor.bo.LedgerBalance;
053: import org.kuali.module.labor.bo.LedgerBalanceForYearEndBalanceForward;
054: import org.kuali.module.labor.service.LaborLedgerBalanceService;
055: import org.kuali.module.labor.service.LaborOriginEntryService;
056: import org.kuali.module.labor.service.LaborReportService;
057: import org.kuali.module.labor.service.LaborYearEndBalanceForwardService;
058: import org.kuali.module.labor.util.DebitCreditUtil;
059: import org.kuali.module.labor.util.ObjectUtil;
060: import org.kuali.module.labor.util.ReportRegistry;
061: import org.springframework.transaction.annotation.Transactional;
062:
063: /**
064: * Labor Ledger Year End – Inception to Date Beginning Balance process moves the Year-to-Date Total plus the Contracts and Grants
065: * Beginning Balances to the Contracts and Grants Beginning Balances of the new fiscal year for a designated group of accounts (to
066: * be identified by fund group and sub fund group).
067: */
068: @Transactional
069: public class LaborYearEndBalanceForwardServiceImpl implements
070: LaborYearEndBalanceForwardService {
071: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
072: .getLogger(LaborYearEndBalanceForwardServiceImpl.class);
073:
074: private LaborLedgerBalanceService laborLedgerBalanceService;
075: private OriginEntryGroupService originEntryGroupService;
076: private LaborOriginEntryService laborOriginEntryService;
077:
078: private OptionsService optionsService;
079:
080: private BusinessObjectService businessObjectService;
081: private LaborReportService laborReportService;
082: private DateTimeService dateTimeService;
083: private ParameterService parameterService;
084:
085: private final static int LINE_INTERVAL = 2;
086:
087: /**
088: * @see org.kuali.module.labor.service.LaborYearEndBalanceForwardService#forwardBalance()
089: */
090: public void forwardBalance() {
091: Integer fiscalYear = Integer.valueOf(parameterService
092: .getParameterValue(
093: LaborYearEndBalanceForwardStep.class,
094: YearEnd.OLD_FISCAL_YEAR));
095: this .forwardBalance(fiscalYear);
096: }
097:
098: /**
099: * @see org.kuali.module.labor.service.LaborYearEndBalanceForwardService#forwardBalance(java.lang.Integer)
100: */
101: public void forwardBalance(Integer fiscalYear) {
102: forwardBalance(fiscalYear, fiscalYear + 1);
103: }
104:
105: /**
106: * @see org.kuali.module.labor.service.LaborYearEndBalanceForwardService#forwardBalance(java.lang.Integer, java.lang.Integer)
107: */
108: public void forwardBalance(Integer fiscalYear, Integer newFiscalYear) {
109: String reportsDirectory = ReportRegistry.getReportsDirectory();
110: Date runDate = dateTimeService.getCurrentSqlDate();
111:
112: List<Summary> reportSummary = new ArrayList<Summary>();
113: Map<Transaction, List<Message>> errorMap = new HashMap<Transaction, List<Message>>();
114: OriginEntryGroup validGroup = originEntryGroupService
115: .createGroup(runDate, LABOR_YEAR_END_BALANCE_FORWARD,
116: true, true, true);
117:
118: Map<String, String> fieldValues = new HashMap<String, String>();
119: fieldValues.put(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR,
120: fiscalYear.toString());
121:
122: int numberOfBalance = businessObjectService.countMatching(
123: LedgerBalance.class, fieldValues);
124: int numberOfSelectedBalance = this .processLedgerBalances(
125: fiscalYear, newFiscalYear, validGroup, errorMap,
126: runDate);
127:
128: Summary.updateReportSummary(reportSummary, LEDGER_BALANCE,
129: KFSConstants.OperationType.READ, numberOfBalance, 0);
130: Summary.updateReportSummary(reportSummary, LEDGER_BALANCE,
131: KFSConstants.OperationType.SELECT,
132: numberOfSelectedBalance, 0);
133: Summary.updateReportSummary(reportSummary, LEDGER_BALANCE,
134: KFSConstants.OperationType.REPORT_ERROR, errorMap
135: .size(), 0);
136: reportSummary.add(new Summary(reportSummary.size()
137: + LINE_INTERVAL, "", 0));
138: Summary.updateReportSummary(reportSummary, ORIGN_ENTRY,
139: KFSConstants.OperationType.INSERT,
140: numberOfSelectedBalance, 0);
141:
142: laborReportService.generateStatisticsReport(reportSummary,
143: errorMap, ReportRegistry.LABOR_YEAR_END_STATISTICS,
144: reportsDirectory, runDate);
145: laborReportService.generateOutputSummaryReport(validGroup,
146: ReportRegistry.LABOR_YEAR_END_OUTPUT, reportsDirectory,
147: runDate);
148: }
149:
150: /**
151: * post the qualified balances into origin entry table for the further labor ledger processing
152: *
153: * @param balanceIterator the given ledger balances that will be carried forward
154: * @param newFiscalYear the new fiscal year
155: * @param validGroup the group that the posted transaction belongs to
156: * @param errorMap the map that records the error messages
157: * @param runDate the date the transaction is posted
158: * @return the number of qualified balances
159: */
160: private int processLedgerBalances(Integer fiscalYear,
161: Integer newFiscalYear, OriginEntryGroup validGroup,
162: Map<Transaction, List<Message>> errorMap, Date runDate) {
163: Options options = optionsService.getOptions(fiscalYear);
164:
165: List<String> processableBalanceTypeCodes = this
166: .getProcessableBalanceTypeCode(options);
167: List<String> processableObjectTypeCodes = this
168: .getProcessableObjectTypeCodes(options);
169: List<String> subFundGroupCodes = this
170: .getSubFundGroupProcessed();
171: List<String> fundGroupCodes = this .getFundGroupProcessed();
172:
173: // process the selected balances by balance type and object type
174: Map<String, String> fieldValues = new HashMap<String, String>();
175: int numberOfSelectedBalance = 0;
176: for (String balanceTypeCode : processableBalanceTypeCodes) {
177: fieldValues.put(
178: KFSPropertyConstants.FINANCIAL_BALANCE_TYPE_CODE,
179: balanceTypeCode);
180:
181: for (String objectTypeCode : processableObjectTypeCodes) {
182: fieldValues
183: .put(
184: KFSPropertyConstants.FINANCIAL_OBJECT_TYPE_CODE,
185: objectTypeCode);
186:
187: fieldValues.remove(LaborConstants.ACCOUNT_FIELDS[0]);
188: fieldValues.remove(LaborConstants.ACCOUNT_FIELDS[1]);
189: List<List<String>> accounts = laborLedgerBalanceService
190: .findAccountsInFundGroups(fiscalYear,
191: fieldValues, subFundGroupCodes,
192: fundGroupCodes);
193:
194: for (List<String> account : accounts) {
195: fieldValues.put(LaborConstants.ACCOUNT_FIELDS[0],
196: account.get(0));
197: fieldValues.put(LaborConstants.ACCOUNT_FIELDS[1],
198: account.get(1));
199:
200: Iterator<LedgerBalanceForYearEndBalanceForward> balanceIterator = laborLedgerBalanceService
201: .findBalancesForFiscalYear(fiscalYear,
202: fieldValues, subFundGroupCodes,
203: fundGroupCodes);
204: numberOfSelectedBalance += postSelectedBalancesAsOriginEntries(
205: balanceIterator, newFiscalYear, validGroup,
206: errorMap, runDate);
207: }
208: }
209: }
210: return numberOfSelectedBalance;
211: }
212:
213: /**
214: * post the qualified balances into origin entry table for the further labor ledger processing
215: *
216: * @param balanceIterator the given ledger balances that will be carried forward
217: * @param newFiscalYear the new fiscal year
218: * @param validGroup the group that the posted transaction belongs to
219: * @param errorMap the map that records the error messages
220: * @param runDate the date the transaction is posted
221: * @return the number of qualified balances
222: */
223: private int postSelectedBalancesAsOriginEntries(
224: Iterator<LedgerBalanceForYearEndBalanceForward> balanceIterator,
225: Integer newFiscalYear, OriginEntryGroup validGroup,
226: Map<Transaction, List<Message>> errorMap, Date runDate) {
227: int numberOfSelectedBalance = 0;
228: String description = this .getDescription();
229: String originationCode = this .getOriginationCode();
230: String documentTypeCode = this .getDocumentTypeCode();
231:
232: while (balanceIterator != null && balanceIterator.hasNext()) {
233: LedgerBalanceForYearEndBalanceForward balance = balanceIterator
234: .next();
235: List<Message> errors = null;
236:
237: boolean isValidBalance = validateBalance(balance, errors);
238: LaborOriginEntry laborOriginEntry = new LaborOriginEntry();
239: if (isValidBalance) {
240: laborOriginEntry.setEntryGroupId(validGroup.getId());
241: laborOriginEntry.setUniversityFiscalYear(newFiscalYear);
242: laborOriginEntry
243: .setFinancialDocumentTypeCode(documentTypeCode);
244: laborOriginEntry
245: .setFinancialSystemOriginationCode(originationCode);
246: laborOriginEntry
247: .setTransactionLedgerEntryDescription(description);
248:
249: this .postAsOriginEntry(balance, laborOriginEntry,
250: runDate);
251: numberOfSelectedBalance++;
252: } else if (errors != null && !errors.isEmpty()) {
253: ObjectUtil.buildObject(laborOriginEntry, balance);
254: errorMap.put(laborOriginEntry, errors);
255: }
256: laborOriginEntry = null;
257: balance = null;
258: }
259: return numberOfSelectedBalance;
260: }
261:
262: /**
263: * determine if the given balance is qualified to be carried forward to new fiscal year
264: *
265: * @param balance the given ledger balance that could be carried forward
266: * @param errors the error list that is updated if the given balacne is not qualified for carry forward
267: * @return true if the balance is qualified; otherwise, false
268: */
269: private boolean validateBalance(
270: LedgerBalanceForYearEndBalanceForward balance,
271: List<Message> errors) {
272: /** This is the placeholder for addtional business rule validation. The former rules were moved down to data access layer. * */
273: return true;
274: }
275:
276: /**
277: * post the qualified balance into origin entry table for the further labor ledger processing
278: *
279: * @param balance the given ledger balance that will be carried forward
280: * @param newFiscalYear the new fiscal year
281: * @param validGroup the group that the posted transaction belongs to
282: * @param postingDate the date the transaction is posted
283: */
284: private void postAsOriginEntry(
285: LedgerBalanceForYearEndBalanceForward balance,
286: LaborOriginEntry originEntry, Date postingDate) {
287: try {
288: originEntry.setAccountNumber(balance.getAccountNumber());
289: originEntry.setChartOfAccountsCode(balance
290: .getChartOfAccountsCode());
291: originEntry.setSubAccountNumber(balance
292: .getSubAccountNumber());
293: originEntry.setFinancialObjectCode(balance
294: .getFinancialObjectCode());
295: originEntry.setFinancialSubObjectCode(balance
296: .getFinancialSubObjectCode());
297: originEntry.setFinancialBalanceTypeCode(balance
298: .getFinancialBalanceTypeCode());
299: originEntry.setFinancialObjectTypeCode(balance
300: .getFinancialObjectTypeCode());
301:
302: originEntry.setPositionNumber(balance.getPositionNumber());
303: originEntry.setEmplid(balance.getEmplid());
304: originEntry.setDocumentNumber(balance
305: .getFinancialBalanceTypeCode()
306: + balance.getAccountNumber());
307:
308: originEntry.setProjectCode(KFSConstants
309: .getDashProjectCode());
310: originEntry
311: .setUniversityFiscalPeriodCode(KFSConstants.PERIOD_CODE_CG_BEGINNING_BALANCE);
312:
313: KualiDecimal transactionAmount = balance
314: .getAccountLineAnnualBalanceAmount();
315: transactionAmount = transactionAmount.add(balance
316: .getContractsGrantsBeginningBalanceAmount());
317:
318: originEntry
319: .setTransactionLedgerEntryAmount(transactionAmount
320: .abs());
321: originEntry.setTransactionDebitCreditCode(DebitCreditUtil
322: .getDebitCreditCode(transactionAmount, false));
323:
324: originEntry.setTransactionLedgerEntrySequenceNumber(null);
325: originEntry.setTransactionTotalHours(BigDecimal.ZERO);
326: originEntry.setTransactionDate(postingDate);
327:
328: laborOriginEntryService.save(originEntry);
329: } catch (Exception e) {
330: LOG.error(e);
331: }
332: }
333:
334: /**
335: * get the fund group codes that are acceptable by year-end process
336: *
337: * @return the fund group codes that are acceptable by year-end process
338: */
339: private List<String> getFundGroupProcessed() {
340: return parameterService.getParameterValues(
341: LaborYearEndBalanceForwardStep.class,
342: YearEnd.FUND_GROUP_PROCESSED);
343: }
344:
345: /**
346: * get the fund group codes that are acceptable by year-end process
347: *
348: * @return the fund group codes that are acceptable by year-end process
349: */
350: private List<String> getSubFundGroupProcessed() {
351: return parameterService.getParameterValues(
352: LaborYearEndBalanceForwardStep.class,
353: YearEnd.SUB_FUND_GROUP_PROCESSED);
354: }
355:
356: /**
357: * get the balance type codes that are acceptable by year-end process
358: *
359: * @return the balance type codes that are acceptable by year-end process
360: */
361: private List<String> getProcessableBalanceTypeCode(Options options) {
362: List<String> processableBalanceTypeCodes = new ArrayList<String>();
363: processableBalanceTypeCodes.add(options
364: .getActualFinancialBalanceTypeCd());
365: return processableBalanceTypeCodes;
366: }
367:
368: /**
369: * get the object type codes that are acceptable by year-end process
370: *
371: * @param options the given system options
372: * @return the object type codes that are acceptable by year-end process
373: */
374: private List<String> getProcessableObjectTypeCodes(Options options) {
375: List<String> processableObjectTypeCodes = new ArrayList<String>();
376:
377: processableObjectTypeCodes.add(options
378: .getFinObjTypeExpenditureexpCd());
379: processableObjectTypeCodes.add(options
380: .getFinObjTypeExpNotExpendCode());
381:
382: return processableObjectTypeCodes;
383: }
384:
385: /**
386: * get the document type code of the transaction posted by year-end process
387: *
388: * @return the document type code of the transaction posted by year-end process
389: */
390: private String getDocumentTypeCode() {
391: return parameterService.getParameterValue(
392: ParameterConstants.GENERAL_LEDGER_BATCH.class,
393: GLConstants.ANNUAL_CLOSING_DOCUMENT_TYPE);
394: }
395:
396: /**
397: * get the origination code of the transaction posted by year-end process
398: *
399: * @return the origination code of the transaction posted by year-end process
400: */
401: private String getOriginationCode() {
402: return parameterService.getParameterValue(
403: LaborYearEndBalanceForwardStep.class,
404: YearEnd.ORIGINATION_CODE);
405: }
406:
407: /**
408: * get the description of the transaction posted by year-end process
409: *
410: * @return the description of the transaction posted by year-end process
411: */
412: private String getDescription() {
413: return SpringContext
414: .getBean(KualiConfigurationService.class)
415: .getPropertyString(
416: LaborKeyConstants.MESSAGE_YEAR_END_TRANSACTION_DESCRIPTON);
417: }
418:
419: /**
420: * Sets the businessObjectService attribute value.
421: *
422: * @param businessObjectService The businessObjectService to set.
423: */
424: public void setBusinessObjectService(
425: BusinessObjectService businessObjectService) {
426: this .businessObjectService = businessObjectService;
427: }
428:
429: /**
430: * Sets the dateTimeService attribute value.
431: *
432: * @param dateTimeService The dateTimeService to set.
433: */
434: public void setDateTimeService(DateTimeService dateTimeService) {
435: this .dateTimeService = dateTimeService;
436: }
437:
438: public void setParameterService(ParameterService parameterService) {
439: this .parameterService = parameterService;
440: }
441:
442: /**
443: * Sets the laborLedgerBalanceService attribute value.
444: *
445: * @param laborLedgerBalanceService The laborLedgerBalanceService to set.
446: */
447: public void setLaborLedgerBalanceService(
448: LaborLedgerBalanceService laborLedgerBalanceService) {
449: this .laborLedgerBalanceService = laborLedgerBalanceService;
450: }
451:
452: /**
453: * Sets the optionsService attribute value.
454: *
455: * @param optionsService The optionsService to set.
456: */
457: public void setOptionsService(OptionsService optionsService) {
458: this .optionsService = optionsService;
459: }
460:
461: /**
462: * Sets the originEntryGroupService attribute value.
463: *
464: * @param originEntryGroupService The originEntryGroupService to set.
465: */
466: public void setOriginEntryGroupService(
467: OriginEntryGroupService originEntryGroupService) {
468: this .originEntryGroupService = originEntryGroupService;
469: }
470:
471: /**
472: * Sets the laborReportService attribute value.
473: *
474: * @param laborReportService The laborReportService to set.
475: */
476: public void setLaborReportService(
477: LaborReportService laborReportService) {
478: this .laborReportService = laborReportService;
479: }
480:
481: /**
482: * Sets the laborOriginEntryService attribute value.
483: *
484: * @param laborOriginEntryService The laborOriginEntryService to set.
485: */
486: public void setLaborOriginEntryService(
487: LaborOriginEntryService laborOriginEntryService) {
488: this.laborOriginEntryService = laborOriginEntryService;
489: }
490: }
|