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.batch.dataaccess.impl;
017
018 import java.lang.reflect.InvocationTargetException;
019 import java.sql.Date;
020 import java.util.HashMap;
021 import java.util.HashSet;
022 import java.util.Iterator;
023
024 import org.apache.commons.beanutils.PropertyUtils;
025 import org.apache.log4j.Logger;
026 import org.apache.ojb.broker.query.Criteria;
027 import org.apache.ojb.broker.query.QueryByCriteria;
028 import org.apache.ojb.broker.query.ReportQueryByCriteria;
029 import org.kuali.kfs.coa.businessobject.Account;
030 import org.kuali.kfs.coa.businessobject.AccountingPeriod;
031 import org.kuali.kfs.coa.businessobject.SubFundGroup;
032 import org.kuali.kfs.module.bc.BCConstants;
033 import org.kuali.kfs.module.bc.batch.dataaccess.GeneralLedgerBudgetLoadDao;
034 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionHeader;
035 import org.kuali.kfs.module.bc.businessobject.BudgetConstructionMonthly;
036 import org.kuali.kfs.module.bc.businessobject.PendingBudgetConstructionGeneralLedger;
037 import org.kuali.kfs.sys.KFSConstants;
038 import org.kuali.kfs.sys.KFSPropertyConstants;
039 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
040 import org.kuali.kfs.sys.service.HomeOriginationService;
041 import org.kuali.rice.kns.service.DateTimeService;
042 import org.kuali.rice.kns.util.KualiInteger;
043
044 public class GeneralLedgerBudgetLoadDaoOjb extends BudgetConstructionBatchHelperDaoOjb implements GeneralLedgerBudgetLoadDao {
045
046 /* turn on the logger for the persistence broker */
047 private static Logger LOG = org.apache.log4j.Logger.getLogger(GeneralLedgerBudgetLoadDaoOjb.class);
048
049 private DateTimeService dateTimeService;
050 private HomeOriginationService homeOriginationService;
051
052 /*
053 * see GeneralLedgerBudgetLoadDao.LoadGeneralLedgerFromBudget
054 */
055 public void loadGeneralLedgerFromBudget(Integer fiscalYear) {
056 /**
057 * this method calls a series of steps that load the general ledger from the budget into the general ledger pending entry
058 * table. this method takes a fiscal year as input, but all that is required is that this object be a key labeling the
059 * bduget construction general ledger rows for the budget period to be loaded. it need not be an actual fiscal year.
060 */
061 //
062 // set up the global variables
063 // this is a single object that can be passed to all methods that need it, to make the code "thread safe"
064 // (1) the fiscal year to load
065 // (2) the initial sequence numbers for each document to be loaded
066 // (3) the run date (which will be the transaction date)
067 // (4) the "origination code", which comes from the database
068 DaoGlobalVariables daoGlobalVariables = new DaoGlobalVariables(fiscalYear);
069 /**
070 * initiliaze the counter variables
071 */
072 DiagnosticCounters diagnosticCounters = new DiagnosticCounters();
073 /**
074 * make sure all the accounting periods for the load year are open, so the entry lines we create can be posted
075 */
076 openAllAccountingPeriods(fiscalYear);
077 /**
078 * process pending budget construction general ledger rows
079 */
080 loadPendingBudgetConstructionGeneralLedger(daoGlobalVariables, diagnosticCounters);
081 /**
082 * process budget construction monthly budget rows
083 */
084 loadBudgetConstructionMonthlyBudget(daoGlobalVariables, diagnosticCounters);
085 // write out the counts for verification
086 diagnosticCounters.writeDiagnosticCounters();
087 }
088
089 /*******************************************************************************************************************************
090 * methods to do the actual load *
091 ******************************************************************************************************************************/
092
093 /**
094 * build a hashmap containing the next entry sequence number to use for each document (document number) to be loaded from budget
095 * construction to the general ledger
096 *
097 * @param target fiscal year for the budget load
098 * @return HashMapap keyed on document number containing the next entry sequence number to use for the key
099 */
100
101 protected HashMap<String, Integer> entrySequenceNumber(Integer requestYear) {
102 HashMap<String, Integer> nextEntrySequenceNumber;
103 // set up the query: each distinct document number in the source load table
104 Criteria criteriaID = new Criteria();
105 criteriaID.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, requestYear);
106 ReportQueryByCriteria queryID = new ReportQueryByCriteria(BudgetConstructionHeader.class, criteriaID);
107 queryID.setAttributes(new String[] { KFSPropertyConstants.DOCUMENT_NUMBER });
108
109 nextEntrySequenceNumber = new HashMap<String, Integer>(hashCapacity(queryID));
110
111 // OK. build the hash map
112 // there are NO entries for these documents yet, so we initialize the entry sequence number to 0
113 Iterator documentNumbersToLoad = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(queryID);
114 while (documentNumbersToLoad.hasNext()) {
115 Object[] resultRow = (Object[]) documentNumbersToLoad.next();
116 nextEntrySequenceNumber.put((String) resultRow[0], new Integer(0));
117 }
118
119 return nextEntrySequenceNumber;
120 }
121
122 /**
123 * This method creates a new generalLedgerPendingEntry object and initializes it with the default settings for the budget
124 * construction general ledger load.
125 *
126 * @param requestYear
127 * @param financialSystemOriginationCode
128 * @return intiliazed GeneralLedgerPendingEntry business object
129 */
130
131 protected GeneralLedgerPendingEntry getNewPendingEntryWithDefaults(DaoGlobalVariables daoGlobalVariables) {
132 GeneralLedgerPendingEntry newRow = new GeneralLedgerPendingEntry();
133 newRow.setUniversityFiscalYear(daoGlobalVariables.getRequestYear());
134 newRow.setTransactionLedgerEntryDescription(BCConstants.BC_TRN_LDGR_ENTR_DESC);
135 newRow.setFinancialDocumentTypeCode(BCConstants.BUDGET_CONSTRUCTION_BEGINNING_BALANCE_DOCUMENT_TYPE);
136 newRow.setFinancialDocumentApprovedCode(KFSConstants.PENDING_ENTRY_APPROVED_STATUS_CODE.APPROVED);
137 newRow.setTransactionDate(daoGlobalVariables.getTransactionDate());
138 newRow.setTransactionEntryOffsetIndicator(false);
139 newRow.setFinancialSystemOriginationCode(daoGlobalVariables.getFinancialSystemOriginationcode());
140 // the fields below are set to null
141 newRow.setOrganizationDocumentNumber(null);
142 newRow.setProjectCode(null);
143 newRow.setOrganizationReferenceId(null);
144 newRow.setReferenceFinancialDocumentTypeCode(null);
145 newRow.setReferenceOriginationCode(null);
146 newRow.setReferenceFinancialDocumentNumber(null);
147 newRow.setFinancialDocumentReversalDate(null);
148 newRow.setTransactionEncumbranceUpdateCode(null);
149 newRow.setAcctSufficientFundsFinObjCd(null);
150 newRow.setTransactionDebitCreditCode(null);
151 newRow.setTransactionEntryProcessedTs(null);
152 return newRow;
153 }
154
155 protected void loadBudgetConstructionMonthlyBudget(DaoGlobalVariables daoGlobalVariables, DiagnosticCounters diagnosticCounters) {
156 QueryByCriteria queryID = queryForBudgetConstructionMonthly(daoGlobalVariables.getRequestYear());
157 Iterator<BudgetConstructionMonthly> monthlyBudgetRows = getPersistenceBrokerTemplate().getIteratorByQuery(queryID);
158 while (monthlyBudgetRows.hasNext()) {
159 BudgetConstructionMonthly monthlyBudgetIn = monthlyBudgetRows.next();
160 diagnosticCounters.increaseBudgetConstructionMonthlyBudgetRead();
161 if (daoGlobalVariables.shouldThisAccountLoad(monthlyBudgetIn.getAccountNumber() + monthlyBudgetIn.getChartOfAccountsCode())) {
162 GeneralLedgerPendingEntry newRow = getNewPendingEntryWithDefaults(daoGlobalVariables);
163 writeGeneralLedgerPendingEntryFromMonthly(newRow, monthlyBudgetIn, daoGlobalVariables, diagnosticCounters);
164 }
165 else {
166 diagnosticCounters.increaseBudgetConstructionMonthlyBudgetSkipped();
167 }
168 }
169 }
170
171 /**
172 * This method loads all the eligible pending budget construction general ledger rows
173 *
174 * @param daoGlobalVariables
175 * @param diagnosticCounters
176 */
177 protected void loadPendingBudgetConstructionGeneralLedger(DaoGlobalVariables daoGlobalVariables, DiagnosticCounters diagnosticCounters) {
178 QueryByCriteria queryID = queryForPendingBudgetConstructionGeneralLedger(daoGlobalVariables.getRequestYear());
179 Iterator<PendingBudgetConstructionGeneralLedger> pbglRows = getPersistenceBrokerTemplate().getIteratorByQuery(queryID);
180 while (pbglRows.hasNext()) {
181 PendingBudgetConstructionGeneralLedger pbglIn = pbglRows.next();
182 diagnosticCounters.increaseBudgetConstructionPendingGeneralLedgerRead();
183 if (daoGlobalVariables.shouldThisAccountLoad(pbglIn.getAccountNumber() + pbglIn.getChartOfAccountsCode())) {
184 GeneralLedgerPendingEntry newRow = getNewPendingEntryWithDefaults(daoGlobalVariables);
185 writeGeneralLedgerPendingEntryFromAnnual(newRow, pbglIn, daoGlobalVariables, diagnosticCounters);
186 }
187 else {
188 diagnosticCounters.increaseBudgetConstructionPendingGeneralLedgerSkipped();
189 }
190 }
191 }
192
193 /**
194 * This method builds the query to fetch the monthly budget general ledger lines to be loaded
195 *
196 * @param fiscalYear : the year to be loaded
197 * @return query for fetching monthly budget rows
198 */
199 protected QueryByCriteria queryForBudgetConstructionMonthly(Integer fiscalYear) {
200 // we only select rows which have non-zero budget amounts
201 // on this object, proxy=true, so we can do a regular query for a business object instead of a report query
202 Criteria criteriaID = new Criteria();
203 criteriaID.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, fiscalYear);
204 // we want to test for at least one non-zero monthly amount
205 Criteria orCriteriaID = new Criteria();
206 Iterator<String[]> monthlyPeriods = BCConstants.BC_MONTHLY_AMOUNTS.iterator();
207 while (monthlyPeriods.hasNext()) {
208 // the first array element is the amount field name (the second is the corresponding accounting period)
209 String monthlyAmountName = monthlyPeriods.next()[0];
210 Criteria amountCriteria = new Criteria();
211 amountCriteria.addNotEqualTo(monthlyAmountName, new KualiInteger(0));
212 orCriteriaID.addOrCriteria(amountCriteria);
213 }
214 criteriaID.addAndCriteria(orCriteriaID);
215 QueryByCriteria queryID = new QueryByCriteria(BudgetConstructionMonthly.class, criteriaID);
216 return queryID;
217 }
218
219 /**
220 * This method builds the query to fetch the pending budget construction general ledger rows to be loaded
221 *
222 * @param fiscalYear: the year to be loaded
223 * @return query for fetching pending budget construction GL rows
224 */
225
226 protected QueryByCriteria queryForPendingBudgetConstructionGeneralLedger(Integer fiscalYear) {
227 // we only select rows which have non-zero budget amounts
228 // on this object, proxy=true, so we can do a regular query for a business object instead of a report query
229 Criteria criteriaID = new Criteria();
230 criteriaID.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, fiscalYear);
231 criteriaID.addNotEqualTo(KFSPropertyConstants.ACCOUNT_LINE_ANNUAL_BALANCE_AMOUNT, new KualiInteger(0));
232 QueryByCriteria queryID = new QueryByCriteria(PendingBudgetConstructionGeneralLedger.class, criteriaID);
233 return queryID;
234 }
235
236 /**
237 * complete the pending entry row based on the data returned from the DB store it to the DB
238 *
239 * @param newRow
240 * @param source annual budget construction GL row
241 * @param object containing global constants
242 */
243 protected void writeGeneralLedgerPendingEntryFromAnnual(GeneralLedgerPendingEntry newRow, PendingBudgetConstructionGeneralLedger pbgl, DaoGlobalVariables daoGlobalVariables, DiagnosticCounters diagnosticCounters) {
244 /**
245 * first get the document number
246 */
247 String incomingDocumentNumber = pbgl.getDocumentNumber();
248 /**
249 * write a base budget row
250 */
251 newRow.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_BASE_BUDGET);
252 newRow.setUniversityFiscalPeriodCode(KFSConstants.PERIOD_CODE_BEGINNING_BALANCE);
253 /**
254 * set the variable fields
255 */
256 newRow.setTransactionLedgerEntrySequenceNumber(daoGlobalVariables.getNextSequenceNumber(incomingDocumentNumber));
257 newRow.setDocumentNumber(incomingDocumentNumber); // document number
258 newRow.setChartOfAccountsCode(pbgl.getChartOfAccountsCode()); // chart of accounts
259 newRow.setAccountNumber(pbgl.getAccountNumber()); // account number
260 newRow.setSubAccountNumber(pbgl.getSubAccountNumber()); // sub account number
261 newRow.setFinancialObjectCode(pbgl.getFinancialObjectCode()); // object code
262 newRow.setFinancialSubObjectCode(pbgl.getFinancialSubObjectCode()); // sub object code
263 newRow.setFinancialObjectTypeCode(pbgl.getFinancialObjectTypeCode()); // object type code
264 /**
265 * the budget works with whole numbers--we must convert to decimal for the general ledger
266 */
267 newRow.setTransactionLedgerEntryAmount(pbgl.getAccountLineAnnualBalanceAmount().kualiDecimalValue());
268 /**
269 * now we store the base budget value
270 */
271 getPersistenceBrokerTemplate().store(newRow);
272 diagnosticCounters.increaseGeneralLedgerBaseBudgetWritten();
273 /**
274 * the same row needs to be written as a current budget item we change only the balance type and the sequence number
275 */
276 newRow.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_CURRENT_BUDGET);
277 newRow.setTransactionLedgerEntrySequenceNumber(daoGlobalVariables.getNextSequenceNumber(incomingDocumentNumber));
278 /**
279 * store the current budget value
280 */
281 getPersistenceBrokerTemplate().store(newRow);
282 diagnosticCounters.increasGenneralLedgerCurrentBudgetWritten();
283 }
284
285 protected void writeGeneralLedgerPendingEntryFromMonthly(GeneralLedgerPendingEntry newRow, BudgetConstructionMonthly pbglMonthly, DaoGlobalVariables daoGlobalVariables, DiagnosticCounters diagnosticCounters) {
286 /**
287 * first get the document number
288 */
289 String incomingDocumentNumber = pbglMonthly.getDocumentNumber();
290 /**
291 * write a base budget row
292 */
293 newRow.setFinancialBalanceTypeCode(KFSConstants.BALANCE_TYPE_MONTHLY_BUDGET);
294 /**
295 * set the variable fields
296 */
297 newRow.setDocumentNumber(incomingDocumentNumber); // document number
298 newRow.setChartOfAccountsCode(pbglMonthly.getChartOfAccountsCode()); // chart of accounts
299 newRow.setAccountNumber(pbglMonthly.getAccountNumber()); // account number
300 newRow.setSubAccountNumber(pbglMonthly.getSubAccountNumber()); // sub account number
301 newRow.setFinancialObjectCode(pbglMonthly.getFinancialObjectCode()); // object code
302 newRow.setFinancialSubObjectCode(pbglMonthly.getFinancialSubObjectCode()); // sub object code
303 newRow.setFinancialObjectTypeCode(pbglMonthly.getFinancialObjectTypeCode()); // object type code
304
305 /**
306 * we have to loop through the monthly array, and write an MB row for each monthly row with a non-zero amount (we do this to
307 * write less code. we hope that the extra hit from reflection won't be too bad)
308 */
309 Iterator<String[]> monthlyPeriodAmounts = BCConstants.BC_MONTHLY_AMOUNTS.iterator();
310 while (monthlyPeriodAmounts.hasNext()) {
311 String[] monthlyPeriodProperties = monthlyPeriodAmounts.next();
312 KualiInteger monthlyAmount;
313 try {
314 monthlyAmount = (KualiInteger) PropertyUtils.getSimpleProperty(pbglMonthly, monthlyPeriodProperties[0]);
315 }
316 catch (IllegalAccessException ex) {
317 LOG.error(String.format("\nunable to use get method to access value of %s in %s\n", monthlyPeriodProperties[0], BudgetConstructionMonthly.class.getName()), ex);
318 diagnosticCounters.writeDiagnosticCounters();
319 throw new RuntimeException(ex);
320 }
321 catch (InvocationTargetException ex) {
322 LOG.error(String.format("\nunable to invoke get method for %s in %s\n", monthlyPeriodProperties[0], BudgetConstructionMonthly.class.getName()), ex);
323 diagnosticCounters.writeDiagnosticCounters();
324 throw new RuntimeException(ex);
325 }
326 catch (NoSuchMethodException ex) {
327 LOG.error(String.format("\nNO get method found for %s in %s ???\n", monthlyPeriodProperties[0], BudgetConstructionMonthly.class.getName()), ex);
328 diagnosticCounters.writeDiagnosticCounters();
329 throw new RuntimeException(ex);
330 }
331 if (!(monthlyAmount.isZero())) {
332 newRow.setTransactionLedgerEntrySequenceNumber(daoGlobalVariables.getNextSequenceNumber(incomingDocumentNumber));
333 newRow.setUniversityFiscalPeriodCode(monthlyPeriodProperties[1]); // accounting period
334 newRow.setTransactionLedgerEntryAmount(monthlyAmount.kualiDecimalValue()); // amount
335 getPersistenceBrokerTemplate().store(newRow);
336 diagnosticCounters.increaseBudgetConstructionMonthlyBudgetWritten();
337 }
338 }
339 }
340
341
342 /*******************************************************************************************************************************
343 * * This section build the list of accounts that SHOULD NOT be loaded to the general ledger * (This may seem strange--why build
344 * a budget if you aren't going to load it--but in the FIS the budget * loaded to payroll as well. For grant accounts, the FIS
345 * allowed people to set salaries for the new year * so those would load to payroll. But, the actual budget for a grant account
346 * was not necessarily done on a * fiscal year basis, and was not part of the university's operating budget, so there was no
347 * "base budget" * for a grant account to load to the general ledger.) * (1) We will inhibit the load to the general ledger of
348 * all accounts in given sub fund groups * (2) (We WILL allow closed accounts to load. There should not be any--they should have
349 * been filtered * out in the budget application, but if there are, they will be caught by the GL scrubber. We want * people to
350 * have a record of this kind of load failure, so it can be corrected. * * *
351 ******************************************************************************************************************************/
352
353 /**
354 * get a list of accounts that should not be loaded from the budget to the General Ledger
355 *
356 * @return hashset of accounts NOT to be loaded
357 */
358
359 protected HashSet<String> getAccountsNotToBeLoaded() {
360 HashSet<String> bannedAccounts;
361 /**
362 * list of subfunds which should not be loaded
363 */
364 HashSet<String> bannedSubFunds = getSubFundsNotToBeLoaded();
365 /**
366 * query for the subfund property for each account in the DB
367 */
368 ReportQueryByCriteria queryID = new ReportQueryByCriteria(Account.class, org.apache.ojb.broker.query.ReportQueryByCriteria.CRITERIA_SELECT_ALL);
369 queryID.setAttributes(new String[] { KFSPropertyConstants.ACCOUNT_NUMBER, KFSPropertyConstants.CHART_OF_ACCOUNTS_CODE, KFSPropertyConstants.SUB_FUND_GROUP_CODE });
370 bannedAccounts = new HashSet<String>(hashCapacity(queryID));
371 /**
372 * use the results to build a hash set of accounts which should NOT be loaded (that is, their subfunds are in the list of
373 * subfunds we do not want
374 */
375 Iterator accountProperties = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(queryID);
376 while (accountProperties.hasNext()) {
377 Object[] selectListValues = (Object[]) accountProperties.next();
378 /**
379 * we will add an account/chart to the list if it has a no-load subfundgroup
380 */
381 if (bannedSubFunds.contains((String) selectListValues[2])) {
382 /**
383 * hash content is account number concatenated with chart (the key of the chart of accounts table)
384 */
385 bannedAccounts.add(((String) selectListValues[0]) + ((String) selectListValues[1]));
386 }
387 }
388 return bannedAccounts;
389 }
390
391 /**
392 * build a hash set of subfunds whose accounts should NOT be loaded this can be done by either a list of FUND groups and/or a
393 * list of subfund groups
394 *
395 * @see org.kuali.kfs.module.bc.BCConstants to initialize the String[] array(s) as desired
396 * @return list of subfunds whose accounts will NOT be loaded
397 */
398 protected HashSet<String> getSubFundsNotToBeLoaded() {
399 HashSet<String> bannedSubFunds;
400 if (BCConstants.NO_BC_GL_LOAD_FUND_GROUPS.size() != 0) {
401 /**
402 * look for subfunds in the banned fund groups
403 */
404 Criteria criteriaID = new Criteria();
405 criteriaID.addIn(KFSPropertyConstants.FUND_GROUP_CODE, BCConstants.NO_BC_GL_LOAD_FUND_GROUPS);
406 ReportQueryByCriteria queryID = new ReportQueryByCriteria(SubFundGroup.class, criteriaID);
407 queryID.setAttributes(new String[] { KFSPropertyConstants.SUB_FUND_GROUP_CODE });
408 /**
409 * set the size of the hashset based on the number of rows the query will return
410 */
411 bannedSubFunds = new HashSet<String>(hashCapacity(queryID) + BCConstants.NO_BC_GL_LOAD_SUBFUND_GROUPS.size());
412 Iterator subfundsForBannedFunds = getPersistenceBrokerTemplate().getReportQueryIteratorByQuery(queryID);
413 /**
414 * add the subfunds for the fund groups to be skipped to the hash set
415 */
416 while (subfundsForBannedFunds.hasNext()) {
417 bannedSubFunds.add((String) ((Object[]) subfundsForBannedFunds.next())[0]);
418 }
419 }
420 else {
421 bannedSubFunds = new HashSet<String>(BCConstants.NO_BC_GL_LOAD_SUBFUND_GROUPS.size() + 1);
422 }
423 /**
424 * now add the specific sub funds we don't want from the hard-coded array in BCConstants to the hash set
425 */
426 Iterator<String> additionalBannedSubFunds = BCConstants.NO_BC_GL_LOAD_SUBFUND_GROUPS.iterator();
427 while (additionalBannedSubFunds.hasNext()) {
428 bannedSubFunds.add(additionalBannedSubFunds.next());
429 }
430 return bannedSubFunds;
431 }
432
433 /*******************************************************************************************************************************
434 * This section sets all the accounting periods for the coming year to open. * The monthly budget will load by accounting
435 * period. If some are not open, some monthly rows will error * out in the scrubber. Current FIS procedure is to prevent this
436 * from happening, by opening all the * accounting periods and letting the university chart manager close them after the budget
437 * is loaded if that * is desirable for some reason. If an institution prefers another policy, just don't call these methods. *
438 * But, even if we let the scrubber fail, there will be no way to load the monthly rows from the error tables* unless the
439 * corresponding accounting periods are open. *
440 ******************************************************************************************************************************/
441
442 /**
443 * this method makes sure all accounting periods inn the target fiscal year are open
444 *
445 * @param request fiscal year (or other fiscal period) which is the TARGET of the load
446 */
447 protected void openAllAccountingPeriods(Integer requestYear) {
448 Criteria criteriaID = new Criteria();
449 criteriaID.addEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR, requestYear);
450 criteriaID.addNotEqualTo(KFSPropertyConstants.UNIVERSITY_FISCAL_PERIOD_STATUS_CODE, "Y");
451 QueryByCriteria queryID = new QueryByCriteria(AccountingPeriod.class, criteriaID);
452 Iterator<AccountingPeriod> unopenPeriods = getPersistenceBrokerTemplate().getIteratorByQuery(queryID);
453 int periodsOpened = 0;
454 while (unopenPeriods.hasNext()) {
455 AccountingPeriod periodToOpen = unopenPeriods.next();
456 periodToOpen.setActive(true);
457 getPersistenceBrokerTemplate().store(periodToOpen);
458 periodsOpened = periodsOpened + 1;
459 }
460 LOG.warn(String.format("\n\naccounting periods for %d changed to open status: %d", requestYear, new Integer(periodsOpened)));
461 }
462
463 /*******************************************************************************************************************************
464 * These two classes are containers so we can make certain variables accessible to all methods without making them global to the *
465 * outer class and without cluttering up the method signatures. *
466 ******************************************************************************************************************************/
467
468 /**
469 * This class keeps a set of counters and provides a method to print them out This allows us to set up thread-local counters in
470 * the unlikely event this code is run by more than one thread
471 */
472 protected class DiagnosticCounters {
473 long budgetConstructionPendingGeneralLedgerRead = 0;
474 long budgetConstructionPendingGeneralLedgerSkipped = 0;
475 long generalLedgerBaseBudgetWritten = 0;
476 long generalLedgerCurrentBudgetWritten = 0;
477
478 long budgetConstructionMonthlyBudgetRead = 0;
479 long budgetConstructionMonthlyBudgetSkipped = 0;
480 long budgetConstructionMonthlyBudgetWritten = 0;
481
482 public void increaseBudgetConstructionPendingGeneralLedgerRead() {
483 budgetConstructionPendingGeneralLedgerRead++;
484 }
485
486 public void increaseBudgetConstructionPendingGeneralLedgerSkipped() {
487 budgetConstructionPendingGeneralLedgerSkipped++;
488 }
489
490 public void increaseGeneralLedgerBaseBudgetWritten() {
491 generalLedgerBaseBudgetWritten++;
492 }
493
494 public void increasGenneralLedgerCurrentBudgetWritten() {
495 generalLedgerCurrentBudgetWritten++;
496 }
497
498 public void increaseBudgetConstructionMonthlyBudgetRead() {
499 budgetConstructionMonthlyBudgetRead++;
500 }
501
502 public void increaseBudgetConstructionMonthlyBudgetSkipped() {
503 budgetConstructionMonthlyBudgetSkipped++;
504 }
505
506 public void increaseBudgetConstructionMonthlyBudgetWritten() {
507 budgetConstructionMonthlyBudgetWritten++;
508 }
509
510 public void writeDiagnosticCounters() {
511 LOG.warn(String.format("\n\nPending Budget Construction General Ledger Load\n"));
512 LOG.warn(String.format("\n pending budget construction GL rows read: %,d", budgetConstructionPendingGeneralLedgerRead));
513 LOG.warn(String.format("\n pending budget construction GL rows skipped: %,d", budgetConstructionPendingGeneralLedgerSkipped));
514 LOG.warn(String.format("\n\n base budget rows written: %,d", generalLedgerBaseBudgetWritten));
515 LOG.warn(String.format("\n current budget rows written: %,d", generalLedgerCurrentBudgetWritten));
516 LOG.warn(String.format("\n\n pending budget construction monthly rows read: %,d", budgetConstructionMonthlyBudgetRead));
517 LOG.warn(String.format("\n pending budget construction monthly rows skipped: %,d", budgetConstructionMonthlyBudgetSkipped));
518 LOG.warn(String.format("\n pending budget construction monthly rows written: %,d", budgetConstructionMonthlyBudgetWritten));
519 }
520 }
521
522 /**
523 * This class allows us to create global variables and pass them around. This should make the code thread safe, in the unlikely
524 * event it is called by more than one thread. it also allows us to fetch constants and build datas stuctures from the DB once
525 * upon instantiation of this class, and make them available for the duration of the run
526 *
527 * @param requestYear
528 * @param <documentNumber, ledger sequence number> HashMap
529 * @param current SQL Date (which will be the transaction date in the general ledger entry rows we create)
530 * @param the "financial system Origination Code" for this database
531 */
532 protected class DaoGlobalVariables {
533 private Integer requestYear;
534 private HashMap<String, Integer> entrySequenceNumber;
535 private Date transactionDate;
536 private String financialSystemOriginationCode;
537 private HashSet<String> accountsNotToBeLoaded;
538
539 public DaoGlobalVariables(Integer requestYear) {
540 this.requestYear = requestYear;
541 this.entrySequenceNumber = entrySequenceNumber(requestYear);
542 // this.transactionDate = SpringContext.getBean(DateTimeService.class).getCurrentSqlDate();
543 this.transactionDate = dateTimeService.getCurrentSqlDate();
544 this.financialSystemOriginationCode = homeOriginationService.getHomeOrigination().getFinSystemHomeOriginationCode();
545 this.accountsNotToBeLoaded = getAccountsNotToBeLoaded();
546 }
547
548 public Integer getRequestYear() {
549 return this.requestYear;
550 }
551
552 /**
553 * return the next available sequence number for the input key and update "next available"
554 */
555 public Integer getNextSequenceNumber(String seqKey) {
556 Integer newSeqNumber = entrySequenceNumber.get(seqKey);
557 entrySequenceNumber.put(seqKey, new Integer(newSeqNumber.intValue() + 1));
558 return newSeqNumber;
559 }
560
561 public Date getTransactionDate() {
562 return this.transactionDate;
563 }
564
565 public String getFinancialSystemOriginationcode() {
566 return this.financialSystemOriginationCode;
567 }
568
569 public boolean shouldThisAccountLoad(String accountAndChart) {
570 return (!accountsNotToBeLoaded.contains(accountAndChart));
571 }
572 }
573
574 public void setDateTimeService(DateTimeService dateTimeService) {
575 this.dateTimeService = dateTimeService;
576 }
577
578 public void setHomeOriginationService(HomeOriginationService homeOriginationService) {
579 this.homeOriginationService = homeOriginationService;
580 }
581
582 }