View Javadoc
1   /*
2    * Copyright 2007 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.coa.document;
17  
18  import java.sql.Date;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.commons.lang.StringUtils;
24  import org.apache.log4j.Logger;
25  import org.kuali.ole.coa.businessobject.Account;
26  import org.kuali.ole.coa.service.AccountPersistenceStructureService;
27  import org.kuali.ole.coa.service.AccountService;
28  import org.kuali.ole.coa.service.SubAccountTrickleDownInactivationService;
29  import org.kuali.ole.coa.service.SubObjectTrickleDownInactivationService;
30  import org.kuali.ole.sys.OLEPropertyConstants;
31  import org.kuali.ole.sys.context.SpringContext;
32  import org.kuali.ole.sys.document.FinancialSystemMaintainable;
33  import org.kuali.rice.core.api.datetime.DateTimeService;
34  import org.kuali.rice.kns.document.MaintenanceDocument;
35  import org.kuali.rice.krad.bo.PersistableBusinessObject;
36  import org.kuali.rice.krad.maintenance.MaintenanceLock;
37  import org.kuali.rice.krad.util.KRADConstants;
38  import org.kuali.rice.krad.util.ObjectUtils;
39  
40  /**
41   * This class overrides the saveBusinessObject() method which is called during post process from the KualiPostProcessor so that it
42   * can automatically deactivate the Sub-Accounts related to the account It also overrides the processAfterCopy so that it sets
43   * specific fields that shouldn't be copied to default values {@link KualiPostProcessor}
44   */
45  public class KualiAccountMaintainableImpl extends FinancialSystemMaintainable {
46      private static final Logger LOG = Logger.getLogger(KualiAccountMaintainableImpl.class);
47      private static final String ACCOUNT_GUIDE_LINE_PROPERTY = "accountGuideline";
48      
49      /**
50       * Automatically deactivates {@link SubAccount}s after saving the {@link Account}
51       * 
52       * @see org.kuali.rice.kns.maintenance.Maintainable#saveBusinessObject()
53       */
54      @Override
55      public void saveBusinessObject() {
56          boolean isClosingAccount = isClosingAccount();
57  
58          // make sure we save account first
59          super.saveBusinessObject();
60  
61          // if we're closing the account, then rely on the trickle-down inactivation services to trickle-down inactivate the
62          // sub-accounts
63          if (isClosingAccount) {
64              SpringContext.getBean(SubAccountTrickleDownInactivationService.class).trickleDownInactivateSubAccounts((Account) getBusinessObject(), getDocumentNumber());
65              SpringContext.getBean(SubObjectTrickleDownInactivationService.class).trickleDownInactivateSubObjects((Account) getBusinessObject(), getDocumentNumber());
66          }
67      }
68  
69      /**
70       * After a copy is done set specific fields on {@link Account} to default values
71       * 
72       * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#processAfterCopy()
73       */
74      @Override
75      public void processAfterCopy(MaintenanceDocument document, Map<String, String[]> parameters) {
76          Account account = (Account) this.getBusinessObject();
77          account.setAccountCreateDate(null); // account's pre-rules will fill this field in
78          account.setAccountEffectiveDate(new Date(SpringContext.getBean(DateTimeService.class).getCurrentDate().getTime()));
79          account.setActive(true);
80          super.processAfterCopy(document, parameters);
81      }
82      
83   
84      @Override
85      public List<MaintenanceLock> generateMaintenanceLocks() {
86          List<MaintenanceLock> maintenanceLocks = super.generateMaintenanceLocks();
87          boolean isClosingAccount = false;
88  
89          if (isClosingAccount()) {
90              maintenanceLocks.addAll(SpringContext.getBean(SubAccountTrickleDownInactivationService.class).generateTrickleDownMaintenanceLocks((Account) getBusinessObject(), getDocumentNumber()));
91              maintenanceLocks.addAll(SpringContext.getBean(SubObjectTrickleDownInactivationService.class).generateTrickleDownMaintenanceLocks((Account) getBusinessObject(), getDocumentNumber()));
92          }
93          return maintenanceLocks;
94      }
95  
96      protected Account retrieveExistingAccountFromDB() {
97          Account newAccount = (Account) getBusinessObject();
98           Account oldAccount = SpringContext.getBean(AccountService.class).getByPrimaryId(newAccount.getChartOfAccountsCode(), newAccount.getAccountNumber());
99          return oldAccount;
100     }
101 
102     protected boolean isClosingAccount() {
103         // the account has to be closed on the new side when editing in order for it to be possible that we are closing the account
104         if (KRADConstants.MAINTENANCE_EDIT_ACTION.equals(getMaintenanceAction()) && !((Account) getBusinessObject()).isActive()) {
105             Account existingAccountFromDB = retrieveExistingAccountFromDB();
106             if (ObjectUtils.isNotNull(existingAccountFromDB)) {
107                 // now see if the original account was not closed, in which case, we are closing the account
108                 if (existingAccountFromDB.isActive()) {
109                     return true;
110                 }
111             }
112         }
113         return false;
114     }
115 
116     /**
117      * Determines who should be FYI'd as the account supervisor for the routing of the account maintenance document. If there is an
118      * existing account, it uses the account supervisor from that; otherwise, it uses the account supervisor from the business
119      * object of this maintainable
120      * 
121      * @return an appropriate account supervisor to FYI during account maintenance document routing
122      */
123     public String getRoutingAccountsSupervisorySystemsIdentifier() {
124         final Account existingAccountFromDB = retrieveExistingAccountFromDB();
125         if (ObjectUtils.isNull(existingAccountFromDB)) {
126             return ((Account) getBusinessObject()).getAccountsSupervisorySystemsIdentifier();
127         }
128         return existingAccountFromDB.getAccountsSupervisorySystemsIdentifier();
129     }
130 
131     /**
132      * Had to override this method because account guideline data was lost when copied and then a lookup is performed
133      * 
134      * @see org.kuali.rice.kns.maintenance.KualiMaintainableImpl#refresh(java.lang.String, java.util.Map,
135      *      org.kuali.rice.kns.document.MaintenanceDocument)
136      */
137     @Override
138     public void refresh(String refreshCaller, Map fieldValues, MaintenanceDocument document) {
139         super.refresh(refreshCaller, fieldValues, document);
140         Account newAcct = (Account) document.getNewMaintainableObject().getBusinessObject();
141         Account oldAcct = (Account) document.getOldMaintainableObject().getBusinessObject();
142         if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(document.getNewMaintainableObject().getMaintenanceAction())) {
143             if (ObjectUtils.isNull(newAcct.getAccountGuideline())) {
144                 newAcct.setAccountGuideline(oldAcct.getAccountGuideline());
145             }
146         }
147 
148     }
149 
150     @Override
151     protected void refreshReferences(String referencesToRefresh) {        
152         //make call to super
153         super.refreshReferences( removeReferenceFromString(referencesToRefresh, ACCOUNT_GUIDE_LINE_PROPERTY) );
154     }
155     
156     /**
157      * Removes a named reference from a referencesToRefresh string
158      */
159     protected String removeReferenceFromString(String referencesToRefresh, String referenceToRemove){
160         String newReference = referencesToRefresh;
161         
162         if(ObjectUtils.isNotNull(newReference)){
163             int index = newReference.indexOf(referenceToRemove);        
164             if(index != -1){  
165                 //remove from beginning
166                 if(index == 0){
167                     
168                     String suffix = "";
169                     //add comma at end since there is more after this word
170                     if(newReference.length() != referenceToRemove.length()){
171                         suffix = ",";
172                     }                    
173                     newReference = referencesToRefresh.replaceAll(ACCOUNT_GUIDE_LINE_PROPERTY + suffix, "");
174                     
175                 }else{
176                     //removing from middle to end... either way, comma will be in front
177                     newReference = referencesToRefresh.replaceAll("," + ACCOUNT_GUIDE_LINE_PROPERTY, "");
178                 }
179             }
180         }
181         
182         return newReference;
183     }
184     
185     /**
186      * @see org.kuali.ole.sys.document.FinancialSystemMaintainable#populateChartOfAccountsCodeFields()
187      * 
188      * Special treatment is needed when a new Account is created, the chartCode-accountNumber fields in the document can use the new account 
189      * that's being created; in which case chart code shall be populated from the PK chart code in the document instead of retrieving it from DB
190      * using the account number, as the new account doesn't exist in the DB yet.
191      */
192     @Override
193     protected void populateChartOfAccountsCodeFields() {
194         // super method is not called because the logic there wouldn't apply here        
195         AccountService acctService = SpringContext.getBean(AccountService.class);        
196         AccountPersistenceStructureService apsService = SpringContext.getBean(AccountPersistenceStructureService.class);
197         PersistableBusinessObject bo = getBusinessObject();        
198         Iterator<Map.Entry<String, String>> chartAccountPairs = apsService.listChartCodeAccountNumberPairs(bo).entrySet().iterator();        
199  
200         // all reference accounts could possibly use the same new accounting being created in the current document 
201         while (chartAccountPairs.hasNext()) {
202             Map.Entry<String, String> entry = (Map.Entry<String, String>)chartAccountPairs.next();
203             String coaCodeName = entry.getKey();            
204             String acctNumName = entry.getValue(); 
205             String accountNumber = (String)ObjectUtils.getPropertyValue(bo, acctNumName);
206             String coaCode = null;
207             String coaCodePK = (String)ObjectUtils.getPropertyValue(bo, OLEPropertyConstants.CHART_OF_ACCOUNTS_CODE);
208             String accountNumberPK = (String)ObjectUtils.getPropertyValue(bo, OLEPropertyConstants.ACCOUNT_NUMBER);
209             
210             // if reference account number is same as the primary key accountNumber, copy the primary key chart code to reference chart Code
211             if (StringUtils.equalsIgnoreCase(accountNumber, accountNumberPK)) {
212                 coaCode = coaCodePK;
213             }
214             // otherwise retrieve chart code from account as usual
215             else {
216                 Account account = acctService.getUniqueAccountForAccountNumber(accountNumber);            
217                 if (ObjectUtils.isNotNull(account)) {
218                     coaCode = account.getChartOfAccountsCode();
219                 }
220             }
221             
222             try {
223                 ObjectUtils.setObjectProperty(bo, coaCodeName, coaCode); 
224             }
225             catch (Exception e) {
226                 LOG.error("Error in setting property value for " + coaCodeName);
227             }
228         }
229     }    
230 
231 }