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.businessobject;
017    
018    import java.sql.Date;
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.HashMap;
022    import java.util.Iterator;
023    import java.util.LinkedHashMap;
024    import java.util.List;
025    import java.util.Map;
026    
027    import org.apache.commons.lang.StringUtils;
028    import org.kuali.kfs.sys.KFSPropertyConstants;
029    import org.kuali.kfs.sys.context.SpringContext;
030    import org.kuali.rice.kns.bo.GlobalBusinessObject;
031    import org.kuali.rice.kns.bo.GlobalBusinessObjectDetail;
032    import org.kuali.rice.kns.bo.PersistableBusinessObject;
033    import org.kuali.rice.kns.bo.PersistableBusinessObjectBase;
034    import org.kuali.rice.kns.exception.BusinessObjectNotFoundException;
035    import org.kuali.rice.kns.service.BusinessObjectService;
036    import org.kuali.rice.kns.service.PersistenceStructureService;
037    import org.kuali.rice.kns.util.KualiDecimal;
038    import org.kuali.rice.kns.util.TypedArrayList;
039    
040    /**
041     * This class simply acts as a container to hold the List of Delegate Changes and the list of Account entries, for the Global
042     * Delegate Change Document.
043     */
044    public class AccountDelegateGlobal extends PersistableBusinessObjectBase implements GlobalBusinessObject {
045    
046        private String documentNumber;
047    
048        private String modelName;
049        private String modelChartOfAccountsCode;
050        private String modelOrganizationCode;
051    
052        private AccountDelegateModel model;
053    
054        List<AccountGlobalDetail> accountGlobalDetails;
055        List<AccountDelegateGlobalDetail> delegateGlobals;
056    
057        /**
058         * Constructs a DelegateGlobal.java.
059         */
060        public AccountDelegateGlobal() {
061            super();
062            accountGlobalDetails = new TypedArrayList(AccountGlobalDetail.class);
063            delegateGlobals = new TypedArrayList(AccountDelegateGlobalDetail.class);
064        }
065    
066        /**
067         * This method adds a single AccountGlobalDetail instance to the list. If one is already present in the list with the same
068         * chartCode and accountNumber, then this new one will not be added.
069         * 
070         * @param accountGlobalDetail - populated AccountGlobalDetail instance
071         */
072        public void addAccount(AccountGlobalDetail accountGlobalDetail) {
073    
074            // validate the argument
075            if (accountGlobalDetail == null) {
076                throw new IllegalArgumentException("The accountGlobalDetail instanced passed in was null.");
077            }
078            else if (StringUtils.isBlank(accountGlobalDetail.getChartOfAccountsCode())) {
079                throw new IllegalArgumentException("The chartOfAccountsCode member of the accountGlobalDetail object was not populated.");
080            }
081            else if (StringUtils.isBlank(accountGlobalDetail.getAccountNumber())) {
082                throw new IllegalArgumentException("The accountNumber member of the accountGlobalDetail object was not populated.");
083            }
084    
085            // add the object if one doesnt already exist, otherwise silently do nothing
086            AccountGlobalDetail testObject = getAccount(accountGlobalDetail.getChartOfAccountsCode(), accountGlobalDetail.getAccountNumber());
087            if (testObject == null) {
088                this.accountGlobalDetails.add(accountGlobalDetail);
089            }
090        }
091    
092        /**
093         * This method retrieves the specific AccountGlobalDetail object that corresponds to your requested chartCode and accountNumber
094         * (or a null object if there is no match).
095         * 
096         * @param chartCode
097         * @param accountNumber
098         * @return returns the AccountGlobalDetail instance matching the chartCode & accountNumber passed in, or Null if none match
099         */
100        public AccountGlobalDetail getAccount(String chartCode, String accountNumber) {
101    
102            // validate the argument
103            if (StringUtils.isBlank(chartCode)) {
104                throw new IllegalArgumentException("The chartCode argument was null or empty.");
105            }
106            else if (StringUtils.isBlank(accountNumber)) {
107                throw new IllegalArgumentException("The accountNumber argument was null or empty.");
108            }
109    
110            // walk the list of AccountGlobalDetail objects
111            for (Iterator iter = this.accountGlobalDetails.iterator(); iter.hasNext();) {
112                AccountGlobalDetail accountGlobalDetail = (AccountGlobalDetail) iter.next();
113    
114                // if this one is a match, then quit
115                if (chartCode.equalsIgnoreCase(accountGlobalDetail.getChartOfAccountsCode()) && accountNumber.equalsIgnoreCase(accountGlobalDetail.getAccountNumber())) {
116                    return accountGlobalDetail;
117                }
118            }
119    
120            // we return null if one is not found
121            return null;
122        }
123    
124        /**
125         * @see org.kuali.rice.kns.document.GlobalBusinessObject#getGlobalChangesToDelete()
126         */
127        public List<PersistableBusinessObject> generateDeactivationsToPersist() {
128            BusinessObjectService boService = SpringContext.getBean(BusinessObjectService.class);
129    
130            // retreive all the existing delegates for these accounts
131            List<AccountDelegate> bosToDeactivate = new ArrayList();
132            Map<String, Object> fieldValues;
133            Collection existingDelegates;
134            for (AccountGlobalDetail accountDetail : getAccountGlobalDetails()) {
135                fieldValues = new HashMap();
136                fieldValues.put("chartOfAccountsCode", accountDetail.getChartOfAccountsCode());
137                fieldValues.put("accountNumber", accountDetail.getAccountNumber());
138                fieldValues.put("active", true);
139                existingDelegates = boService.findMatching(AccountDelegate.class, fieldValues);
140                bosToDeactivate.addAll(existingDelegates);
141            }
142    
143            // mark all the delegates as inactive
144            for (AccountDelegate accountDelegate : bosToDeactivate) {
145                accountDelegate.setActive(false);
146            }
147            return new ArrayList<PersistableBusinessObject>(bosToDeactivate);
148        }
149    
150        /**
151         * @see org.kuali.rice.kns.document.GlobalBusinessObject#applyGlobalChanges(org.kuali.rice.kns.bo.BusinessObject)
152         */
153        @SuppressWarnings("deprecation")
154        public List<PersistableBusinessObject> generateGlobalChangesToPersist() {
155    
156            BusinessObjectService boService = SpringContext.getBean(BusinessObjectService.class);
157            List<AccountDelegate> persistables = new ArrayList();
158    
159            List<AccountDelegateGlobalDetail> changeDocuments = this.getDelegateGlobals();
160            List<AccountGlobalDetail> accountDetails = this.getAccountGlobalDetails();
161    
162            for (AccountDelegateGlobalDetail changeDocument : changeDocuments) {
163                for (AccountGlobalDetail accountDetail : accountDetails) {
164    
165                    Account account = (Account) boService.findByPrimaryKey(Account.class, accountDetail.getPrimaryKeys());
166    
167                    // if the account doesnt exist, fail fast, as this should never happen,
168                    // the busines rules for this document should have caught this.
169                    if (account == null) {
170                        throw new BusinessObjectNotFoundException("Account [" + accountDetail.getChartOfAccountsCode() + "-" + accountDetail.getAccountNumber() + "] was not present in the database. " + "This should never happen under normal circumstances, as an invalid account should have " + "been caught by the Business Rules infrastructure.");
171                    }
172    
173                    // attempt to load the existing Delegate from the DB, if it exists. we do this to avoid
174                    // versionNumber conflicts if we tried to just insert a new record that already existed.
175                    Map pkMap = new HashMap();
176                    pkMap.putAll(accountDetail.getPrimaryKeys()); // chartOfAccountsCode & accountNumber
177                    pkMap.put("financialDocumentTypeCode", changeDocument.getFinancialDocumentTypeCode());
178                    pkMap.put("accountDelegateSystemId", changeDocument.getAccountDelegateUniversalId());
179                    AccountDelegate delegate = (AccountDelegate) boService.findByPrimaryKey(AccountDelegate.class, pkMap);
180    
181                    // if there is no existing Delegate with these primary keys, then we're creating a new one,
182                    // so lets populate it with the primary keys
183                    if (delegate == null) {
184                        delegate = new AccountDelegate();
185                        delegate.setChartOfAccountsCode(accountDetail.getChartOfAccountsCode());
186                        delegate.setAccountNumber(accountDetail.getAccountNumber());
187                        delegate.setAccountDelegateSystemId(changeDocument.getAccountDelegateUniversalId());
188                        delegate.setFinancialDocumentTypeCode(changeDocument.getFinancialDocumentTypeCode());
189                        delegate.setActive(true);
190                    }
191                    else {
192                        delegate.setActive(true);
193                    }
194    
195                    // APPROVAL FROM AMOUNT
196                    if (changeDocument.getApprovalFromThisAmount() != null) {
197                        if (!changeDocument.getApprovalFromThisAmount().equals(KualiDecimal.ZERO)) {
198                            delegate.setFinDocApprovalFromThisAmt(changeDocument.getApprovalFromThisAmount());
199                        }
200                    }
201    
202                    // APPROVAL TO AMOUNT
203                    if (changeDocument.getApprovalToThisAmount() != null) {
204                        if (!changeDocument.getApprovalToThisAmount().equals(KualiDecimal.ZERO)) {
205                            delegate.setFinDocApprovalToThisAmount(changeDocument.getApprovalToThisAmount());
206                        }
207                    }
208    
209                    // PRIMARY ROUTING
210                    delegate.setAccountsDelegatePrmrtIndicator(changeDocument.getAccountDelegatePrimaryRoutingIndicator());
211    
212                    // START DATE
213                    if (changeDocument.getAccountDelegateStartDate() != null) {
214                        delegate.setAccountDelegateStartDate(new Date(changeDocument.getAccountDelegateStartDate().getTime()));
215                    }
216    
217                    persistables.add(delegate);
218    
219                }
220            }
221    
222            return new ArrayList<PersistableBusinessObject>(persistables);
223        }
224    
225        /**
226         * @see org.kuali.rice.kns.bo.BusinessObjectBase#toStringMapper()
227         */
228        @Override
229        protected LinkedHashMap toStringMapper() {
230    
231            LinkedHashMap m = new LinkedHashMap();
232    
233            m.put(KFSPropertyConstants.DOCUMENT_NUMBER, this.documentNumber);
234            return m;
235        }
236    
237        /**
238         * @see org.kuali.rice.kns.document.GlobalBusinessObject#getDocumentNumber()
239         */
240        public String getDocumentNumber() {
241            return documentNumber;
242        }
243    
244        /**
245         * @see org.kuali.rice.kns.document.GlobalBusinessObject#setDocumentNumber(java.lang.String)
246         */
247        public void setDocumentNumber(String documentNumber) {
248            this.documentNumber = documentNumber;
249    
250        }
251    
252        /**
253         * Gets the accountGlobalDetails attribute.
254         * 
255         * @return Returns the accountGlobalDetails.
256         */
257        public final List<AccountGlobalDetail> getAccountGlobalDetails() {
258            return accountGlobalDetails;
259        }
260    
261        /**
262         * Sets the accountGlobalDetails attribute value.
263         * 
264         * @param accountGlobalDetails The accountGlobalDetails to set.
265         */
266        public final void setAccountGlobalDetails(List<AccountGlobalDetail> accountGlobalDetails) {
267            this.accountGlobalDetails = accountGlobalDetails;
268        }
269    
270        /**
271         * Gets the delegateGlobals attribute.
272         * 
273         * @return Returns the delegateGlobals.
274         */
275        public final List<AccountDelegateGlobalDetail> getDelegateGlobals() {
276            return delegateGlobals;
277        }
278    
279        /**
280         * Sets the delegateGlobals attribute value.
281         * 
282         * @param delegateGlobals The delegateGlobals to set.
283         */
284        public final void setDelegateGlobals(List<AccountDelegateGlobalDetail> delegateGlobals) {
285            this.delegateGlobals = delegateGlobals;
286        }
287    
288        /**
289         * @see org.kuali.rice.kns.document.GlobalBusinessObject#isPersistable()
290         */
291        public boolean isPersistable() {
292            PersistenceStructureService persistenceStructureService = SpringContext.getBean(PersistenceStructureService.class);
293    
294            // fail if the PK for this object is emtpy
295            if (StringUtils.isBlank(documentNumber)) {
296                return false;
297            }
298    
299            // fail if the PKs for any of the contained objects are empty
300            for (AccountDelegateGlobalDetail delegateGlobals : getDelegateGlobals()) {
301                if (!persistenceStructureService.hasPrimaryKeyFieldValues(delegateGlobals)) {
302                    return false;
303                }
304            }
305            for (AccountGlobalDetail account : getAccountGlobalDetails()) {
306                if (!persistenceStructureService.hasPrimaryKeyFieldValues(account)) {
307                    return false;
308                }
309            }
310    
311            // otherwise, its all good
312            return true;
313        }
314    
315        public String getModelName() {
316            return modelName;
317        }
318    
319        public void setModelName(String loadModelName) {
320            this.modelName = loadModelName;
321        }
322    
323        public String getModelChartOfAccountsCode() {
324            return modelChartOfAccountsCode;
325        }
326    
327        public void setModelChartOfAccountsCode(String loadModelChartOfAccountsCode) {
328            this.modelChartOfAccountsCode = loadModelChartOfAccountsCode;
329        }
330    
331        public String getModelOrganizationCode() {
332            return modelOrganizationCode;
333        }
334    
335        public void setModelOrganizationCode(String loadModelOrganizationCode) {
336            this.modelOrganizationCode = loadModelOrganizationCode;
337        }
338    
339        public AccountDelegateModel getModel() {
340            return model;
341        }
342    
343        public void setModel(AccountDelegateModel loadModel) {
344            this.model = loadModel;
345        }
346    
347        public List<? extends GlobalBusinessObjectDetail> getAllDetailObjects() {
348            ArrayList<GlobalBusinessObjectDetail> details = new ArrayList<GlobalBusinessObjectDetail>(accountGlobalDetails.size() + delegateGlobals.size());
349            details.addAll(accountGlobalDetails);
350            details.addAll(delegateGlobals);
351            return details;
352        }
353    
354        @Override
355        public void linkEditableUserFields() {
356            super.linkEditableUserFields();
357            if (this == null) {
358                throw new IllegalArgumentException("globalDelegate parameter passed in was null");
359            }
360            List bos = new ArrayList();
361            bos.addAll(getDelegateGlobals());
362            SpringContext.getBean(BusinessObjectService.class).linkUserFields(bos);
363        }
364    
365        /**
366         * @see org.kuali.rice.kns.bo.PersistableBusinessObjectBase#buildListOfDeletionAwareLists()
367         */
368        @Override
369        public List buildListOfDeletionAwareLists() {
370            List<List> managedLists = super.buildListOfDeletionAwareLists();
371    
372            managedLists.add(getAccountGlobalDetails());
373            managedLists.add(getDelegateGlobals());
374    
375            return managedLists;
376        }
377    }