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.sys.service.impl; 017 018 import java.util.Calendar; 019 import java.util.HashMap; 020 021 import org.kuali.kfs.coa.businessobject.Account; 022 import org.kuali.kfs.coa.businessobject.ObjectCode; 023 import org.kuali.kfs.coa.businessobject.OffsetDefinition; 024 import org.kuali.kfs.coa.service.AccountService; 025 import org.kuali.kfs.coa.service.ObjectCodeService; 026 import org.kuali.kfs.fp.businessobject.OffsetAccount; 027 import org.kuali.kfs.gl.businessobject.FlexibleAccountUpdateable; 028 import org.kuali.kfs.sys.KFSConstants; 029 import org.kuali.kfs.sys.exception.InvalidFlexibleOffsetException; 030 import org.kuali.kfs.sys.service.FlexibleOffsetAccountService; 031 import org.kuali.rice.kns.service.BusinessObjectService; 032 import org.kuali.rice.kns.service.DateTimeService; 033 import org.kuali.rice.kns.service.ParameterService; 034 035 /** 036 * This is the default implementation of the FlexibleOffsetAccountService interface. 037 */ 038 public class FlexibleOffsetAccountServiceImpl implements FlexibleOffsetAccountService { 039 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(FlexibleOffsetAccountServiceImpl.class); 040 041 private BusinessObjectService businessObjectService; 042 private AccountService accountService; 043 private ObjectCodeService objectCodeService; 044 private DateTimeService dateTimeService; 045 private ParameterService parameterService; 046 047 /** 048 * This method uses the parameters provided to retrieve an OffsetAccount instance if the flexible offset account flag is 049 * enabled. 050 * 051 * @param chartOfAccountsCode The chart code used to retrieve the flexible offset account. 052 * @param accountNumber The account number of the flexible offset account being retrieved. 053 * @param financialOffsetObjectCode The offset object code used to retrieve the offset account. 054 * @return A flexible offset account based on the parameters provided, or null if offsets are not enabled. 055 * 056 * @see FlexibleOffsetAccountService#getByPrimaryIdIfEnabled 057 */ 058 public OffsetAccount getByPrimaryIdIfEnabled(String chartOfAccountsCode, String accountNumber, String financialOffsetObjectCode) { 059 LOG.debug("getByPrimaryIdIfEnabled() started"); 060 061 if (!getEnabled()) { 062 return null; 063 } 064 HashMap<String,Object> keys = new HashMap(); 065 keys.put("chartOfAccountsCode", chartOfAccountsCode); 066 keys.put("accountNumber", accountNumber); 067 keys.put("financialOffsetObjectCode", financialOffsetObjectCode); 068 return (OffsetAccount) businessObjectService.findByPrimaryKey(OffsetAccount.class, keys); 069 } 070 071 /** 072 * This method queries the parameter table to retrieve the value of the flexible offset flag and returns the resulting value. 073 * 074 * @return True if flexible offsets are enabled, false otherwise. 075 * 076 * @see FlexibleOffsetAccountService#getEnabled 077 */ 078 public boolean getEnabled() { 079 LOG.debug("getEnabled() started"); 080 return parameterService.getIndicatorParameter(OffsetDefinition.class, KFSConstants.SystemGroupParameterNames.FLEXIBLE_OFFSET_ENABLED_FLAG); 081 } 082 083 /** 084 * This method modifies the origin entry provided with values from the associated flexible offset account, which is 085 * retrieved from the database using values provided by the origin entry. 086 * 087 * @param originEntry The origin entry to be updated with offset account details. 088 * @return False if the flexible offset flag is false, if there is no corresponding flexbile offset account, true otherwise. 089 * 090 * @see org.kuali.kfs.sys.service.FlexibleOffsetAccountService#updateOffset(org.kuali.kfs.gl.businessobject.OriginEntryFull) 091 */ 092 public boolean updateOffset(FlexibleAccountUpdateable transaction) { 093 LOG.debug("setBusinessObjectService() started"); 094 095 if (!getEnabled()) { 096 return false; 097 } 098 String keyOfErrorMessage = ""; 099 100 Integer fiscalYear = transaction.getUniversityFiscalYear(); 101 String chartOfAccountsCode = transaction.getChartOfAccountsCode(); 102 String accountNumber = transaction.getAccountNumber(); 103 104 String balanceTypeCode = transaction.getFinancialBalanceTypeCode(); 105 String documentTypeCode = transaction.getFinancialDocumentTypeCode(); 106 107 // do nothing if there is no the offset account with the given chart of accounts code, 108 // account number and offset object code in the offset table. 109 OffsetAccount flexibleOffsetAccount = getByPrimaryIdIfEnabled(chartOfAccountsCode, accountNumber, transaction.getFinancialObjectCode()); 110 if (flexibleOffsetAccount == null) { 111 return false; 112 } 113 114 String offsetAccountNumber = flexibleOffsetAccount.getFinancialOffsetAccountNumber(); 115 String offsetChartOfAccountsCode = flexibleOffsetAccount.getFinancialOffsetChartOfAccountCode(); 116 117 Account offsetAccount = accountService.getByPrimaryId(offsetChartOfAccountsCode, offsetAccountNumber); 118 if (offsetAccount == null) { 119 throw new InvalidFlexibleOffsetException("Invalid Flexible Offset Account " + offsetChartOfAccountsCode + "-" + offsetAccountNumber); 120 } 121 122 // Can't be closed and can't be expired 123 if (!offsetAccount.isActive()) { 124 throw new InvalidFlexibleOffsetException("Closed Flexible Offset Account " + offsetChartOfAccountsCode + "-" + offsetAccountNumber); 125 } 126 if ((offsetAccount.getAccountExpirationDate() != null) && isExpired(offsetAccount, dateTimeService.getCurrentCalendar())) { 127 throw new InvalidFlexibleOffsetException("Expired Flexible Offset Account " + offsetChartOfAccountsCode + "-" + offsetAccountNumber); 128 } 129 130 // If the chart changes, make sure the object code is still valid 131 if (!chartOfAccountsCode.equals(offsetChartOfAccountsCode)) { 132 ObjectCode objectCode = objectCodeService.getByPrimaryId(fiscalYear, offsetChartOfAccountsCode, transaction.getFinancialObjectCode()); 133 if (objectCode == null) { 134 throw new InvalidFlexibleOffsetException("Invalid Object Code for flexible offset " + fiscalYear + "-" + offsetChartOfAccountsCode + "-" + transaction.getFinancialObjectCode()); 135 } 136 } 137 138 // replace the chart and account of the given transaction with those of the offset account obtained above 139 transaction.setAccount(offsetAccount); 140 transaction.setAccountNumber(offsetAccountNumber); 141 transaction.setChartOfAccountsCode(offsetChartOfAccountsCode); 142 143 // blank out the sub account and sub object since the account has been replaced 144 transaction.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 145 transaction.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 146 return true; 147 } 148 149 /** 150 * This method determines if an account has expired. An account has expired if the expiration year of the account is 151 * less than the run date year or if the date of expiration occurred before the run date provided. 152 * 153 * @param account The account to be examined. 154 * @param runCalendar The date the expiration date is tested against. 155 * @return True if the account has expired, false otherwise. 156 */ 157 protected boolean isExpired(Account account, Calendar runCalendar) { 158 159 Calendar expirationDate = Calendar.getInstance(); 160 expirationDate.setTimeInMillis(account.getAccountExpirationDate().getTime()); 161 162 int expirationYear = expirationDate.get(Calendar.YEAR); 163 int runYear = runCalendar.get(Calendar.YEAR); 164 int expirationDay = expirationDate.get(Calendar.DAY_OF_YEAR); 165 int runDay = runCalendar.get(Calendar.DAY_OF_YEAR); 166 167 return (expirationYear < runYear) || (expirationYear == runYear && expirationDay < runDay); 168 } 169 170 /** 171 * Sets the local dateTimeService attribute. 172 * @param dateTimeService The DateTimeService instance to be set. 173 */ 174 public void setDateTimeService(DateTimeService dateTimeService) { 175 this.dateTimeService = dateTimeService; 176 } 177 178 /** 179 * Sets the local accountService attribute. 180 * @param accountService The AccountService instance to be set. 181 */ 182 public void setAccountService(AccountService accountService) { 183 this.accountService = accountService; 184 } 185 186 /** 187 * Sets the local objectCodeService attribute. 188 * @param objectCodeService The ObjectCodeService instance to be set. 189 */ 190 public void setObjectCodeService(ObjectCodeService objectCodeService) { 191 this.objectCodeService = objectCodeService; 192 } 193 194 /** 195 * Sets the local businessObjectService attribute. 196 * @param businessObjectService The BusinessObjectService instance to be set. 197 */ 198 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 199 this.businessObjectService = businessObjectService; 200 } 201 202 /** 203 * Sets the local parameterService attribute. 204 * @param parameterService The ParameterService instance to be set. 205 */ 206 public void setParameterService(ParameterService parameterService) { 207 this.parameterService = parameterService; 208 } 209 }