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 }