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.apache.log4j.Logger; 021 import org.kuali.kfs.module.bc.batch.dataaccess.impl.SQLForStep; 022 import org.kuali.kfs.module.bc.document.dataaccess.BudgetConstructionMonthlyBudgetsCreateDeleteDao; 023 import org.kuali.rice.kns.service.PersistenceService; 024 025 026 public class BudgetConstructionMonthlyBudgetsCreateDeleteDaoJdbc extends BudgetConstructionDaoJdbcBase implements BudgetConstructionMonthlyBudgetsCreateDeleteDao { 027 028 029 030 private static Logger LOG = org.apache.log4j.Logger.getLogger(BudgetConstructionMonthlyBudgetsCreateDeleteDaoJdbc.class); 031 032 033 private static ArrayList<SQLForStep> deleteAllSql = new ArrayList<SQLForStep>(2); 034 private static ArrayList<SQLForStep> spreadRevenueSql = new ArrayList<SQLForStep>(2); 035 private static ArrayList<SQLForStep> spreadExpenditureSql = new ArrayList<SQLForStep>(3); 036 037 private PersistenceService persistenceService; 038 039 public BudgetConstructionMonthlyBudgetsCreateDeleteDaoJdbc() 040 { 041 042 StringBuilder sqlBuilder = new StringBuilder(5000); 043 ArrayList<Integer> insertionPoints = new ArrayList<Integer>(); 044 // delete all rows for a given key from the budget construction monthly table 045 sqlBuilder.append("DELETE FROM LD_BCNSTR_MONTH_T\n"); 046 sqlBuilder.append("WHERE (fdoc_nbr = ?)\n"); 047 sqlBuilder.append(" AND (univ_fiscal_yr = ?)\n"); 048 sqlBuilder.append(" AND (fin_coa_cd = ?)\n"); 049 sqlBuilder.append(" AND (account_nbr = ?)\n"); 050 sqlBuilder.append(" AND (sub_acct_nbr = ?)\n"); 051 sqlBuilder.append(" AND (fin_obj_typ_cd IN "); 052 insertionPoints.add(sqlBuilder.length()); 053 sqlBuilder.append(")"); 054 // revenue 055 deleteAllSql.add(new SQLForStep(sqlBuilder,insertionPoints)); 056 // expenditure (exact same thing at present) 057 deleteAllSql.add(new SQLForStep(sqlBuilder,insertionPoints)); 058 sqlBuilder.delete(0,sqlBuilder.length()); 059 insertionPoints.clear(); 060 061 // SQL needed to spread revenue 062 // delete existing revenue for this key, so it can be spread again 063 sqlBuilder.append("DELETE FROM LD_BCNSTR_MONTH_T\n"); 064 sqlBuilder.append("WHERE (fdoc_nbr = ?)\n"); 065 sqlBuilder.append(" AND (univ_fiscal_yr = ?)\n"); 066 sqlBuilder.append(" AND (fin_coa_cd = ?)\n"); 067 sqlBuilder.append(" AND (account_nbr = ?)\n"); 068 sqlBuilder.append(" AND (sub_acct_nbr = ?)\n"); 069 sqlBuilder.append(" AND (fin_obj_typ_cd IN "); 070 insertionPoints.add(sqlBuilder.length()); 071 sqlBuilder.append(")"); 072 spreadRevenueSql.add(new SQLForStep(sqlBuilder,insertionPoints)); 073 insertionPoints.clear(); 074 075 sqlBuilder.delete(0,sqlBuilder.length()); 076 // insert ALL revenue (since we do not re-calculate benefits on revenue, any revenue benefits object classes should be spread along with the other object classes 077 sqlBuilder.append("INSERT INTO LD_BCNSTR_MONTH_T\n"); 078 sqlBuilder.append("(FDOC_NBR, UNIV_FISCAL_YR, FIN_COA_CD, ACCOUNT_NBR, SUB_ACCT_NBR, FIN_OBJECT_CD, FIN_SUB_OBJ_CD, FIN_BALANCE_TYP_CD, FIN_OBJ_TYP_CD,\n"); 079 sqlBuilder.append(" FDOC_LN_MO1_AMT, FDOC_LN_MO2_AMT, FDOC_LN_MO3_AMT, FDOC_LN_MO4_AMT, FDOC_LN_MO5_AMT, FDOC_LN_MO6_AMT,\n"); 080 sqlBuilder.append(" FDOC_LN_MO7_AMT, FDOC_LN_MO8_AMT, FDOC_LN_MO9_AMT, FDOC_LN_MO10_AMT, FDOC_LN_MO11_AMT, FDOC_LN_MO12_AMT)\n"); 081 sqlBuilder.append("(SELECT ?, ?, ?, ?, ?, FIN_OBJECT_CD, FIN_SUB_OBJ_CD, FIN_BALANCE_TYP_CD, FIN_OBJ_TYP_CD,\n"); 082 sqlBuilder.append(" ROUND((acln_annl_bal_amt / 12), 0) + \n"); 083 sqlBuilder.append(" (acln_annl_bal_amt - (ROUND((acln_annl_bal_amt / 12), 0) * 12)),\n"); 084 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 085 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 086 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 087 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 088 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 089 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 090 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 091 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 092 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 093 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 094 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0)\n"); 095 sqlBuilder.append(" FROM LD_PND_BCNSTR_GL_T\n"); 096 sqlBuilder.append(" WHERE (fdoc_nbr = ?)\n"); 097 sqlBuilder.append(" AND (univ_fiscal_yr = ?)\n"); 098 sqlBuilder.append(" AND (fin_coa_cd = ?)\n"); 099 sqlBuilder.append(" AND (account_nbr = ?)\n"); 100 sqlBuilder.append(" AND (sub_acct_nbr = ?)\n"); 101 sqlBuilder.append(" AND (fin_obj_typ_cd IN "); 102 insertionPoints.add(sqlBuilder.length()); 103 sqlBuilder.append("))"); 104 spreadRevenueSql.add(new SQLForStep(sqlBuilder,insertionPoints)); 105 insertionPoints.clear(); 106 107 sqlBuilder.delete(0,sqlBuilder.length()); 108 109 // SQL to spread expenditure 110 // delete existing monthly expenditure (except for actual benefits objects--the benefits will be recalulated and spread later from the GL) 111 sqlBuilder.append("DELETE FROM LD_BCNSTR_MONTH_T\n"); 112 sqlBuilder.append("WHERE (fdoc_nbr = ?)\n"); 113 sqlBuilder.append(" AND (univ_fiscal_yr = ?)\n"); 114 sqlBuilder.append(" AND (fin_coa_cd = ?)\n"); 115 sqlBuilder.append(" AND (account_nbr = ?)\n"); 116 sqlBuilder.append(" AND (sub_acct_nbr = ?)\n"); 117 sqlBuilder.append(" AND (fin_obj_typ_cd IN "); 118 insertionPoints.add(sqlBuilder.length()); 119 sqlBuilder.append(")\n"); 120 sqlBuilder.append("AND (NOT EXISTS (SELECT 1\n"); 121 sqlBuilder.append(" FROM LD_BENEFITS_CALC_T\n"); 122 sqlBuilder.append(" WHERE (LD_BENEFITS_CALC_T.UNIV_FISCAL_YR = ?)\n"); 123 sqlBuilder.append(" AND (LD_BENEFITS_CALC_T.FIN_COA_CD = ?)\n"); 124 sqlBuilder.append(" AND (LD_BENEFITS_CALC_T.POS_FRNGBEN_OBJ_CD = LD_BCNSTR_MONTH_T.FIN_OBJECT_CD)))\n"); 125 spreadExpenditureSql.add(new SQLForStep(sqlBuilder,insertionPoints)); 126 insertionPoints.clear(); 127 128 sqlBuilder.delete(0,sqlBuilder.length()); 129 // spread the general ledger expenditure anew over the 12 months 130 sqlBuilder.append("INSERT INTO LD_BCNSTR_MONTH_T\n"); 131 sqlBuilder.append("(FDOC_NBR, UNIV_FISCAL_YR, FIN_COA_CD, ACCOUNT_NBR, SUB_ACCT_NBR, FIN_OBJECT_CD, FIN_SUB_OBJ_CD, FIN_BALANCE_TYP_CD, FIN_OBJ_TYP_CD,\n"); 132 sqlBuilder.append(" FDOC_LN_MO1_AMT, FDOC_LN_MO2_AMT, FDOC_LN_MO3_AMT, FDOC_LN_MO4_AMT, FDOC_LN_MO5_AMT, FDOC_LN_MO6_AMT,\n"); 133 sqlBuilder.append(" FDOC_LN_MO7_AMT, FDOC_LN_MO8_AMT, FDOC_LN_MO9_AMT, FDOC_LN_MO10_AMT, FDOC_LN_MO11_AMT, FDOC_LN_MO12_AMT)\n"); 134 sqlBuilder.append("(SELECT ?, ?, ?, ?, ?, FIN_OBJECT_CD, FIN_SUB_OBJ_CD, FIN_BALANCE_TYP_CD, FIN_OBJ_TYP_CD,\n"); 135 sqlBuilder.append(" ROUND((acln_annl_bal_amt / 12), 0) + \n"); 136 sqlBuilder.append(" (acln_annl_bal_amt - (ROUND((acln_annl_bal_amt / 12), 0) * 12)),\n"); 137 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 138 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 139 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 140 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 141 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 142 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 143 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 144 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 145 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 146 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0),\n"); 147 sqlBuilder.append(" ROUND((LD_PND_BCNSTR_GL_T.acln_annl_bal_amt / 12), 0)\n"); 148 sqlBuilder.append(" FROM LD_PND_BCNSTR_GL_T\n"); 149 sqlBuilder.append(" WHERE (fdoc_nbr = ?)\n"); 150 sqlBuilder.append(" AND (univ_fiscal_yr = ?)\n"); 151 sqlBuilder.append(" AND (fin_coa_cd = ?)\n"); 152 sqlBuilder.append(" AND (account_nbr = ?)\n"); 153 sqlBuilder.append(" AND (sub_acct_nbr = ?)\n"); 154 sqlBuilder.append("AND (NOT EXISTS (SELECT 1\n"); 155 sqlBuilder.append(" FROM LD_BENEFITS_CALC_T\n"); 156 sqlBuilder.append(" WHERE (LD_BENEFITS_CALC_T.UNIV_FISCAL_YR = ?)\n"); 157 sqlBuilder.append(" AND (LD_BENEFITS_CALC_T.FIN_COA_CD = ?)\n"); 158 sqlBuilder.append(" AND (LD_BENEFITS_CALC_T.POS_FRNGBEN_OBJ_CD = LD_PND_BCNSTR_GL_T.FIN_OBJECT_CD)))\n"); 159 sqlBuilder.append(" AND (fin_obj_typ_cd IN "); 160 insertionPoints.add(sqlBuilder.length()); 161 sqlBuilder.append("))"); 162 spreadExpenditureSql.add(new SQLForStep(sqlBuilder,insertionPoints)); 163 insertionPoints.clear(); 164 165 sqlBuilder.delete(0,sqlBuilder.length()); 166 // count the number of object classes eligible for fringe benefits, to signal the caller that benefits need to be recalculated and spread. 167 sqlBuilder.append("SELECT COUNT(*)\n"); 168 sqlBuilder.append("FROM (LD_BCNSTR_MONTH_T INNER JOIN LD_LBR_OBJ_BENE_T\n"); 169 sqlBuilder.append(" ON ((LD_BCNSTR_MONTH_T.UNIV_FISCAL_YR = LD_LBR_OBJ_BENE_T.UNIV_FISCAL_YR) AND\n"); 170 sqlBuilder.append(" (LD_BCNSTR_MONTH_T.FIN_COA_CD = LD_LBR_OBJ_BENE_T.FIN_COA_CD) AND\n"); 171 sqlBuilder.append(" (LD_BCNSTR_MONTH_T.FIN_OBJECT_CD = LD_LBR_OBJ_BENE_T.FIN_OBJECT_CD)))\n"); 172 sqlBuilder.append("WHERE (LD_BCNSTR_MONTH_T.FDOC_NBR = ?)\n"); 173 sqlBuilder.append(" AND (LD_BCNSTR_MONTH_T.UNIV_FISCAL_YR = ?)\n"); 174 sqlBuilder.append(" AND (LD_BCNSTR_MONTH_T.FIN_COA_CD = ?)\n"); 175 sqlBuilder.append(" AND (LD_BCNSTR_MONTH_T.ACCOUNT_NBR = ?)\n"); 176 sqlBuilder.append(" AND (LD_BCNSTR_MONTH_T.SUB_ACCT_NBR = ?)\n"); 177 sqlBuilder.append(" AND (LD_BCNSTR_MONTH_T.FIN_OBJ_TYP_CD IN "); 178 insertionPoints.add(sqlBuilder.length()); 179 sqlBuilder.append(")\n"); 180 spreadExpenditureSql.add(new SQLForStep(sqlBuilder,insertionPoints)); 181 insertionPoints.clear(); 182 183 } 184 185 /** 186 * 187 * @see org.kuali.kfs.module.bc.document.dataaccess.BudgetConstructionMonthlyBudgetsCreateDeleteDao#BudgetConstructionMonthlyBudgetsDeleteRevenue(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) 188 */ 189 public void deleteBudgetConstructionMonthlyBudgetsRevenue(String documentNumber, Integer fiscalYear, String chartCode, String accountNumber, String subAccountNumber) { 190 191 // get the revenue object types as an SQL IN list 192 ArrayList<String> inSqlString = new ArrayList<String>(); 193 inSqlString.add(getRevenueINList()); 194 195 //run the delete-all SQL with the revenue object classes 196 int returnCount = getSimpleJdbcTemplate().update(deleteAllSql.get(0).getSQL(inSqlString), documentNumber, fiscalYear, chartCode, accountNumber, subAccountNumber); 197 LOG.warn(String.format("\n%s\n Expenditure (all) rows deleted for (%s,%d,%s,%s,%s) = %d",getDbPlatform().toString(),documentNumber, fiscalYear,chartCode,accountNumber, subAccountNumber, returnCount)); 198 /** 199 * 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. 200 */ 201 persistenceService.clearCache(); 202 } 203 204 /** 205 * 206 * @see org.kuali.kfs.module.bc.document.dataaccess.BudgetConstructionMonthlyBudgetsCreateDeleteDao#BudgetConstructionMonthlyBudgetsDeleteExpenditure(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) 207 */ 208 public void deleteBudgetConstructionMonthlyBudgetsExpenditure(String documentNumber, Integer fiscalYear, String chartCode, String accountNumber, String subAccountNumber) { 209 210 // get the expenditure object types as an SQL IN list 211 ArrayList<String> inSqlString = new ArrayList<String>(); 212 inSqlString.add(getExpenditureINList()); 213 214 // run the delete-all SQL with the expenditure object classes 215 int returnCount = getSimpleJdbcTemplate().update(deleteAllSql.get(1).getSQL(inSqlString), documentNumber, fiscalYear, chartCode, accountNumber, subAccountNumber); 216 LOG.warn(String.format("\n%s\n Expenditure (all) rows deleted for (%s,%d,%s,%s,%s) = %d",getDbPlatform().toString(),documentNumber, fiscalYear,chartCode,accountNumber, subAccountNumber, returnCount)); 217 /** 218 * 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. 219 */ 220 persistenceService.clearCache(); 221 } 222 223 /** 224 * 225 * @see org.kuali.kfs.module.bc.document.dataaccess.BudgetConstructionMonthlyBudgetsCreateDeleteDao#BudgetConstructionMonthlyBudgetsSpreadRevenue(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) 226 */ 227 public void spreadBudgetConstructionMonthlyBudgetsRevenue(String documentNumber, Integer fiscalYear, String chartCode, String accountNumber, String subAccountNumber) { 228 229 // for revenue, we delete all existing rows, and spread all the corresponding rows in the general ledger 230 // if there is any revenue for benefits, it will be spread, not calculated based on non-benefits rows as expenditure benefits will be 231 // get the revenue IN list 232 ArrayList<String> inSqlString = new ArrayList<String>(); 233 inSqlString.add(getRevenueINList()); 234 235 236 // delete what is there now for this document for the revenue object classes 237 int returnCount = getSimpleJdbcTemplate().update(spreadRevenueSql.get(0).getSQL(inSqlString), documentNumber, fiscalYear, chartCode, accountNumber, subAccountNumber); 238 LOG.warn(String.format("\n%s\n RevenueSpread rows deleted for (%s,%d,%s,%s,%s) = %d",getDbPlatform().toString(),documentNumber, fiscalYear,chartCode,accountNumber, subAccountNumber, returnCount)); 239 240 // run the create-monthly-budgets-from-GL SQL with the revenue object classes 241 returnCount = getSimpleJdbcTemplate().update(spreadRevenueSql.get(1).getSQL(inSqlString),documentNumber, fiscalYear, chartCode, accountNumber, subAccountNumber, documentNumber, fiscalYear, chartCode, accountNumber, subAccountNumber ); 242 LOG.warn(String.format("\n%s\n RevenueSpread rows inserted for (%s,%d,%s,%s,%s) = %d",getDbPlatform().toString(),documentNumber, fiscalYear,chartCode,accountNumber, subAccountNumber, returnCount)); 243 /** 244 * 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. 245 */ 246 persistenceService.clearCache(); 247 } 248 249 250 /** 251 * 252 * @see org.kuali.kfs.module.bc.document.dataaccess.BudgetConstructionMonthlyBudgetsCreateDeleteDao#BudgetConstructionMonthlyBudgetsSpreadExpenditure(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) 253 */ 254 public boolean spreadBudgetConstructionMonthlyBudgetsExpenditure(String documentNumber, Integer fiscalYear, String chartCode, String accountNumber, String subAccountNumber) { 255 256 // spread general ledger expenditures across 12 months, excluding benefits object types. benefits object expenditure will be recalculated and spread later, because several object codes eligible for benefits can target the same fringe benefit object 257 // get the expenditure object types as an SQL IN list 258 ArrayList<String> inSqlString = new ArrayList<String>(); 259 inSqlString.add(getExpenditureINList()); 260 261 // run the delete-all-except-benefits SQL with the expenditure object classes 262 int returnCount = getSimpleJdbcTemplate().update(spreadExpenditureSql.get(0).getSQL(inSqlString), documentNumber, fiscalYear, chartCode, accountNumber, subAccountNumber, fiscalYear, chartCode); 263 LOG.warn(String.format("\n%s\n ExpenditureSpread rows deleted for (%s,%d,%s,%s,%s) = %d",getDbPlatform().toString(),documentNumber, fiscalYear,chartCode,accountNumber, subAccountNumber, returnCount)); 264 265 // run the create-monthly-budgets-from-GL SQL with the expenditure object classes 266 returnCount = getSimpleJdbcTemplate().update(spreadExpenditureSql.get(1).getSQL(inSqlString), documentNumber, fiscalYear, chartCode, accountNumber, subAccountNumber, documentNumber, fiscalYear, chartCode, accountNumber, subAccountNumber, fiscalYear, chartCode); 267 LOG.warn(String.format("\n%s\n ExpenditureSpread rows inserted for (%s,%d,%s,%s,%s) = %d",getDbPlatform().toString(),documentNumber, fiscalYear,chartCode,accountNumber, subAccountNumber, returnCount)); 268 /** 269 * 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. 270 */ 271 persistenceService.clearCache(); 272 273 // tell the caller whether there were any benefits-eligible object classes with non-zero amounts 274 return(budgetConstructionMonthlyBudgetContainsBenefitsExpenditure(spreadExpenditureSql.get(2).getSQL(inSqlString), documentNumber, fiscalYear, chartCode, accountNumber, subAccountNumber)); 275 } 276 277 /** 278 * 279 * return true if there are benefits object codes in the general ledger for the document, false otherwise 280 */ 281 protected boolean budgetConstructionMonthlyBudgetContainsBenefitsExpenditure(String BenefitsObjectsCheckSQL, String documentNumber, Integer fiscalYear, String chartCode, String accountNumber, String subAccountNumber) { 282 283 Long numberOfBenefitsEligibleRows = getSimpleJdbcTemplate().queryForLong(BenefitsObjectsCheckSQL,documentNumber, fiscalYear, chartCode, accountNumber, subAccountNumber); 284 return (numberOfBenefitsEligibleRows != 0); 285 } 286 287 public void setPersistenceService(PersistenceService persistenceService) 288 { 289 this.persistenceService = persistenceService; 290 } 291 292 293 }