/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.gl.batch.service.impl;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import org.kuali.kfs.gl.GeneralLedgerConstants;
import org.kuali.kfs.gl.batch.PosterBalancingStep;
import org.kuali.kfs.gl.businessobject.AccountBalance;
import org.kuali.kfs.gl.businessobject.AccountBalanceHistory;
import org.kuali.kfs.gl.businessobject.Balance;
import org.kuali.kfs.gl.businessobject.BalanceHistory;
import org.kuali.kfs.gl.businessobject.Encumbrance;
import org.kuali.kfs.gl.businessobject.EncumbranceHistory;
import org.kuali.kfs.gl.businessobject.Entry;
import org.kuali.kfs.gl.businessobject.EntryHistory;
import org.kuali.kfs.gl.dataaccess.AccountBalanceDao;
import org.kuali.kfs.gl.dataaccess.BalancingDao;
import org.kuali.kfs.gl.dataaccess.EncumbranceDao;
import org.kuali.kfs.gl.dataaccess.LedgerBalancingDao;
import org.kuali.kfs.gl.dataaccess.LedgerEntryHistoryBalancingDao;
import org.kuali.kfs.sys.ConfigureContext;
import org.kuali.kfs.sys.batch.BatchDirectoryHelper;
import org.kuali.kfs.sys.batch.BatchSpringContext;
import org.kuali.kfs.sys.batch.Step;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.sys.context.TestUtils;
import org.kuali.rice.krad.service.BusinessObjectService;
/**
* GL BalancingServiceImpl test cases
*/
@ConfigureContext
public class BalancingServiceImplTest extends BalancingServiceImplTestBase {
private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BalancingServiceImplTest.class);
protected BalancingDao balancingDao;
protected AccountBalanceDao accountBalanceDao;
protected EncumbranceDao encumbranceDao;
private BatchDirectoryHelper batchDirectoryHelper;
@Override
protected void setUp() throws Exception {
balancingService = (BalancingServiceBaseImpl<Entry, Balance>) TestUtils.getUnproxiedService("glBalancingService");
ledgerEntryHistoryBalancingDao = (LedgerEntryHistoryBalancingDao) SpringContext.getService("glEntryHistoryDao");
ledgerBalancingDao = (LedgerBalancingDao) SpringContext.getService("glLedgerBalancingDao");
balancingDao = (BalancingDao) SpringContext.getService("glBalancingDao");
accountBalanceDao = SpringContext.getBean(AccountBalanceDao.class);
encumbranceDao = SpringContext.getBean(EncumbranceDao.class);
businessObjectService = SpringContext.getBean(BusinessObjectService.class);
// Delete all data so that balancing has an empty table set to work with
Map<String, Object> fieldValues = new HashMap<String, Object>();
businessObjectService.deleteMatching(Entry.class, fieldValues);
businessObjectService.deleteMatching(Balance.class, fieldValues);
businessObjectService.deleteMatching(Encumbrance.class, fieldValues);
businessObjectService.deleteMatching(AccountBalance.class, fieldValues);
businessObjectService.deleteMatching(EntryHistory.class, fieldValues);
businessObjectService.deleteMatching(BalanceHistory.class, fieldValues);
businessObjectService.deleteMatching(EncumbranceHistory.class, fieldValues);
businessObjectService.deleteMatching(AccountBalanceHistory.class, fieldValues);
// Because KULDBA doesn't support FYs more then 1 year back we need to limit our range in order to properly test boundary cases
TestUtils.setSystemParameter(PosterBalancingStep.class, GeneralLedgerConstants.Balancing.NUMBER_OF_PAST_FISCAL_YEARS_TO_INCLUDE, "0");
// make sure originEntry directory exists
batchDirectoryHelper = new BatchDirectoryHelper("gl","originEntry");
batchDirectoryHelper.createBatchDirectory();
// careful: super.setUp needs to happen at the end because of service initialization and NUMBER_OF_PAST_FISCAL_YEARS_TO_INCLUDE
super.setUp();
}
// remove the origin entry directory if we created it
@Override
public void tearDown() throws Exception {
super.tearDown();
batchDirectoryHelper.removeBatchDirectory();
}
@Override
public void testRunBalancingPopulateData() {
LOG.debug("No data present scenario, hence process should populate data");
// First confirm tables are empty. If this fails then the test scenario is incorrectly set up
assertEquals(0, getLedgerEntryBalancingDao().findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(0, getLedgerBalanceBalancingDao().findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(0, accountBalanceDao.findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(0, encumbranceDao.findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(0, this.getHistoryCount(null, EntryHistory.class));
assertEquals(0, this.getHistoryCount(null, BalanceHistory.class));
assertEquals(0, this.getHistoryCount(null, AccountBalanceHistory.class));
assertEquals(0, this.getHistoryCount(null, EncumbranceHistory.class));
// Generate some data and check that poster operated as expected. If this fails then the test scenario is incorrectly set up
this.postTestCaseEntries(INPUT_TRANSACTIONS);
assertEquals(12, getLedgerEntryBalancingDao().findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(7, getLedgerBalanceBalancingDao().findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(5, accountBalanceDao.findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(2, encumbranceDao.findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
// Balancing should succeed successfully since this is an expected use case where it does an initial population of history tables
assertTrue(balancingService.runBalancing());
// Once it ran, we expect data in balancing tables. This data is per INPUT_TRANSACTIONS data structure
assertEquals(12, ledgerEntryHistoryBalancingDao.findSumRowCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(9, this.getHistoryCount(null, EntryHistory.class));
assertEquals(7, this.getHistoryCount(null, BalanceHistory.class));
assertEquals(5, this.getHistoryCount(null, AccountBalanceHistory.class));
assertEquals(2, this.getHistoryCount(null, EncumbranceHistory.class));
// Finally make sure there wasn't any comparison failure. We do this by running comparison methods directly (again). Should pass
// since we just populated the history tables this should hold true
this.assertCompareHistorySuccess();
}
@Override
public void testRunBalancingDeleteObsoleteUniversityFiscalYearData() {
// Run the poster to pick up the last two entries which are out of range
this.postTestCaseEntries(INPUT_TRANSACTIONS);
// Manually populate our history tables and force entries to be picked up. This essentially does the same as testRunBalancingPopulateData
assertTrue("Populate should have copied some data", 0 != ledgerBalancingDao.populateLedgerEntryHistory(obsoleteUniversityFiscalYear));
assertTrue("Populate should have copied some data", 0 != ledgerBalancingDao.populateLedgerBalanceHistory(obsoleteUniversityFiscalYear));
assertTrue("Populate should have copied some data", 0 != balancingDao.populateAccountBalancesHistory(obsoleteUniversityFiscalYear));
assertTrue("Populate should have copied some data", 0 != balancingDao.populateEncumbranceHistory(obsoleteUniversityFiscalYear));
// Pretty silly at this point, but lets double check that it copied the entries
assertTrue("Found no EntryHistory", 0 != this.getHistoryCount(obsoleteUniversityFiscalYear, EntryHistory.class));
assertTrue("Found no BalanceHistory", 0 != this.getHistoryCount(obsoleteUniversityFiscalYear, BalanceHistory.class));
assertTrue("Found no AccountBalanceHistory", 0 != this.getHistoryCount(obsoleteUniversityFiscalYear, AccountBalanceHistory.class));
assertTrue("Found no EncumbranceHistory", 0 != this.getHistoryCount(obsoleteUniversityFiscalYear, EncumbranceHistory.class));
// Run Balancing, it should hit the case that deletes the obsolete entries. Coincidentally: This will also ignore the two out of range entries in
// INPUT_TRANSACTIONS (the last two) but we're not actively testing for that here
assertTrue(balancingService.runBalancing());
// Verify that it deleted the entries
assertEquals(0, this.getHistoryCount(obsoleteUniversityFiscalYear, EntryHistory.class));
assertEquals(0, this.getHistoryCount(obsoleteUniversityFiscalYear, BalanceHistory.class));
assertEquals(0, this.getHistoryCount(obsoleteUniversityFiscalYear, AccountBalanceHistory.class));
assertEquals(0, this.getHistoryCount(obsoleteUniversityFiscalYear, EncumbranceHistory.class));
}
@Override
public void testRunBalancingHistoryUpdate() {
// First pass is exactly the same as testRunBalancingPopulateData. This serves to populate the tables
this.postTestCaseEntries(INPUT_TRANSACTIONS);
assertTrue("Populate should have copied some data", 0 != ledgerBalancingDao.populateLedgerEntryHistory(obsoleteUniversityFiscalYear));
assertTrue("Populate should have copied some data", 0 != ledgerBalancingDao.populateLedgerBalanceHistory(obsoleteUniversityFiscalYear));
assertTrue("Populate should have copied some data", 0 != balancingDao.populateAccountBalancesHistory(obsoleteUniversityFiscalYear));
assertTrue("Populate should have copied some data", 0 != balancingDao.populateEncumbranceHistory(obsoleteUniversityFiscalYear));
try {
// Briefly sleep to ensure that we get unique timestamps on the rename step. This is obsolete since the input files will
// be the same but done to avoid future bugs if there are changes to the test setup
Thread.sleep(1000);
} catch (InterruptedException e) {
fail("No reason that this job should have gotten interrupted.");
}
// Next we post exactly the same entries and verify data exists. Note, now we have more entries
this.postTestCaseEntries(INPUT_TRANSACTIONS);
assertEquals(24, getLedgerEntryBalancingDao().findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(7, getLedgerBalanceBalancingDao().findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(5, accountBalanceDao.findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(2, encumbranceDao.findCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
// And run balancing again. Again, this should succeed
assertTrue(balancingService.runBalancing());
// Once it ran, we expect data in balancing tables, but different this time since the balancing job ran updates
assertEquals(24, ledgerEntryHistoryBalancingDao.findSumRowCountGreaterOrEqualThan(startUniversityFiscalYear).intValue());
assertEquals(9, this.getHistoryCount(null, EntryHistory.class));
assertEquals(7, this.getHistoryCount(null, BalanceHistory.class));
assertEquals(5, this.getHistoryCount(null, AccountBalanceHistory.class));
assertEquals(2, this.getHistoryCount(null, EncumbranceHistory.class));
// Finally make sure there wasn't any comparison failure. We do this by running comparison methods directly (again)
this.assertCompareHistorySuccess();
}
/**
* @see org.kuali.kfs.gl.batch.service.impl.BalancingServiceImplTestBase#postTestCaseEntries(java.lang.String[])
*/
@Override
protected void postTestCaseEntries(String[] inputTransactions) {
// Write test file
TestUtils.writeFile(this.getBatchFileDirectoryName() + File.separator + GeneralLedgerConstants.BatchFileSystem.POSTER_INPUT_FILE + GeneralLedgerConstants.BatchFileSystem.EXTENSION, inputTransactions);
try {
// Run the poster
Step posterEntriesStep = BatchSpringContext.getStep("posterEntriesStep");
assertTrue("posterEntriesStep should have succeeded", posterEntriesStep.execute(getClass().getName(), dateTimeService.getCurrentDate()));
// Rename the file because that's what happens before the balancing job runs
Step fileRenameStep = BatchSpringContext.getStep("fileRenameStep");
assertTrue("fileRenameStep should have succeeded", fileRenameStep.execute(getClass().getName(), dateTimeService.getCurrentDate()));
}
catch (InterruptedException e) {
fail("posterEntriesStep or fileRenameStep failed: " + e.getMessage());
}
}
/**
* @see org.kuali.kfs.gl.batch.service.impl.BalancingServiceImplTestBase#getInputTransactions()
*/
@Override
protected String[] getInputTransactions() {
// These inputTransactions are missing an initial 4 character FY string. It is added in setUp to test Balancing skipping old entries. Also, first 4
// of the following array are in error intentionally.
return new String[] {
"BL1031420----- ---EXEX08PO EP542894 88888Midwest Scientific 50.00D2009-02-09568210 ---------- REQSEP568210 D",
"BL1031420----- ---EXFB08PO EP542894 88888GENERATED OFFSET 50.00C2009-03-25 ---------- ",
"BL1031420----- ---EXEX08PO EP61063 88888SIEMENS MEDICAL SOLUTIONS USA INC. 14331.00D2009-02-0999PC192 ---------- REQSEP57895 D",
"BL1031420----- ---EXFB08PO EP61063 88888GENERATED OFFSET 14331.00C2009-03-25 ---------- ",
"BL1031420-----4100---EXEX08PO EP6797 88888166080043 HPS OFFICE SYSTEMS 579.84D2009-02-09 ---------- D",
"BL1031420-----9892---EXFB08PO EP6797 88888GENERATED OFFSET 579.84C2009-03-25 ---------- ",
"BL1031420-----4617---ACEX08PREQEP926741 88888Young,Bonnie 223.44C2009-02-09 ---------- PO EP528673 ",
"BL1031420-----9041---ACLI08PREQEP926741 88888Young,Bonnie 223.44D2009-02-09 ---------- PO EP528673 ",
"BL1031420-----4300---ACEX08PREQEP934559 88888Post Masters 539.73D2009-02-09 ---------- PO EP409297 ",
"BL1031420-----9041---ACLI08PREQEP934559 88888Post Masters 539.73C2009-02-09 ---------- PO EP409297 ",
"BL1031420-----4300---EXEX08PREQEP934559 88888Post Masters 539.73C2009-02-09 ---------- PO EP409297 R",
"BL1031420-----9892---EXFB08PREQEP934559 88888GENERATED OFFSET 539.73D2009-03-25 ---------- ",
"BL1031420-----4520---ACEX08PREQEP942275 88888ESG SECURITY INC 49.00D2009-02-09BC70226 ---------- PO EP510147 ",
"BL1031420-----9041---ACLI08PREQEP942275 88888ESG SECURITY INC 49.00C2009-02-09BC70226 ---------- PO EP510147 ",
"BL1031420-----4520---ACEX08PREQEP942275 88888ESG SECURITY INC 49.00D2009-02-09BC70226 ---------- PO EP510147 ",
"BL1031420-----9041---ACLI08PREQEP942275 88888ESG SECURITY INC 49.00C2009-02-09BC70226 ---------- PO EP510147 ",
CHART_OF_ACCOUNTS_CODE + "1031420-----" + FINANCIAL_OBJECT_CODE + "---EXEX08PO EP6797 88888166080043 HPS OFFICE SYSTEMS 579.84D2009-02-09 ---------- D",
CHART_OF_ACCOUNTS_CODE + "1031420-----" + FINANCIAL_OBJECT_CODE + "---EXFB08PO EP6797 88888GENERATED OFFSET 579.84C2009-03-25 ---------- ",
};
}
}