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 }