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