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.fp.document.service.impl;
017
018 import static org.kuali.kfs.sys.document.validation.impl.AccountingDocumentRuleBaseConstants.ERROR_PATH.DOCUMENT_ERROR_PREFIX;
019
020 import java.util.ArrayList;
021 import java.util.Arrays;
022 import java.util.HashMap;
023 import java.util.Iterator;
024 import java.util.List;
025 import java.util.Map;
026
027 import org.apache.commons.lang.StringUtils;
028 import org.kuali.kfs.fp.businessobject.CashDrawer;
029 import org.kuali.kfs.fp.businessobject.CashieringTransaction;
030 import org.kuali.kfs.fp.businessobject.CoinDetail;
031 import org.kuali.kfs.fp.businessobject.CurrencyDetail;
032 import org.kuali.kfs.fp.document.CashReceiptDocument;
033 import org.kuali.kfs.fp.document.CashReceiptFamilyBase;
034 import org.kuali.kfs.fp.document.dataaccess.CashManagementDao;
035 import org.kuali.kfs.fp.document.service.CashReceiptService;
036 import org.kuali.kfs.fp.service.CashDrawerService;
037 import org.kuali.kfs.sys.KFSConstants;
038 import org.kuali.kfs.sys.KFSKeyConstants;
039 import org.kuali.kfs.sys.KFSPropertyConstants;
040 import org.kuali.kfs.sys.KFSKeyConstants.CashReceipt;
041 import org.kuali.kfs.sys.context.SpringContext;
042 import org.kuali.rice.kew.exception.WorkflowException;
043 import org.kuali.rice.kim.bo.Person;
044 import org.kuali.rice.kns.bo.Campus;
045 import org.kuali.rice.kns.bo.CampusImpl;
046 import org.kuali.rice.kns.bo.DocumentHeader;
047 import org.kuali.rice.kns.exception.InfrastructureException;
048 import org.kuali.rice.kns.service.BusinessObjectService;
049 import org.kuali.rice.kns.service.DataDictionaryService;
050 import org.kuali.rice.kns.service.DictionaryValidationService;
051 import org.kuali.rice.kns.service.KualiModuleService;
052 import org.kuali.rice.kns.service.ParameterService;
053 import org.kuali.rice.kns.util.GlobalVariables;
054 import org.kuali.rice.kns.util.KualiDecimal;
055 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
056 import org.kuali.rice.kns.workflow.service.WorkflowDocumentService;
057 import org.springframework.transaction.annotation.Transactional;
058
059 /**
060 *
061 * This is the default implementation of the CashReceiptService interface.
062 */
063 @Transactional
064 public class CashReceiptServiceImpl implements CashReceiptService {
065
066 private BusinessObjectService businessObjectService;
067 private WorkflowDocumentService workflowDocumentService;
068 private CashManagementDao cashManagementDao;
069 private CashDrawerService cashDrawerService;
070 private ParameterService parameterService;
071 private DictionaryValidationService dictionaryValidationService;
072
073 /**
074 * This method verifies the campus code provided exists. This is done by retrieving all the available campuses from
075 * the BusinessObjectService and then looking for a matching campus code within the result set.
076 *
077 * @param campusCode The campus code to be verified.
078 * @return True if the campus code provided is valid and exists, false otherwise.
079 */
080 protected boolean verifyCampus(String campusCode) {
081 List campusList = SpringContext.getBean(KualiModuleService.class).getResponsibleModuleService(
082 Campus.class).getExternalizableBusinessObjectsList(Campus.class, new HashMap<String, Object>());
083 Iterator campiiIter = campusList.iterator();
084 boolean foundCampus = false;
085 while (campiiIter.hasNext() && !foundCampus) {
086 Campus campus = (Campus)campiiIter.next();
087 if (campus.getCampusCode().equals(campusCode)) {
088 foundCampus = true;
089 }
090 }
091 return foundCampus;
092
093 }
094
095
096 /**
097 * This method retrieves the cash receipt verification unit based on the user provided. This is done by retrieving the campus
098 * code associated with the user provided and then performing the lookup using this campus code.
099 *
100 * @param user The user to be used to retrieve the verification unit.
101 * @return The cash receipt verification unit associated with the user provided.
102 *
103 * @see org.kuali.kfs.fp.document.service.CashReceiptService#getCashReceiptVerificationUnit(org.kuali.rice.kns.bo.user.KualiUser)
104 */
105 public String getCashReceiptVerificationUnitForUser(Person user) {
106 String unitName = null;
107
108 if (user == null) {
109 throw new IllegalArgumentException("invalid (null) user");
110 }
111
112 return user.getCampusCode();
113 }
114
115
116 /**
117 * This method retrieves a collection of cash receipts using the verification unit and the status provided to
118 * retrieve the cash receipts.
119 *
120 * @param verificationUnit The verification unit used to retrieve a collection of associated cash receipts.
121 * @param statusCode The status code of the cash receipts to be retrieved.
122 * @return A collection of cash receipt documents which match the search criteria provided.
123 *
124 * @see org.kuali.kfs.fp.document.service.CashReceiptService#getCashReceipts(java.lang.String, java.lang.String)
125 */
126 public List getCashReceipts(String verificationUnit, String statusCode) {
127 if (StringUtils.isBlank(statusCode)) {
128 throw new IllegalArgumentException("invalid (blank) statusCode");
129 }
130
131 String[] statii = new String[] { statusCode };
132 return getCashReceipts(verificationUnit, statii);
133 }
134
135 /**
136 * This method retrieves a collection of cash receipts using the verification unit and the statuses provided to
137 * retrieve the cash receipts.
138 *
139 * @param verificationUnit The verification unit used to retrieve a collection of associated cash receipts.
140 * @param statii A collection of possible statuses that will be used in the lookup of cash receipts.
141 * @return A collection of cash receipt documents which match the search criteria provided.
142 *
143 * @see org.kuali.kfs.fp.document.service.CashReceiptService#getCashReceipts(java.lang.String, java.lang.String[])
144 */
145 public List getCashReceipts(String verificationUnit, String[] statii) {
146 if (StringUtils.isBlank(verificationUnit)) {
147 throw new IllegalArgumentException("invalid (blank) verificationUnit");
148 }
149 if (statii == null) {
150 throw new IllegalArgumentException("invalid (null) statii");
151 }
152 else {
153 if (statii.length == 0) {
154 throw new IllegalArgumentException("invalid (empty) statii");
155 }
156 else {
157 for (int i = 0; i < statii.length; ++i) {
158 if (StringUtils.isBlank(statii[i])) {
159 throw new IllegalArgumentException("invalid (blank) status code " + i);
160 }
161 }
162 }
163 }
164
165 return getPopulatedCashReceipts(verificationUnit, statii);
166 }
167
168 /**
169 * This method retrieves a populated collection of cash receipts using the lookup parameters provided. A populated
170 * cash receipt document is a cash receipt document with fully populated workflow fields.
171 *
172 * @param verificationUnit The verification unit used to retrieve a collection of associated cash receipts.
173 * @param statii A collection of possible statuses that will be used in the lookup of the cash receipts.
174 * @return List of CashReceiptDocument instances with their associated workflowDocuments populated.
175 */
176 public List getPopulatedCashReceipts(String verificationUnit, String[] statii) {
177 Map queryCriteria = buildCashReceiptCriteriaMap(verificationUnit, statii);
178
179 List documents = new ArrayList(getBusinessObjectService().findMatchingOrderBy(CashReceiptDocument.class, queryCriteria, KFSPropertyConstants.DOCUMENT_NUMBER, true));
180
181 populateWorkflowFields(documents);
182
183 return documents;
184 }
185
186
187 /**
188 * This method builds out a map of search criteria for performing cash receipt lookups using the values provided.
189 *
190 * @param campusCode The campus code to use as search criteria for looking up cash receipts.
191 * @param statii A collection of possible statuses to use as search criteria for looking up cash receipts.
192 * @return The search criteria provided in a map with CashReceiptConstants used as keys to the parameters given.
193 */
194 protected Map buildCashReceiptCriteriaMap(String campusCode, String[] statii) {
195 Map queryCriteria = new HashMap();
196
197 if (statii.length == 1) {
198 queryCriteria.put(KFSConstants.CashReceiptConstants.CASH_RECEIPT_DOC_HEADER_STATUS_CODE_PROPERTY_NAME, statii[0]);
199 }
200 else if (statii.length > 0) {
201 List<String> statusList = Arrays.asList(statii);
202 queryCriteria.put(KFSConstants.CashReceiptConstants.CASH_RECEIPT_DOC_HEADER_STATUS_CODE_PROPERTY_NAME, statusList);
203 }
204
205 queryCriteria.put(KFSConstants.CashReceiptConstants.CASH_RECEIPT_CAMPUS_LOCATION_CODE_PROPERTY_NAME, campusCode);
206
207 return queryCriteria;
208 }
209
210 /**
211 * This method populates the workflowDocument field of each CashReceiptDocument in the given List
212 *
213 * @param documents A collection of CashReceiptDocuments to be populated with workflow document data.
214 */
215 protected void populateWorkflowFields(List documents) {
216 for (Iterator i = documents.iterator(); i.hasNext();) {
217 CashReceiptDocument cr = (CashReceiptDocument) i.next();
218
219 KualiWorkflowDocument workflowDocument = null;
220 DocumentHeader docHeader = cr.getDocumentHeader();
221 try {
222 Long documentHeaderId = Long.valueOf(docHeader.getDocumentNumber());
223 Person user = GlobalVariables.getUserSession().getPerson();
224
225 workflowDocument = getWorkflowDocumentService().createWorkflowDocument(documentHeaderId, user);
226 }
227 catch (WorkflowException e) {
228 throw new InfrastructureException("unable to retrieve workflow document for documentHeaderId '" + docHeader.getDocumentNumber() + "'", e);
229 }
230
231 docHeader.setWorkflowDocument(workflowDocument);
232 }
233 }
234
235 /**
236 * This method retrieves the cash details from the cash receipt document provided and adds those details to the
237 * associated cash drawer. After the details are added to the drawer, the drawer is persisted to the database.
238 *
239 * @param crDoc The cash receipt document the cash details will be retrieved from.
240 *
241 * @see org.kuali.kfs.fp.document.service.CashReceiptService#addCashDetailsToCashDrawer(org.kuali.kfs.fp.document.CashReceiptDocument)
242 */
243 public void addCashDetailsToCashDrawer(CashReceiptDocument crDoc) {
244 CashDrawer drawer = retrieveCashDrawer(crDoc);
245 // we need to to add the currency and coin to the cash management doc's cumulative CR as well
246 if (crDoc.getCurrencyDetail() != null && !crDoc.getCurrencyDetail().isEmpty()) {
247 CurrencyDetail cumulativeCurrencyDetail = cashManagementDao.findCurrencyDetailByCashieringRecordSource(drawer.getReferenceFinancialDocumentNumber(), CashieringTransaction.DETAIL_DOCUMENT_TYPE, KFSConstants.CurrencyCoinSources.CASH_RECEIPTS);
248 cumulativeCurrencyDetail.add(crDoc.getCurrencyDetail());
249 businessObjectService.save(cumulativeCurrencyDetail);
250
251 drawer.addCurrency(crDoc.getCurrencyDetail());
252 }
253 if (crDoc.getCoinDetail() != null && !crDoc.getCoinDetail().isEmpty()) {
254 CoinDetail cumulativeCoinDetail = cashManagementDao.findCoinDetailByCashieringRecordSource(drawer.getReferenceFinancialDocumentNumber(), CashieringTransaction.DETAIL_DOCUMENT_TYPE, KFSConstants.CurrencyCoinSources.CASH_RECEIPTS);
255 cumulativeCoinDetail.add(crDoc.getCoinDetail());
256 businessObjectService.save(cumulativeCoinDetail);
257
258 drawer.addCoin(crDoc.getCoinDetail());
259 }
260 SpringContext.getBean(BusinessObjectService.class).save(drawer);
261 }
262
263 /**
264 * This method finds the appropriate cash drawer for this cash receipt document to add cash to.
265 *
266 * @param crDoc The document the cash drawer will be retrieved from.
267 * @return An instance of a cash drawer associated with the cash receipt document provided.
268 */
269 protected CashDrawer retrieveCashDrawer(CashReceiptDocument crDoc) {
270 String campusCode = crDoc.getCampusLocationCode();
271 if (campusCode == null) {
272 throw new RuntimeException("Cannot find workgroup name for Cash Receipt document: "+crDoc.getDocumentNumber());
273 }
274
275 CashDrawer drawer = cashDrawerService.getByCampusCode(campusCode);
276 if (drawer == null) {
277 throw new RuntimeException("There is no Cash Drawer for Workgroup "+campusCode);
278 }
279 return drawer;
280 }
281
282 /**
283 * @see org.kuali.module.financial.service.CashReceiptTotalsVerificationService#areCashTotalsInvalid(org.kuali.kfs.fp.document.CashReceiptDocument)
284 */
285 public boolean areCashTotalsInvalid(CashReceiptDocument cashReceiptDocument) {
286 String documentEntryName = cashReceiptDocument.getDocumentHeader().getWorkflowDocument().getDocumentType();
287
288 boolean isInvalid = isTotalInvalid(cashReceiptDocument, cashReceiptDocument.getTotalCheckAmount(), documentEntryName, KFSPropertyConstants.TOTAL_CHECK_AMOUNT);
289 isInvalid |= isTotalInvalid(cashReceiptDocument, cashReceiptDocument.getTotalCashAmount(), documentEntryName, KFSPropertyConstants.TOTAL_CASH_AMOUNT);
290 isInvalid |= isTotalInvalid(cashReceiptDocument, cashReceiptDocument.getTotalCoinAmount(), documentEntryName, KFSPropertyConstants.TOTAL_COIN_AMOUNT);
291
292 isInvalid |= isTotalInvalid(cashReceiptDocument, cashReceiptDocument.getTotalDollarAmount(), documentEntryName, KFSPropertyConstants.SUM_TOTAL_AMOUNT);
293
294 return isInvalid;
295 }
296
297 /**
298 * Puts an error message in the error map for that property if the amount is negative.
299 *
300 * @param cashReceiptDocument submitted cash receipt document
301 * @param totalAmount total amount (cash total, check total, etc)
302 * @param documentEntryName document type
303 * @param propertyName property type (i.e totalCashAmount, totalCheckAmount, etc)
304 * @return true if the totalAmount is an invalid value
305 */
306 protected boolean isTotalInvalid(CashReceiptFamilyBase cashReceiptDocument, KualiDecimal totalAmount, String documentEntryName, String propertyName) {
307 boolean isInvalid = false;
308 String errorProperty = DOCUMENT_ERROR_PREFIX + propertyName;
309
310 if (totalAmount != null) {
311 DataDictionaryService dds = SpringContext.getBean(DataDictionaryService.class);
312 String errorLabel = dds.getAttributeLabel(documentEntryName, propertyName);
313
314 if (totalAmount.isNegative()) {
315 GlobalVariables.getMessageMap().putError(errorProperty, CashReceipt.ERROR_NEGATIVE_TOTAL, errorLabel);
316
317 isInvalid = true;
318 }
319 else {
320 int precount = GlobalVariables.getMessageMap().size();
321
322 getDictionaryValidationService().validateDocumentAttribute(cashReceiptDocument, propertyName, DOCUMENT_ERROR_PREFIX);
323
324 // replace generic error message, if any, with something more readable
325 GlobalVariables.getMessageMap().replaceError(errorProperty, KFSKeyConstants.ERROR_MAX_LENGTH, CashReceipt.ERROR_EXCESSIVE_TOTAL, errorLabel);
326
327 int postcount = GlobalVariables.getMessageMap().size();
328 isInvalid = (postcount > precount);
329 }
330 }
331
332 return isInvalid;
333 }
334
335 // injection-molding
336 /**
337 * Gets the businessObjectService attribute.
338 * @return current value of businessObjectService.
339 */
340 public BusinessObjectService getBusinessObjectService() {
341 return businessObjectService;
342 }
343
344 /**
345 * Sets the businessObjectService attribute value.
346 * @param businessObjectService The businessObjectService to set.
347 */
348 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
349 this.businessObjectService = businessObjectService;
350 }
351
352
353 /**
354 * Gets the workflowDocumentService attribute.
355 * @return current value of workflowDocumentService.
356 */
357 public WorkflowDocumentService getWorkflowDocumentService() {
358 return workflowDocumentService;
359 }
360
361 /**
362 * Sets the workflowDocumentService attribute value.
363 * @param workflowDocumentService The workflowDocumentService to set.
364 */
365 public void setWorkflowDocumentService(WorkflowDocumentService workflowDocumentService) {
366 this.workflowDocumentService = workflowDocumentService;
367 }
368
369 /**
370 * Gets the cashManagementDao attribute.
371 *
372 * @return Returns the cashManagementDao.
373 */
374 public CashManagementDao getCashManagementDao() {
375 return cashManagementDao;
376 }
377
378
379 /**
380 * Sets the cashManagementDao attribute value.
381 *
382 * @param cashManagementDao The cashManagementDao to set.
383 */
384 public void setCashManagementDao(CashManagementDao cashManagementDao) {
385 this.cashManagementDao = cashManagementDao;
386 }
387
388 /**
389 * Gets the cashDrawerService attribute.
390 *
391 * @return Returns the cashDrawerService.
392 */
393 public CashDrawerService getCashDrawerService() {
394 return cashDrawerService;
395 }
396
397
398 /**
399 * Sets the cashDrawerService attribute value.
400 *
401 * @param cashDrawerService The cashDrawerService to set.
402 */
403 public void setCashDrawerService(CashDrawerService cashDrawerService) {
404 this.cashDrawerService = cashDrawerService;
405 }
406
407 /**
408 * Gets the parameterService attribute.
409 *
410 * @return Returns the parameterService.
411 */
412 public ParameterService getParameterService() {
413 return parameterService;
414 }
415
416
417 /**
418 * Sets the parameterService attribute value.
419 *
420 * @param parameterService The parameterService to set.
421 */
422 public void setParameterService(ParameterService parameterService) {
423 this.parameterService = parameterService;
424 }
425
426 /**
427 * Gets the dictionaryValidationService attribute.
428 * @return Returns the dictionaryValidationService.
429 */
430 public DictionaryValidationService getDictionaryValidationService() {
431 return dictionaryValidationService;
432 }
433
434 /**
435 * Sets the dictionaryValidationService attribute value.
436 * @param dictionaryValidationService The dictionaryValidationService to set.
437 */
438 public void setDictionaryValidationService(DictionaryValidationService dictionaryValidationService) {
439 this.dictionaryValidationService = dictionaryValidationService;
440 }
441 }
442