001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.module.chart.rules;
017:
018: import java.sql.Timestamp;
019: import java.util.HashMap;
020:
021: import org.apache.commons.lang.StringUtils;
022: import org.kuali.core.document.MaintenanceDocument;
023: import org.kuali.core.service.BusinessObjectService;
024: import org.kuali.core.service.KualiConfigurationService;
025: import org.kuali.core.util.ObjectUtils;
026: import org.kuali.kfs.bo.PostalZipCode;
027: import org.kuali.kfs.context.SpringContext;
028: import org.kuali.module.chart.bo.Account;
029: import org.kuali.module.chart.bo.SubFundGroup;
030: import org.kuali.module.chart.service.AccountService;
031:
032: /**
033: * PreRules checks for the Account that needs to occur while still in the Struts processing. This includes defaults, confirmations,
034: * etc.
035: */
036: public class AccountPreRules extends MaintenancePreRulesBase {
037:
038: protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
039: .getLogger(AccountPreRules.class);
040:
041: private static final String DEFAULT_STATE_CODE = "Account.Defaults.StateCode";
042: private static final String DEFAULT_ACCOUNT_TYPE_CODE = "Account.Defaults.AccountType";
043:
044: private KualiConfigurationService configService;
045: private AccountService accountService;
046: private Account newAccount;
047: private Account copyAccount;
048:
049: private static final String GENERAL_FUND_CD = "GF";
050: private static final String RESTRICTED_FUND_CD = "RF";
051: private static final String ENDOWMENT_FUND_CD = "EN";
052: private static final String PLANT_FUND_CD = "PF";
053:
054: private static final String RESTRICTED_CD_RESTRICTED = "R";
055: private static final String RESTRICTED_CD_UNRESTRICTED = "U";
056: private static final String RESTRICTED_CD_TEMPORARILY_RESTRICTED = "T";
057: private static final String RESTRICTED_CD_NOT_APPLICABLE = "N";
058:
059: public AccountPreRules() {
060: accountService = SpringContext.getBean(AccountService.class);
061: configService = SpringContext
062: .getBean(KualiConfigurationService.class);
063: }
064:
065: /**
066: * Executes the following pre rules
067: * <ul>
068: * <li>{@link AccountPreRules#checkForContinuationAccount(String, String, String, String)}</li>
069: * <li>{@link AccountPreRules#checkForDefaultSubFundGroupStatus()}</li>
070: * <li>{@link AccountPreRules#newAccountDefaults(MaintenanceDocument)}</li>
071: * <li>{@link AccountPreRules#setStateFromZip}</li>
072: * </ul>
073: * This does not fail on rule failures
074: * @see org.kuali.module.chart.rules.MaintenancePreRulesBase#doCustomPreRules(org.kuali.core.document.MaintenanceDocument)
075: */
076: protected boolean doCustomPreRules(MaintenanceDocument document) {
077: setupConvenienceObjects(document);
078: checkForContinuationAccounts(); // run this first to avoid side effects
079: checkForDefaultSubFundGroupStatus();
080:
081: LOG
082: .debug("done with continuation account, proceeeding with remaining pre rules");
083:
084: newAccountDefaults(document);
085: setStateFromZip(document);
086:
087: return true;
088: }
089:
090: /**
091: * This method sets a default restricted status on an account if and only if the status code in SubFundGroup has been set and
092: * the user answers in the affirmative that they definitely want to use this SubFundGroup.
093: */
094: private void checkForDefaultSubFundGroupStatus() {
095: String restrictedStatusCode = "";
096:
097: // if subFundGroupCode was not entered, then we have nothing
098: // to do here, so exit
099: if (ObjectUtils.isNull(copyAccount.getSubFundGroup())
100: || StringUtils.isBlank(copyAccount
101: .getSubFundGroupCode())) {
102: return;
103: }
104: SubFundGroup subFundGroup = copyAccount.getSubFundGroup();
105:
106: // KULCOA-1112 : if the sub fund group has a restriction code, override whatever the user selected
107: if (StringUtils.isNotBlank(subFundGroup
108: .getAccountRestrictedStatusCode())) {
109: restrictedStatusCode = subFundGroup
110: .getAccountRestrictedStatusCode().trim();
111: String subFundGroupCd = subFundGroup.getSubFundGroupCode();
112: newAccount
113: .setAccountRestrictedStatusCode(restrictedStatusCode);
114: }
115:
116: }
117:
118: /**
119: * This method checks for continuation accounts and presents the user with a question regarding their use on this account.
120: */
121: private void checkForContinuationAccounts() {
122: LOG.debug("entering checkForContinuationAccounts()");
123:
124: if (StringUtils.isNotBlank(newAccount
125: .getReportsToAccountNumber())) {
126: Account account = checkForContinuationAccount(
127: "Fringe Benefit Account", newAccount
128: .getReportsToChartOfAccountsCode(),
129: newAccount.getReportsToAccountNumber(), "");
130: if (ObjectUtils.isNotNull(account)) { // override old user inputs
131: newAccount.setReportsToAccountNumber(account
132: .getAccountNumber());
133: newAccount.setReportsToChartOfAccountsCode(account
134: .getChartOfAccountsCode());
135: }
136: }
137:
138: if (StringUtils.isNotBlank(newAccount
139: .getEndowmentIncomeAccountNumber())) {
140: Account account = checkForContinuationAccount(
141: "Endowment Account", newAccount
142: .getEndowmentIncomeAcctFinCoaCd(),
143: newAccount.getEndowmentIncomeAccountNumber(), "");
144: if (ObjectUtils.isNotNull(account)) { // override old user inputs
145: newAccount.setEndowmentIncomeAccountNumber(account
146: .getAccountNumber());
147: newAccount.setEndowmentIncomeAcctFinCoaCd(account
148: .getChartOfAccountsCode());
149: }
150: }
151:
152: if (StringUtils.isNotBlank(newAccount
153: .getIncomeStreamAccountNumber())) {
154: Account account = checkForContinuationAccount(
155: "Income Stream Account", newAccount
156: .getIncomeStreamFinancialCoaCode(),
157: newAccount.getIncomeStreamAccountNumber(), "");
158: if (ObjectUtils.isNotNull(account)) { // override old user inputs
159: newAccount.setIncomeStreamAccountNumber(account
160: .getAccountNumber());
161: newAccount.setIncomeStreamFinancialCoaCode(account
162: .getChartOfAccountsCode());
163: }
164: }
165:
166: if (StringUtils.isNotBlank(newAccount
167: .getContractControlAccountNumber())) {
168: Account account = checkForContinuationAccount(
169: "Contract Control Account", newAccount
170: .getContractControlFinCoaCode(), newAccount
171: .getContractControlAccountNumber(), "");
172: if (ObjectUtils.isNotNull(account)) { // override old user inputs
173: newAccount.setContractControlAccountNumber(account
174: .getAccountNumber());
175: newAccount.setContractControlFinCoaCode(account
176: .getChartOfAccountsCode());
177: }
178: }
179:
180: if (StringUtils.isNotBlank(newAccount
181: .getIndirectCostRecoveryAcctNbr())) {
182: Account account = checkForContinuationAccount(
183: "Indirect Cost Recovery Account", newAccount
184: .getIndirectCostRcvyFinCoaCode(),
185: newAccount.getIndirectCostRecoveryAcctNbr(), "");
186: if (ObjectUtils.isNotNull(account)) { // override old user inputs
187: newAccount.setIndirectCostRecoveryAcctNbr(account
188: .getAccountNumber());
189: newAccount.setIndirectCostRcvyFinCoaCode(account
190: .getChartOfAccountsCode());
191: }
192: }
193:
194: }
195:
196: /**
197: * This method sets the convenience objects like newAccount and oldAccount, so you have short and easy handles to the new and
198: * old objects contained in the maintenance document. It also calls the BusinessObjectBase.refresh(), which will attempt to load
199: * all sub-objects from the DB by their primary keys, if available.
200: *
201: * @param document - the maintenanceDocument being evaluated
202: */
203: private void setupConvenienceObjects(MaintenanceDocument document) {
204:
205: // setup newAccount convenience objects, make sure all possible sub-objects are populated
206: newAccount = (Account) document.getNewMaintainableObject()
207: .getBusinessObject();
208: copyAccount = (Account) ObjectUtils.deepCopy(newAccount);
209: copyAccount.refresh();
210: }
211:
212: /**
213: * This method sets up some defaults for new Account
214: *
215: * @param maintenanceDocument
216: */
217: private void newAccountDefaults(
218: MaintenanceDocument maintenanceDocument) {
219:
220: /*
221: * GlobalVariables.getErrorMap().put("document.newMaintainableObject.accountEffectiveDate" ,
222: * "error.document.accountMaintenance.emptyAccountEffectiveDate", "Account Effective Date");
223: */
224:
225: // TODO: this is not needed any more, is in maintdoc xml defaults
226: Timestamp ts = maintenanceDocument.getDocumentHeader()
227: .getWorkflowDocument().getCreateDate();
228: // Set nano as zero, to prevent an error related on maximum character numbers.
229: ts.setNanos(0);
230: if (ts != null) {
231: // On new Accounts AccountCreateDate is defaulted to the doc creation date
232: if (newAccount.getAccountCreateDate() == null) {
233: newAccount.setAccountCreateDate(ts);
234: }
235: // On new Accounts acct_effect_date is defaulted to the doc creation date
236: if (copyAccount.getAccountEffectiveDate() == null) {
237: newAccount.setAccountEffectiveDate(ts);
238: }
239: }
240: }
241:
242: /**
243: * This method lookups state and city from populated zip, set the values on the form
244: *
245: * @param maintenanceDocument
246: */
247: private void setStateFromZip(MaintenanceDocument maintenanceDocument) {
248:
249: // acct_zip_cd, acct_state_cd, acct_city_nm all are populated by looking up
250: // the zip code and getting the state and city from that
251: if (!StringUtils.isBlank(copyAccount.getAccountZipCode())) {
252:
253: HashMap primaryKeys = new HashMap();
254: primaryKeys.put("postalZipCode", copyAccount
255: .getAccountZipCode());
256: PostalZipCode zip = (PostalZipCode) SpringContext.getBean(
257: BusinessObjectService.class).findByPrimaryKey(
258: PostalZipCode.class, primaryKeys);
259:
260: // If user enters a valid zip code, override city name and state code entered by user
261: if (ObjectUtils.isNotNull(zip)) { // override old user inputs
262: newAccount.setAccountCityName(zip.getPostalCityName());
263: newAccount
264: .setAccountStateCode(zip.getPostalStateCode());
265: }
266: }
267: }
268:
269: }
|