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.service.impl;
017    
018    import org.apache.log4j.Logger;
019    import org.kuali.kfs.module.bc.batch.dataaccess.GenesisDao;
020    import org.kuali.kfs.module.bc.batch.service.BudgetConstructionHumanResourcesPayrollInterfaceService;
021    import org.kuali.kfs.module.bc.batch.service.GenesisService;
022    import org.kuali.kfs.sys.KFSConstants;
023    import org.kuali.kfs.sys.KFSConstants.BudgetConstructionConstants;
024    import org.springframework.transaction.annotation.Transactional;
025    
026    import java.util.HashMap;
027    import java.util.Map;
028    
029    @Transactional
030    public class GenesisServiceImpl implements GenesisService {
031    
032        /* settings for common fields for all document headers for budget construction */
033    
034        private GenesisDao genesisDao;
035        private BudgetConstructionHumanResourcesPayrollInterfaceService budgetConstructionHumanResourcesPayrollInterfaceService;
036    
037        private static Logger LOG = org.apache.log4j.Logger.getLogger(GenesisServiceImpl.class);
038    
039        /*
040         * here are some flag value routines
041         */
042    
043        public boolean BatchPositionSynchAllowed(Integer BaseYear) {
044            Integer RequestYear = BaseYear + 1;
045            boolean ReturnValue = (genesisDao.getBudgetConstructionControlFlag(RequestYear, BudgetConstructionConstants.BUDGET_CONSTRUCTION_GENESIS_RUNNING)) || ((genesisDao.getBudgetConstructionControlFlag(RequestYear, BudgetConstructionConstants.BUDGET_CONSTRUCTION_ACTIVE)) && (genesisDao.getBudgetConstructionControlFlag(RequestYear, BudgetConstructionConstants.BUDGET_BATCH_SYNCHRONIZATION_OK)));
046            return ReturnValue;
047        }
048        
049        public boolean CSFUpdatesAllowed(Integer BaseYear) {
050            Integer RequestYear = BaseYear + 1;
051            boolean ReturnValue = (genesisDao.getBudgetConstructionControlFlag(RequestYear, BudgetConstructionConstants.BUDGET_CONSTRUCTION_GENESIS_RUNNING)) || ((genesisDao.getBudgetConstructionControlFlag(RequestYear, BudgetConstructionConstants.BUDGET_CONSTRUCTION_ACTIVE)) && (genesisDao.getBudgetConstructionControlFlag(RequestYear, BudgetConstructionConstants.CSF_UPDATES_OK)));
052            return ReturnValue;
053        }
054    
055        public boolean GLUpdatesAllowed(Integer BaseYear) {
056            Integer RequestYear = BaseYear + 1;
057            boolean ReturnValue = (genesisDao.getBudgetConstructionControlFlag(RequestYear, BudgetConstructionConstants.BUDGET_CONSTRUCTION_GENESIS_RUNNING)) || ((genesisDao.getBudgetConstructionControlFlag(RequestYear, BudgetConstructionConstants.BUDGET_CONSTRUCTION_ACTIVE)) && (genesisDao.getBudgetConstructionControlFlag(BaseYear, BudgetConstructionConstants.BASE_BUDGET_UPDATES_OK)));
058            return ReturnValue;
059        }
060        
061        public boolean IsBudgetConstructionInUpdateMode(Integer baseYear)
062        {
063            Integer requestYear = baseYear + 1;
064            return genesisDao.getBudgetConstructionControlFlag(requestYear, BudgetConstructionConstants.BUDGET_CONSTRUCTION_GENESIS_RUNNING) || ((genesisDao.getBudgetConstructionControlFlag(requestYear, BudgetConstructionConstants.BUDGET_CONSTRUCTION_ACTIVE)) && (genesisDao.getBudgetConstructionControlFlag(requestYear, BudgetConstructionConstants.BUDGET_CONSTRUCTION_UPDATES_OK)));
065        }
066    
067        public void clearDBForGenesis(Integer BaseYear) {
068            genesisDao.clearDBForGenesis(BaseYear);
069        }
070    
071        // use today's date to return the base fiscal year
072        public Integer genesisFiscalYearFromToday() {
073            return genesisDao.fiscalYearFromToday();
074        }
075    
076        // this step updates the budget from the payroll (CSF) and the GL once
077        // genesis has run.
078        public void bCUpdateStep(Integer BaseYear) {
079            /**
080             *  the calling order is important
081             *  for example, GL cannot be created without a document number, appointment funding needs the normal work months
082             *  from the budget construction position table
083             *  the calling order is constrained further if an institution implements referential integrity
084             */
085            LOG.warn(String.format("\n\nStarting BC Update:\n  clear hanging locks\n"));
086            genesisDao.clearHangingBCLocks(BaseYear);
087            LOG.warn(String.format("\n  validate object classes\n"));
088            genesisDao.ensureObjectClassRIForBudget(BaseYear);
089            LOG.warn(String.format("\n  create new documents\n"));
090            genesisDao.createNewBCDocumentsFromGLCSF(BaseYear, GLUpdatesAllowed(BaseYear), CSFUpdatesAllowed(BaseYear));
091            if (GLUpdatesAllowed(BaseYear)) {
092                LOG.warn(String.format("\n  add rows to pending general ledger\n"));
093                genesisDao.updateToPBGL(BaseYear);
094            }
095            boolean CSFOK = CSFUpdatesAllowed(BaseYear);
096            boolean PSSynchOK = BatchPositionSynchAllowed(BaseYear);
097            boolean BCUpdatesAllowed = IsBudgetConstructionInUpdateMode(BaseYear);
098            LOG.warn(String.format("\n  update Budget Construction Position\n"));
099            budgetConstructionHumanResourcesPayrollInterfaceService.refreshBudgetConstructionPosition(BaseYear,PSSynchOK,CSFOK);
100            LOG.warn(String.format("\n  intended incumbent"));
101            budgetConstructionHumanResourcesPayrollInterfaceService.refreshBudgetConstructionIntendedIncumbent(BaseYear,PSSynchOK,CSFOK,BCUpdatesAllowed);
102            if (CSFOK) {
103                LOG.warn(String.format("\n  build appointment funding\n"));
104                genesisDao.buildAppointmentFundingAndBCSF(BaseYear);
105            }
106            LOG.warn(String.format("\n  rebuild the organization hierarchy\n"));
107            genesisDao.rebuildOrganizationHierarchy(BaseYear);
108            // look for accounts coming from payroll or GL that have not been entered into the Budget Construction Accounting table
109            Integer requestFiscalYear = BaseYear + 1;
110            LOG.warn(String.format("\n  look for accounts missing from Budget Construction Accounting\n"));
111            HashMap<String,String[]> missingAccounts = (HashMap<String,String[]>) genesisDao.verifyAccountsAreAccessible(requestFiscalYear);
112            for (Map.Entry<String,String[]> missingAccount : missingAccounts.entrySet())
113            {
114                String[] missingValues = missingAccount.getValue();
115                LOG.warn(String.format("    (chart: %s, account: %s) not found in Budget Construction Accounting\n", missingValues[0], missingValues[1]));
116            }
117        }
118    
119        public void genesisStep(Integer BaseYear) {
120            /**
121             *  the calling order is important
122             *  for example, GL cannot be created without a document number, appointment funding needs the normal work months
123             *  from the budget construction position table
124             *  the calling order is constrained further if an institution implements referential integrity
125             */
126            LOG.warn(String.format("\nstarting Genesis:\n  flags"));
127            genesisDao.setControlFlagsAtTheStartOfGenesis(BaseYear);
128            LOG.warn(String.format("\n  clear database"));
129            genesisDao.clearDBForGenesis(BaseYear);
130            LOG.warn(String.format("\n  chart for budget"));
131            genesisDao.createChartForNextBudgetCycle();
132            LOG.warn(String.format("\n  referential integrity for object classes"));
133            genesisDao.ensureObjectClassRIForBudget(BaseYear);
134            LOG.warn(String.format("\n  new BC documents"));
135            genesisDao.createNewBCDocumentsFromGLCSF(BaseYear, GLUpdatesAllowed(BaseYear), CSFUpdatesAllowed(BaseYear));
136            LOG.warn(String.format("\n  load to PBGL"));
137            genesisDao.initialLoadToPBGL(BaseYear);
138            LOG.warn(String.format("\n  new positions"));
139            boolean CSFOK = CSFUpdatesAllowed(BaseYear);
140            boolean PSSynchOK = BatchPositionSynchAllowed(BaseYear);
141            boolean BCUpdatesAllowed = IsBudgetConstructionInUpdateMode(BaseYear);
142            budgetConstructionHumanResourcesPayrollInterfaceService.refreshBudgetConstructionPosition(BaseYear,PSSynchOK,CSFOK);
143            LOG.warn(String.format("\n  intended incumbent"));
144            budgetConstructionHumanResourcesPayrollInterfaceService.refreshBudgetConstructionIntendedIncumbent(BaseYear,PSSynchOK,CSFOK,BCUpdatesAllowed);
145            if (CSFOK) {
146                LOG.warn("\n  appointment funding/BCSF");
147                genesisDao.buildAppointmentFundingAndBCSF(BaseYear);
148            }
149            LOG.warn("\n  organization hierarchy");
150            genesisDao.rebuildOrganizationHierarchy(BaseYear);
151            LOG.warn("\n  reset control flags");
152            genesisDao.setControlFlagsAtTheEndOfGenesis(BaseYear);
153            LOG.warn("\n  end of genesis");
154        }
155        
156        /*
157         *   look of accounts from the payroll (CSF) or GL that came into budget construction but are *not* in the budget construction accounting table.
158         *   this can be due to an oversight on the part of the chart manager, or to problems with the current year's budget control.
159         *   such accounts will not appear in the pull-up list, since they can't be added to the reporting hierarchy, which is built from budget construction accounting.
160         *   this method is provided for use by a report an institution might want to write.  such accounts will always appear in the log from bCUpdateStep above, whether this method is used or not.
161         */
162        public Map verifyAccountsAreAccessible(Integer requestFiscalYear)
163        {
164            return genesisDao.verifyAccountsAreAccessible(requestFiscalYear);
165        }
166    
167        public void setGenesisDao(GenesisDao genesisDao) {
168            this.genesisDao = genesisDao;
169        }
170        
171        public void setBudgetConstructionHumanResourcesPayrollInterfaceService(BudgetConstructionHumanResourcesPayrollInterfaceService budgetConstructionHumanResourcesPayrollInterfaceService)
172        {
173            this.budgetConstructionHumanResourcesPayrollInterfaceService = budgetConstructionHumanResourcesPayrollInterfaceService; 
174        }
175    }