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.dataaccess.impl;
017    
018    import java.util.ArrayList;
019    
020    import org.kuali.kfs.module.bc.batch.dataaccess.impl.SQLForStep;
021    import org.kuali.kfs.module.bc.document.dataaccess.BenefitsCalculationDao;
022    import org.kuali.kfs.sys.KFSConstants;
023    import org.kuali.rice.kns.service.PersistenceService;
024    import org.kuali.rice.kns.util.Guid;
025    
026    /**
027     * 
028     * implements the SQL procedures to calculate benefits for the personnel object codes in the budget.  
029     * apply the appropriate percentage to each object type in the general ledger, and split the result out into the monthly budget lines 
030     * if monthly budgets exist for the accounting key.
031     */
032    
033    public class BenefitsCalculationDaoJdbc extends BudgetConstructionDaoJdbcBase implements BenefitsCalculationDao {
034    
035        private static ArrayList<SQLForStep> sqlAnnualSteps  = new ArrayList<SQLForStep>(6);
036        private static ArrayList<SQLForStep> sqlMonthlySteps = new ArrayList<SQLForStep>(4);
037        
038        private PersistenceService persistenceService;
039        
040        
041        /**
042         *  these will be set to constant values in the constructor and used throughout SQL for the various steps.
043         */
044    
045        public BenefitsCalculationDaoJdbc() {
046    
047            //this is a bean constructor, so it is dangerous to access static constants defined in other classes here.  the other classes may not have been loaded yet.
048            //so, we use insertion points to indicate where such constants should be placed in the SQL, and we splice them in a run time.  we also use insertion points to splice in run time constants from SH_PARM_T.
049            StringBuilder sqlBuilder = new StringBuilder(2500);
050            ArrayList<Integer> insertionPoints = new ArrayList<Integer>();
051            /**
052             * this needs to be done before we can get rid of annual fringe benefits objects with no base.
053             * LD_BNCSTR_MNTH_T has an RI child constraint on LD_PND_BCNSTR_GL_T.  So, before we eliminate any Budget Construction
054             * general ledger rows, we have to get rid of any dependent Budget Construction Monthly rows.  If we call this set of
055             * queries to rebuild budgeted benefits for the general ledger, the next set of queries will also have to be called if
056             * monthly budgets exist.  If no monthly budgets exist, the query below will not do anything.  In that case, calling the
057             * Budget Construction general ledger benefits calculation routine without calling the monthly benefits calculation 
058             * routine will be acceptable. 
059             */
060            sqlBuilder.append("DELETE FROM LD_BCNSTR_MONTH_T\n");
061            sqlBuilder.append("WHERE (LD_BCNSTR_MONTH_T.FDOC_NBR = ?)\n");
062            sqlBuilder.append("AND (LD_BCNSTR_MONTH_T.UNIV_FISCAL_YR = ?)\n");
063            sqlBuilder.append("AND (LD_BCNSTR_MONTH_T.FIN_COA_CD = ?)\n");
064            sqlBuilder.append("AND (LD_BCNSTR_MONTH_T.ACCOUNT_NBR = ?)\n");
065            sqlBuilder.append("AND (LD_BCNSTR_MONTH_T.SUB_ACCT_NBR = ?)\n");
066            sqlBuilder.append("AND (EXISTS (SELECT 1\n");
067            sqlBuilder.append("       FROM (LD_PND_BCNSTR_GL_T INNER JOIN LD_BENEFITS_CALC_T\n");
068            sqlBuilder.append("       ON ((LD_PND_BCNSTR_GL_T.UNIV_FISCAL_YR = LD_BENEFITS_CALC_T.UNIV_FISCAL_YR)\n");
069            sqlBuilder.append("           AND (LD_PND_BCNSTR_GL_T.FIN_COA_CD = LD_BENEFITS_CALC_T.FIN_COA_CD)\n");
070            sqlBuilder.append("           AND (LD_PND_BCNSTR_GL_T.FIN_OBJECT_CD = LD_BENEFITS_CALC_T.POS_FRNGBEN_OBJ_CD)))\n");
071            sqlBuilder.append("       WHERE (LD_BCNSTR_MONTH_T.UNIV_FISCAL_YR = LD_PND_BCNSTR_GL_T.UNIV_FISCAL_YR)\n");
072            sqlBuilder.append("         AND (LD_BCNSTR_MONTH_T.FDOC_NBR = LD_PND_BCNSTR_GL_T.FDOC_NBR)\n");
073            sqlBuilder.append("         AND (LD_BCNSTR_MONTH_T.FIN_COA_CD = LD_PND_BCNSTR_GL_T.FIN_COA_CD)\n");
074            sqlBuilder.append("         AND (LD_BCNSTR_MONTH_T.ACCOUNT_NBR = LD_PND_BCNSTR_GL_T.ACCOUNT_NBR)\n");
075            sqlBuilder.append("         AND (LD_BCNSTR_MONTH_T.SUB_ACCT_NBR = LD_PND_BCNSTR_GL_T.SUB_ACCT_NBR)\n");
076            sqlBuilder.append("         AND (LD_BCNSTR_MONTH_T.FIN_OBJECT_CD = LD_PND_BCNSTR_GL_T.FIN_OBJECT_CD)\n");
077            sqlBuilder.append("         AND (LD_PND_BCNSTR_GL_T.FIN_BEG_BAL_LN_AMT = 0)))\n");
078            sqlAnnualSteps.add(new SQLForStep(sqlBuilder));
079            sqlBuilder.delete(0,sqlBuilder.length());
080            /**
081             * get rid of fringe benefits objects with no base
082             */
083            sqlBuilder.append("DELETE FROM LD_PND_BCNSTR_GL_T\n");
084            sqlBuilder.append("WHERE (LD_PND_BCNSTR_GL_T.FDOC_NBR = ?)\n");
085            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.UNIV_FISCAL_YR =?)\n ");
086            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.FIN_COA_CD = ?)\n");
087            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.ACCOUNT_NBR = ?)\n");
088            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.SUB_ACCT_NBR = ?)\n");
089            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.FIN_BEG_BAL_LN_AMT = 0)\n");
090            sqlBuilder.append("  AND (EXISTS (SELECT 1 FROM LD_BENEFITS_CALC_T\n");
091            sqlBuilder.append("WHERE (LD_BENEFITS_CALC_T.UNIV_FISCAL_YR = LD_PND_BCNSTR_GL_T.UNIV_FISCAL_YR)\n");
092            sqlBuilder.append("  AND (LD_BENEFITS_CALC_T.FIN_COA_CD = LD_PND_BCNSTR_GL_T.FIN_COA_CD)\n");
093            sqlBuilder.append("  AND (LD_BENEFITS_CALC_T.POS_FRNGBEN_OBJ_CD = LD_PND_BCNSTR_GL_T.FIN_OBJECT_CD)))");
094            sqlAnnualSteps.add(new SQLForStep(sqlBuilder));
095            sqlBuilder.delete(0, sqlBuilder.length());
096            /**
097             * set the request to 0 for fringe benefits objects with base
098             */
099            sqlBuilder.append("UPDATE LD_PND_BCNSTR_GL_T\n");
100            sqlBuilder.append("SET ACLN_ANNL_BAL_AMT =0\n");
101            sqlBuilder.append("WHERE (LD_PND_BCNSTR_GL_T.FDOC_NBR = ?)\n");
102            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.UNIV_FISCAL_YR = ?)\n");
103            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.FIN_COA_CD = ?)\n");
104            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.ACCOUNT_NBR = ?)\n");
105            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.SUB_ACCT_NBR = ?)\n");
106            sqlBuilder.append("  AND (EXISTS (SELECT 1 FROM LD_BENEFITS_CALC_T\n");
107            sqlBuilder.append("               WHERE (LD_BENEFITS_CALC_T.UNIV_FISCAL_YR = LD_PND_BCNSTR_GL_T.UNIV_FISCAL_YR)\n");
108            sqlBuilder.append("                 AND (LD_BENEFITS_CALC_T.FIN_COA_CD = LD_PND_BCNSTR_GL_T.FIN_COA_CD)\n");
109            sqlBuilder.append("                 AND (LD_BENEFITS_CALC_T.POS_FRNGBEN_OBJ_CD = LD_PND_BCNSTR_GL_T.FIN_OBJECT_CD)))");
110            sqlAnnualSteps.add(new SQLForStep(sqlBuilder));
111            sqlBuilder.delete(0, sqlBuilder.length());
112            /**
113             * sum the amounts in benefits-eligible objects and attach the appropriate benefits object code
114             */
115            sqlBuilder.append("INSERT INTO LD_BCN_BENEFITS_RECALC01_MT\n(SESID, POS_FRNGBEN_OBJ_CD, FB_SUM)\n");
116            sqlBuilder.append("(SELECT ?,LD_BENEFITS_CALC_T.POS_FRNGBEN_OBJ_CD,\n");
117            sqlBuilder.append(" ROUND(SUM(LD_PND_BCNSTR_GL_T.ACLN_ANNL_BAL_AMT * (LD_BENEFITS_CALC_T.POS_FRNG_BENE_PCT/100.0)),0)\n ");
118            sqlBuilder.append(" FROM LD_PND_BCNSTR_GL_T,\n");
119            sqlBuilder.append("      LD_LBR_OBJ_BENE_T,\n");
120            sqlBuilder.append("      LD_BENEFITS_CALC_T\n");
121            sqlBuilder.append(" WHERE (LD_PND_BCNSTR_GL_T.FDOC_NBR = ?)\n");
122            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.UNIV_FISCAL_YR = ?)\n");
123            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.FIN_COA_CD = ?)\n");
124            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.ACCOUNT_NBR = ?)\n");
125            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.SUB_ACCT_NBR = ?)\n");
126            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.ACLN_ANNL_BAL_AMT <> 0)\n");
127            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.UNIV_FISCAL_YR = LD_LBR_OBJ_BENE_T.UNIV_FISCAL_YR)\n");
128            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.fin_coa_cd = LD_LBR_OBJ_BENE_T.fin_coa_cd)\n");
129            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.fin_object_cd = LD_LBR_OBJ_BENE_T.fin_object_cd)\n");
130            sqlBuilder.append("   AND (LD_LBR_OBJ_BENE_T.univ_fiscal_yr = LD_BENEFITS_CALC_T.univ_fiscal_yr)\n");
131            sqlBuilder.append("   AND (LD_LBR_OBJ_BENE_T.fin_coa_cd = LD_BENEFITS_CALC_T.fin_coa_cd)\n");
132            sqlBuilder.append("   AND (LD_LBR_OBJ_BENE_T.finobj_bene_typ_cd = LD_BENEFITS_CALC_T.pos_benefit_typ_cd)\n");
133            sqlBuilder.append(" GROUP BY LD_BENEFITS_CALC_T.pos_frngben_obj_cd)");
134            sqlAnnualSteps.add(new SQLForStep(sqlBuilder));
135            sqlBuilder.delete(0, sqlBuilder.length());
136            /**
137             * re-set the request amount for the appropriate benefits code
138             */
139            sqlBuilder.append("UPDATE LD_PND_BCNSTR_GL_T\n");
140            sqlBuilder.append("SET acln_annl_bal_amt =\n");
141            sqlBuilder.append("        (SELECT LD_BCN_BENEFITS_RECALC01_MT.fb_sum\n");
142            sqlBuilder.append("         FROM LD_BCN_BENEFITS_RECALC01_MT\n");
143            sqlBuilder.append("        WHERE (LD_BCN_BENEFITS_RECALC01_MT.sesid = ?)\n");
144            sqlBuilder.append("          AND (LD_PND_BCNSTR_GL_T.fin_object_cd = LD_BCN_BENEFITS_RECALC01_MT.pos_frngben_obj_cd))\n");
145            sqlBuilder.append("WHERE (LD_PND_BCNSTR_GL_T.fdoc_nbr = ?)\n");
146            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.univ_fiscal_yr = ?)\n");
147            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.fin_coa_cd = ?)\n");
148            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.account_nbr = ?)\n");
149            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.sub_acct_nbr = ?)\n");
150            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.fin_sub_obj_cd = '");
151            // default sub object code
152            insertionPoints.add(sqlBuilder.length());
153            sqlBuilder.append("')\n");
154            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.fin_balance_typ_cd = '");
155            // general ledger budget balance type code
156            insertionPoints.add(sqlBuilder.length());
157            sqlBuilder.append("')\n");
158            sqlBuilder.append("  AND EXISTS (SELECT 1\n");
159            sqlBuilder.append("              FROM LD_BCN_BENEFITS_RECALC01_MT\n");
160            sqlBuilder.append("              WHERE (sesid = ?)\n");
161            sqlBuilder.append("                AND (LD_PND_BCNSTR_GL_T.fin_object_cd = LD_BCN_BENEFITS_RECALC01_MT.pos_frngben_obj_cd))\n");
162            sqlBuilder.append("  AND (LD_PND_BCNSTR_GL_T.fin_obj_typ_cd IN ");
163            // expenditure object types 
164            insertionPoints.add(sqlBuilder.length());
165            sqlBuilder.append(")");
166            sqlAnnualSteps.add(new SQLForStep(sqlBuilder,insertionPoints));
167            sqlBuilder.delete(0, sqlBuilder.length());
168            insertionPoints.clear();
169            /**
170             * now re-insert rows with zero base which still have benefits-eligible object codes in pending BC GL.  all budget construction GL lines added by the budget construction application have an object type code of FinObjTypeExpenditureexpCd, which we pass at run time as a parameter.  we have an IN clause to check for other object types which may have been loaded in the base from the general ledger.  the request for such lines will not have this object type.
171             * 
172             */
173            sqlBuilder.append("INSERT INTO LD_PND_BCNSTR_GL_T\n");
174            sqlBuilder.append("(FDOC_NBR, UNIV_FISCAL_YR, FIN_COA_CD, ACCOUNT_NBR, SUB_ACCT_NBR, FIN_OBJECT_CD,\n");
175            sqlBuilder.append(" FIN_SUB_OBJ_CD, FIN_BALANCE_TYP_CD, FIN_OBJ_TYP_CD, ACLN_ANNL_BAL_AMT, FIN_BEG_BAL_LN_AMT)\n");
176            sqlBuilder.append("(SELECT ?, ?, ?, ?, ?,\n");
177            sqlBuilder.append("LD_BCN_BENEFITS_RECALC01_MT.pos_frngben_obj_cd,\n");
178            sqlBuilder.append(" '");
179            // default sub object code
180            insertionPoints.add(sqlBuilder.length());
181            sqlBuilder.append("', '");
182            // general ledger budget balance type code
183            insertionPoints.add(sqlBuilder.length());
184            sqlBuilder.append("', ");
185            sqlBuilder.append("?, \n");
186            sqlBuilder.append("LD_BCN_BENEFITS_RECALC01_MT.fb_sum, 0\n");
187            sqlBuilder.append("FROM LD_BCN_BENEFITS_RECALC01_MT\n");
188            sqlBuilder.append("WHERE (LD_BCN_BENEFITS_RECALC01_MT.sesid = ?)\n");
189            sqlBuilder.append("  AND (NOT EXISTS\n");
190            sqlBuilder.append("(SELECT 1\n");
191            sqlBuilder.append(" FROM LD_PND_BCNSTR_GL_T\n");
192            sqlBuilder.append(" WHERE (LD_PND_BCNSTR_GL_T.fdoc_nbr = ?)\n");
193            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.univ_fiscal_yr = ?)\n");
194            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.fin_coa_cd = ?)\n");
195            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.account_nbr = ?)\n");
196            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.sub_acct_nbr = ?)\n");
197            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.fin_object_cd = LD_BCN_BENEFITS_RECALC01_MT.pos_frngben_obj_cd)\n");
198            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.fin_sub_obj_cd = '");
199            // default sub object code
200            insertionPoints.add(sqlBuilder.length());
201            sqlBuilder.append("')\n");
202            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.fin_balance_typ_cd = '");
203            // general ledger budget balance type code
204            insertionPoints.add(sqlBuilder.length());
205            sqlBuilder.append("')\n");
206            sqlBuilder.append("   AND (LD_PND_BCNSTR_GL_T.fin_obj_typ_cd IN ");
207            //  expenditure object types
208            insertionPoints.add(sqlBuilder.length());
209            sqlBuilder.append("))))");
210            sqlAnnualSteps.add(new SQLForStep(sqlBuilder,insertionPoints));
211            sqlBuilder.delete(0, sqlBuilder.length());
212            insertionPoints.clear();
213            /**
214             * this is the SQL for the monthly budget benefits. any rounding amount is added to the amount for month 1
215             */
216            /**
217             * Cleanup the rare case where annual request goes to zero with existing monthly buckets.
218             * This gives monthly calc benefits problems from constraints since the annual benefit target row
219             * might be non-existent when it inserts the new results from the left over monthly buckets
220             * This is usually the case since annual benefits are usually calculated first.
221             */
222            sqlBuilder.append("DELETE FROM LD_BCNSTR_MONTH_T\n");
223            sqlBuilder.append("WHERE LD_BCNSTR_MONTH_T.fdoc_nbr = ?\n");
224            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.univ_fiscal_yr = ?\n");
225            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.fin_coa_cd = ?\n");
226            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.account_nbr = ?\n");
227            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.sub_acct_nbr = ?\n");
228            sqlBuilder.append("  AND NOT (LD_BCNSTR_MONTH_T.fdoc_ln_mo1_amt = 0\n");
229            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo2_amt = 0\n");
230            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo3_amt = 0\n");
231            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo4_amt = 0\n");
232            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo5_amt = 0\n");
233            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo6_amt = 0\n");
234            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo7_amt = 0\n");
235            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo8_amt = 0\n");
236            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo9_amt = 0\n");
237            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo10_amt = 0\n");
238            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo11_amt = 0\n");
239            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo12_amt = 0) \n");
240            sqlBuilder.append("  AND EXISTS\n");
241            sqlBuilder.append("        (SELECT 1\n");
242            sqlBuilder.append("         FROM LD_PND_BCNSTR_GL_T\n");
243            sqlBuilder.append("        WHERE LD_PND_BCNSTR_GL_T.fdoc_nbr = LD_BCNSTR_MONTH_T.fdoc_nbr\n");
244            sqlBuilder.append("          AND LD_PND_BCNSTR_GL_T.univ_fiscal_yr = LD_BCNSTR_MONTH_T.univ_fiscal_yr\n");
245            sqlBuilder.append("          AND LD_PND_BCNSTR_GL_T.fin_coa_cd = LD_BCNSTR_MONTH_T.fin_coa_cd\n");
246            sqlBuilder.append("          AND LD_PND_BCNSTR_GL_T.account_nbr = LD_BCNSTR_MONTH_T.account_nbr\n");
247            sqlBuilder.append("          AND LD_PND_BCNSTR_GL_T.sub_acct_nbr = LD_BCNSTR_MONTH_T.sub_acct_nbr\n");
248            sqlBuilder.append("          AND LD_PND_BCNSTR_GL_T.fin_object_cd = LD_BCNSTR_MONTH_T.fin_object_cd\n");
249            sqlBuilder.append("          AND LD_PND_BCNSTR_GL_T.fin_sub_obj_cd = LD_BCNSTR_MONTH_T.fin_sub_obj_cd\n");
250            sqlBuilder.append("          AND LD_PND_BCNSTR_GL_T.fin_balance_typ_cd = LD_BCNSTR_MONTH_T.fin_balance_typ_cd\n");
251            sqlBuilder.append("          AND LD_PND_BCNSTR_GL_T.fin_obj_typ_cd = LD_BCNSTR_MONTH_T.fin_obj_typ_cd\n");
252            sqlBuilder.append("          AND LD_PND_BCNSTR_GL_T.acln_annl_bal_amt = 0)");
253            sqlMonthlySteps.add(new SQLForStep(sqlBuilder));
254            sqlBuilder.delete(0, sqlBuilder.length());
255    
256    
257            /**
258             * cleanup by deleting any existing monthly benefit recs
259             */
260            sqlBuilder.append("DELETE FROM LD_BCNSTR_MONTH_T\n");
261            sqlBuilder.append("WHERE LD_BCNSTR_MONTH_T.fdoc_nbr = ?\n");
262            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.univ_fiscal_yr = ?\n");
263            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.fin_coa_cd = ?\n");
264            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.account_nbr = ?\n");
265            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.sub_acct_nbr = ?\n");
266            sqlBuilder.append("  AND EXISTS\n");
267            sqlBuilder.append("        (SELECT 1\n");
268            sqlBuilder.append("         FROM LD_BENEFITS_CALC_T\n");
269            sqlBuilder.append("        WHERE LD_BENEFITS_CALC_T.univ_fiscal_yr = ?\n");
270            sqlBuilder.append("          AND LD_BENEFITS_CALC_T.fin_coa_cd = ?\n");
271            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fin_object_cd = LD_BENEFITS_CALC_T.pos_frngben_obj_cd)");
272            sqlMonthlySteps.add(new SQLForStep(sqlBuilder));
273            sqlBuilder.delete(0, sqlBuilder.length());
274            /**
275             * calc benefits for source objects and sum to target objects.   all budget construction GL lines added by the budget construction application have an object type code of FinObjTypeExpenditureexpCd, which we pass at run time as a parameter.  we have an IN clause to check for other object types which may have been loaded in the base from the general ledger.  the request for such lines will not have this object type.
276             */
277            sqlBuilder.append("INSERT INTO LD_BCNSTR_MONTH_T\n");
278            sqlBuilder.append("(FDOC_NBR, UNIV_FISCAL_YR, FIN_COA_CD, ACCOUNT_NBR, SUB_ACCT_NBR, FIN_OBJECT_CD,\n");
279            sqlBuilder.append("FIN_SUB_OBJ_CD, FIN_BALANCE_TYP_CD, FIN_OBJ_TYP_CD, FDOC_LN_MO1_AMT, FDOC_LN_MO2_AMT,\n");
280            sqlBuilder.append(" FDOC_LN_MO3_AMT, FDOC_LN_MO4_AMT, FDOC_LN_MO5_AMT, FDOC_LN_MO6_AMT, FDOC_LN_MO7_AMT, FDOC_LN_MO8_AMT,\n");
281            sqlBuilder.append(" FDOC_LN_MO9_AMT, FDOC_LN_MO10_AMT, FDOC_LN_MO11_AMT, FDOC_LN_MO12_AMT)\n");
282            sqlBuilder.append("SELECT ?,\n");
283            sqlBuilder.append("    ?,\n");
284            sqlBuilder.append("    ?,\n");
285            sqlBuilder.append("    ?,\n");
286            sqlBuilder.append("    ?,\n");
287            sqlBuilder.append("   LD_BENEFITS_CALC_T.pos_frngben_obj_cd,");
288            sqlBuilder.append(" '");
289            // default sub object code
290            insertionPoints.add(sqlBuilder.length());
291            sqlBuilder.append("', '");
292            // general ledger budget balance type code
293            insertionPoints.add(sqlBuilder.length());
294            sqlBuilder.append("', ");
295            sqlBuilder.append("?, \n");
296            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo1_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
297            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo2_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
298            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo3_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
299            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo4_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
300            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo5_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
301            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo6_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
302            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo7_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
303            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo8_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
304            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo9_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
305            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo10_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
306            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo11_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0),\n");
307            sqlBuilder.append("   ROUND(SUM(COALESCE(LD_BCNSTR_MONTH_T.fdoc_ln_mo12_amt * (LD_BENEFITS_CALC_T.pos_frng_bene_pct/100.0),0)),0)\n");
308            sqlBuilder.append("FROM LD_BCNSTR_MONTH_T,\n");
309            sqlBuilder.append("     LD_BENEFITS_CALC_T,\n");
310            sqlBuilder.append("     LD_LBR_OBJ_BENE_T\n");
311            sqlBuilder.append("WHERE LD_BCNSTR_MONTH_T.fdoc_nbr = ?\n");
312            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.univ_fiscal_yr = ?\n");
313            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.fin_coa_cd = ?\n");
314            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.account_nbr = ?\n");
315            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.sub_acct_nbr = ?\n");
316            sqlBuilder.append("  AND NOT (LD_BCNSTR_MONTH_T.fdoc_ln_mo1_amt = 0\n");
317            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo2_amt = 0\n");
318            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo3_amt = 0\n");
319            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo4_amt = 0\n");
320            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo5_amt = 0\n");
321            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo6_amt = 0\n");
322            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo7_amt = 0\n");
323            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo8_amt = 0\n");
324            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo9_amt = 0\n");
325            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo10_amt = 0\n");
326            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo11_amt = 0\n");
327            sqlBuilder.append("          AND LD_BCNSTR_MONTH_T.fdoc_ln_mo12_amt = 0) \n");
328            sqlBuilder.append("  AND LD_LBR_OBJ_BENE_T.univ_fiscal_yr = LD_BCNSTR_MONTH_T.univ_fiscal_yr\n");
329            sqlBuilder.append("  AND LD_LBR_OBJ_BENE_T.fin_coa_cd = LD_BCNSTR_MONTH_T.fin_coa_cd\n");
330            sqlBuilder.append("  AND LD_LBR_OBJ_BENE_T.fin_object_cd = LD_BCNSTR_MONTH_T.fin_object_cd\n");
331            sqlBuilder.append("  AND LD_BENEFITS_CALC_T.univ_fiscal_yr = LD_LBR_OBJ_BENE_T.univ_fiscal_yr\n");
332            sqlBuilder.append("  AND LD_BENEFITS_CALC_T.fin_coa_cd = LD_LBR_OBJ_BENE_T.fin_coa_cd\n");
333            sqlBuilder.append("  AND LD_BENEFITS_CALC_T.pos_benefit_typ_cd = LD_LBR_OBJ_BENE_T.finobj_bene_typ_cd\n");
334            sqlBuilder.append("GROUP BY LD_BENEFITS_CALC_T.pos_frngben_obj_cd");
335            sqlMonthlySteps.add(new SQLForStep(sqlBuilder,insertionPoints));
336            sqlBuilder.delete(0, sqlBuilder.length());
337            insertionPoints.clear();
338    
339    
340            /**
341             * adjust the month 1 totals for rounding error
342             */
343            sqlBuilder.append("UPDATE LD_BCNSTR_MONTH_T\n");
344            sqlBuilder.append("SET fdoc_ln_mo1_amt =\n");
345            sqlBuilder.append("    (SELECT (LD_BCNSTR_MONTH_T.fdoc_ln_mo1_amt +\n");
346            sqlBuilder.append("            (LD_PND_BCNSTR_GL_T.acln_annl_bal_amt -\n");
347            sqlBuilder.append("            (LD_BCNSTR_MONTH_T.fdoc_ln_mo1_amt + LD_BCNSTR_MONTH_T.fdoc_ln_mo2_amt +\n");
348            sqlBuilder.append("             LD_BCNSTR_MONTH_T.fdoc_ln_mo3_amt + LD_BCNSTR_MONTH_T.fdoc_ln_mo4_amt +\n");
349            sqlBuilder.append("             LD_BCNSTR_MONTH_T.fdoc_ln_mo5_amt + LD_BCNSTR_MONTH_T.fdoc_ln_mo6_amt +\n");
350            sqlBuilder.append("             LD_BCNSTR_MONTH_T.fdoc_ln_mo7_amt + LD_BCNSTR_MONTH_T.fdoc_ln_mo8_amt +\n");
351            sqlBuilder.append("             LD_BCNSTR_MONTH_T.fdoc_ln_mo9_amt + LD_BCNSTR_MONTH_T.fdoc_ln_mo10_amt +\n");
352            sqlBuilder.append("             LD_BCNSTR_MONTH_T.fdoc_ln_mo11_amt + LD_BCNSTR_MONTH_T.fdoc_ln_mo12_amt)))\n");
353            sqlBuilder.append("    FROM LD_PND_BCNSTR_GL_T\n");
354            sqlBuilder.append("    WHERE LD_BCNSTR_MONTH_T.fdoc_nbr = LD_PND_BCNSTR_GL_T.fdoc_nbr\n");
355            sqlBuilder.append("      AND LD_BCNSTR_MONTH_T.univ_fiscal_yr = LD_PND_BCNSTR_GL_T.univ_fiscal_yr\n");
356            sqlBuilder.append("      AND LD_BCNSTR_MONTH_T.fin_coa_cd = LD_PND_BCNSTR_GL_T.fin_coa_cd\n");
357            sqlBuilder.append("      AND LD_BCNSTR_MONTH_T.account_nbr = LD_PND_BCNSTR_GL_T.account_nbr\n");
358            sqlBuilder.append("      AND LD_BCNSTR_MONTH_T.sub_acct_nbr = LD_PND_BCNSTR_GL_T.sub_acct_nbr\n");
359            sqlBuilder.append("      AND LD_BCNSTR_MONTH_T.fin_object_cd = LD_PND_BCNSTR_GL_T.fin_object_cd\n");
360            sqlBuilder.append("      AND LD_BCNSTR_MONTH_T.fin_sub_obj_cd = LD_PND_BCNSTR_GL_T.fin_sub_obj_cd\n");
361            sqlBuilder.append("      AND LD_BCNSTR_MONTH_T.fin_balance_typ_cd = LD_PND_BCNSTR_GL_T.fin_balance_typ_cd\n");
362            sqlBuilder.append("      AND LD_BCNSTR_MONTH_T.fin_obj_typ_cd = LD_PND_BCNSTR_GL_T.fin_obj_typ_cd)\n");
363            sqlBuilder.append("WHERE LD_BCNSTR_MONTH_T.fdoc_nbr = ?\n");
364            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.univ_fiscal_yr = ?\n");
365            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.fin_coa_cd = ?\n");
366            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.account_nbr = ?\n");
367            sqlBuilder.append("  AND LD_BCNSTR_MONTH_T.sub_acct_nbr = ?\n");
368            sqlBuilder.append("  AND EXISTS \n");
369            sqlBuilder.append("        (SELECT 1\n");
370            sqlBuilder.append("        FROM LD_BENEFITS_CALC_T\n");
371            sqlBuilder.append("        WHERE LD_BENEFITS_CALC_T.univ_fiscal_yr = ?\n");
372            sqlBuilder.append("          AND LD_BENEFITS_CALC_T.fin_coa_cd = ?\n");
373            sqlBuilder.append("          AND LD_BENEFITS_CALC_T.pos_frngben_obj_cd = LD_BCNSTR_MONTH_T.fin_object_cd)\n");
374            ;
375            sqlMonthlySteps.add(new SQLForStep(sqlBuilder));
376        }
377    
378        /**
379         * @see org.kuali.kfs.module.bc.document.dataaccess.BenefitsCalculationDao#calculateAnnualBudgetConstructionGeneralLedgerBenefits(String, Integer, String, String, String, String)
380         */
381        public void calculateAnnualBudgetConstructionGeneralLedgerBenefits(String documentNumber, Integer fiscalYear, String chartOfAccounts, String accountNumber, String subAccountNumber, String finObjTypeExpenditureexpCd) {
382    
383            // the first thing to do is get the SQL IN list of expenditure object code types allowed in budget construction.
384            // if this parameter is ill-formed, we can't calculate benefits. we will blow the user out of the water as a consequence.
385            // if the benefits portion of budget construction is not in use at a particular site, then doing it this way will have no impact.
386            
387            ArrayList<String> stringsToInsert = new ArrayList<String>();
388            stringsToInsert.add(KFSConstants.getDashFinancialSubObjectCode());
389            stringsToInsert.add(KFSConstants.BALANCE_TYPE_BASE_BUDGET);
390            stringsToInsert.add(getExpenditureINList());
391            String idForSession = (new Guid()).toString();
392    
393            getSimpleJdbcTemplate().update(sqlAnnualSteps.get(0).getSQL(), documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber);
394            getSimpleJdbcTemplate().update(sqlAnnualSteps.get(1).getSQL(), documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber);
395            getSimpleJdbcTemplate().update(sqlAnnualSteps.get(2).getSQL(), documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber);
396            getSimpleJdbcTemplate().update(sqlAnnualSteps.get(3).getSQL(), idForSession, documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber);
397            // re-set general ledger amount for existing fringe benefits object codes 
398            getSimpleJdbcTemplate().update(sqlAnnualSteps.get(4).getSQL(stringsToInsert), idForSession, documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber, idForSession);
399            // insert general ledger lines for new fringe benefits object codes.
400            stringsToInsert.add(2,stringsToInsert.get(0));
401            stringsToInsert.add(3,stringsToInsert.get(1));
402            getSimpleJdbcTemplate().update(sqlAnnualSteps.get(5).getSQL(stringsToInsert), documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber, finObjTypeExpenditureexpCd, idForSession, documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber);
403            clearTempTableBySesId("LD_BCN_BENEFITS_RECALC01_MT", "SESID", idForSession);
404            /**
405             * this is necessary to clear any rows for the tables we have just updated from the OJB cache.  otherwise, subsequent calls to OJB will fetch the old, unupdated cached rows.
406             */
407            persistenceService.clearCache();
408        }
409    
410        /**
411         * 
412         * @see org.kuali.kfs.module.bc.document.dataaccess.BenefitsCalculationDao#calculateMonthlyBudgetConstructionGeneralLedgerBenefits(java.lang.String, java.lang.Integer, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
413         */
414        public void calculateMonthlyBudgetConstructionGeneralLedgerBenefits(String documentNumber, Integer fiscalYear, String chartOfAccounts, String accountNumber, String subAccountNumber, String finObjTypeExpenditureexpCd) {
415            String idForSession = (new Guid()).toString();
416    
417            ArrayList<String> stringsToInsert = new ArrayList<String>();
418            stringsToInsert.add(KFSConstants.getDashFinancialSubObjectCode());
419            stringsToInsert.add(KFSConstants.BALANCE_TYPE_BASE_BUDGET);
420    
421            // get rid of monthly buckets for any rows with annual zero request
422            getSimpleJdbcTemplate().update(sqlMonthlySteps.get(0).getSQL(), documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber);
423            // get rid of existing monthly budgets for this key       
424            getSimpleJdbcTemplate().update(sqlMonthlySteps.get(1).getSQL(), documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber, fiscalYear, chartOfAccounts);
425            // spread the budgeted general ledger fringe beneftis amounts for this key equally into the twelve months
426            getSimpleJdbcTemplate().update(sqlMonthlySteps.get(2).getSQL(stringsToInsert), documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber, finObjTypeExpenditureexpCd, documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber);
427            // add any rounding errors to the first month
428            getSimpleJdbcTemplate().update(sqlMonthlySteps.get(3).getSQL(), documentNumber, fiscalYear, chartOfAccounts, accountNumber, subAccountNumber, fiscalYear, chartOfAccounts);
429            /**
430             * this is necessary to clear any rows for the tables we have just updated from the OJB cache.  otherwise, subsequent calls to OJB will fetch the old, unupdated cached rows.
431             */
432            persistenceService.clearCache();
433        }
434        
435        public void setPersistenceService(PersistenceService persistenceService)
436        {
437            this.persistenceService = persistenceService;
438        }
439    }