0001: /*
0002: * Copyright 2006-2007 The Kuali Foundation.
0003: *
0004: * Licensed under the Educational Community License, Version 1.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.opensource.org/licenses/ecl1.php
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.kuali.module.financial.service.impl;
0017:
0018: import java.util.ArrayList;
0019: import java.util.HashMap;
0020: import java.util.Iterator;
0021: import java.util.List;
0022: import java.util.Map;
0023:
0024: import org.apache.commons.lang.StringUtils;
0025: import org.kuali.core.bo.DocumentHeader;
0026: import org.kuali.core.bo.user.UniversalUser;
0027: import org.kuali.core.document.authorization.DocumentAuthorizer;
0028: import org.kuali.core.exceptions.InfrastructureException;
0029: import org.kuali.core.service.BusinessObjectService;
0030: import org.kuali.core.service.DataDictionaryService;
0031: import org.kuali.core.service.DateTimeService;
0032: import org.kuali.core.service.DocumentAuthorizationService;
0033: import org.kuali.core.service.DocumentService;
0034: import org.kuali.core.util.GlobalVariables;
0035: import org.kuali.core.util.KualiDecimal;
0036: import org.kuali.kfs.KFSConstants;
0037: import org.kuali.kfs.KFSPropertyConstants;
0038: import org.kuali.kfs.KFSConstants.CashDrawerConstants;
0039: import org.kuali.kfs.KFSConstants.CurrencyCoinSources;
0040: import org.kuali.kfs.KFSConstants.DepositConstants;
0041: import org.kuali.kfs.KFSConstants.DocumentStatusCodes;
0042: import org.kuali.kfs.bo.GeneralLedgerPendingEntry;
0043: import org.kuali.kfs.context.SpringContext;
0044: import org.kuali.module.financial.bo.Bank;
0045: import org.kuali.module.financial.bo.BankAccount;
0046: import org.kuali.module.financial.bo.CashDrawer;
0047: import org.kuali.module.financial.bo.CashReceiptHeader;
0048: import org.kuali.module.financial.bo.CashieringItemInProcess;
0049: import org.kuali.module.financial.bo.CashieringTransaction;
0050: import org.kuali.module.financial.bo.Check;
0051: import org.kuali.module.financial.bo.CoinDetail;
0052: import org.kuali.module.financial.bo.CurrencyDetail;
0053: import org.kuali.module.financial.bo.Deposit;
0054: import org.kuali.module.financial.bo.DepositCashReceiptControl;
0055: import org.kuali.module.financial.dao.CashManagementDao;
0056: import org.kuali.module.financial.document.CashManagementDocument;
0057: import org.kuali.module.financial.document.CashReceiptDocument;
0058: import org.kuali.module.financial.exceptions.CashDrawerStateException;
0059: import org.kuali.module.financial.exceptions.InvalidCashReceiptState;
0060: import org.kuali.module.financial.rules.CashieringTransactionRule;
0061: import org.kuali.module.financial.service.CashDrawerService;
0062: import org.kuali.module.financial.service.CashManagementService;
0063: import org.kuali.module.financial.service.CashReceiptService;
0064: import org.kuali.module.financial.web.struts.form.CashDrawerStatusCodeFormatter;
0065: import org.springframework.transaction.annotation.Transactional;
0066:
0067: import edu.iu.uis.eden.exception.WorkflowException;
0068:
0069: /**
0070: * This is the default implementation of the CashManagementService interface.
0071: */
0072: @Transactional
0073: public class CashManagementServiceImpl implements CashManagementService {
0074: private BusinessObjectService businessObjectService;
0075: private CashDrawerService cashDrawerService;
0076: private DateTimeService dateTimeService;
0077: private DocumentService documentService;
0078: private CashManagementDao cashManagementDao;
0079:
0080: /**
0081: * If a CMD is found that is associated with the CR document, then that CMD is returned; otherwise null is returned.
0082: * Currently the relationships are:
0083: * <ul>
0084: * <li>(CashReceipt to CashReceiptHeader) is (1 to 1)</li>
0085: * <li>(CashReceiptHeader to DepositCashReceiptControl) is (1 to 1)</li>
0086: * <li>(DepositCashReceiptControl to Deposit) is (many to 1)</li>
0087: * <li>(Deposit to CashManagementDocument) is (many to 1)</li>
0088: * </ul>
0089: *
0090: * @param documentId The id of the cash receipt document linked to the cash management document.
0091: * @return An instance of a CashManagementDocument matching the provided search criteria, or null if no value is found.
0092: *
0093: * @see org.kuali.module.financial.service.CashManagementService#getCashManagementDocumentForCashReceiptId(java.lang.String)
0094: */
0095: public CashManagementDocument getCashManagementDocumentForCashReceiptId(
0096: String documentId) {
0097: CashManagementDocument cmdoc = null;
0098:
0099: // get CashReceiptHeader for the CashReceipt, if any
0100: HashMap primaryKeys = new HashMap();
0101: primaryKeys.put(KFSPropertyConstants.DOCUMENT_NUMBER,
0102: documentId);
0103: CashReceiptHeader crh = (CashReceiptHeader) businessObjectService
0104: .findByPrimaryKey(CashReceiptHeader.class, primaryKeys);
0105:
0106: // get the DepositCashReceiptControl for the CashReceiptHeader
0107: if (crh != null) {
0108: List crcList = crh.getDepositCashReceiptControl();
0109: if (!crcList.isEmpty()) {
0110: DepositCashReceiptControl dpcrc = (DepositCashReceiptControl) crcList
0111: .get(0);
0112:
0113: // get the Deposit and follow it to the CashManagementDocument
0114: Deposit d = (Deposit) dpcrc.getDeposit();
0115: cmdoc = d.getCashManagementDocument();
0116: }
0117: }
0118:
0119: return cmdoc;
0120: }
0121:
0122: /**
0123: * This method creates a new cash management document and sets the provided values as attributes to the document.
0124: * The steps followed to create a new cash management document are as follows:
0125: * <ul>
0126: * <li>Find the drawer for the workgroupName given.</li>
0127: * <li>Make sure the drawer is closed, force the drawer closed if it is not already closed.</li>
0128: * <li>Create the cash management document, set the provided values to the document and link it to the cash drawer</li>
0129: * </ul>
0130: *
0131: * If the workgroupName or docDescription values are null, an IllegalArgumentException will be thrown.
0132: *
0133: * TODO - annotation is not used or set at all in this method, remove it if appropriate.
0134: *
0135: * @param workgroupName The workgroup name of the cash drawer.
0136: * @param docDescription The document description to be set on the new cash management document.
0137: * @param annotation
0138: * @return A new instance of a CashManagementDocument (not persisted).
0139: *
0140: * @see org.kuali.module.financial.service.CashManagementService#createCashManagementDocument(java.lang.String,
0141: * java.lang.String, java.lang.String)
0142: */
0143: public CashManagementDocument createCashManagementDocument(
0144: String workgroupName, String docDescription,
0145: String annotation) {
0146: if (StringUtils.isBlank(workgroupName)) {
0147: throw new IllegalArgumentException(
0148: "invalid (blank) workgroupName");
0149: }
0150: if (StringUtils.isBlank(docDescription)) {
0151: throw new IllegalArgumentException(
0152: "invalid (blank) docDescription");
0153: }
0154:
0155: // check user authorization
0156: UniversalUser user = GlobalVariables.getUserSession()
0157: .getUniversalUser();
0158: String documentTypeName = SpringContext.getBean(
0159: DataDictionaryService.class)
0160: .getDocumentTypeNameByClass(
0161: CashManagementDocument.class);
0162: DocumentAuthorizer documentAuthorizer = SpringContext.getBean(
0163: DocumentAuthorizationService.class)
0164: .getDocumentAuthorizer(documentTypeName);
0165: documentAuthorizer.canInitiate(documentTypeName, user);
0166:
0167: // check cash drawer
0168: CashDrawer cd = cashDrawerService.getByWorkgroupName(
0169: workgroupName, true);
0170: String controllingDocId = cd
0171: .getReferenceFinancialDocumentNumber();
0172:
0173: // KULEDOCS-1475: adding handling for two things which should never happen:
0174: // 1. CashDrawer is open or locked by document 'null'
0175: // 2. CashDrawer is open or locked by a document which doesn't exist
0176: if (!cd.isClosed() || cd.getStatusCode() == null) {
0177: boolean forceDrawerClosed = false;
0178:
0179: if (cd.getStatusCode() == null) {
0180: forceDrawerClosed = true;
0181: }
0182:
0183: if (StringUtils.isBlank(controllingDocId)) {
0184: forceDrawerClosed = true;
0185: } else if (!documentService
0186: .documentExists(controllingDocId)) {
0187: forceDrawerClosed = true;
0188: }
0189:
0190: if (forceDrawerClosed) {
0191: cashDrawerService.closeCashDrawer(cd);
0192: cd = cashDrawerService.getByWorkgroupName(
0193: workgroupName, true);
0194: }
0195: }
0196:
0197: CashManagementDocument cmDoc = null;
0198: if (cd.isClosed()) {
0199: // create the document
0200: try {
0201: cmDoc = (CashManagementDocument) documentService
0202: .getNewDocument(CashManagementDocument.class);
0203: cmDoc
0204: .getDocumentHeader()
0205: .setFinancialDocumentDescription(docDescription);
0206: cmDoc.setWorkgroupName(workgroupName);
0207: cmDoc.setCashDrawer(cd);
0208: cmDoc.getCurrentTransaction().setWorkgroupName(
0209: cmDoc.getWorkgroupName());
0210: cmDoc.getCurrentTransaction()
0211: .setReferenceFinancialDocumentNumber(
0212: cmDoc.getDocumentNumber());
0213: cmDoc.getCurrentTransaction().setOpenItemsInProcess(
0214: getOpenItemsInProcess(cmDoc));
0215: } catch (WorkflowException e) {
0216: throw new InfrastructureException(
0217: "unable to create CashManagementDocument", e);
0218: }
0219: } else {
0220: CashDrawerStatusCodeFormatter f = new CashDrawerStatusCodeFormatter();
0221:
0222: throw new CashDrawerStateException(workgroupName,
0223: controllingDocId, (String) f
0224: .format(CashDrawerConstants.STATUS_CLOSED),
0225: (String) f.format(cd.getStatusCode()));
0226: }
0227:
0228: return cmDoc;
0229: }
0230:
0231: /**
0232: * This method creates new cumulative currency and coin details for the document given.
0233: *
0234: * @param cmDoc The cash management document the cumulative details will be associated with.
0235: * @param cashieringSource The cashiering record source for the new details.
0236: */
0237: public void createNewCashDetails(CashManagementDocument cmDoc,
0238: String cashieringSource) {
0239: CoinDetail coinDetail = new CoinDetail();
0240: coinDetail.setDocumentNumber(cmDoc.getDocumentNumber());
0241: coinDetail
0242: .setFinancialDocumentTypeCode(CashieringTransaction.DETAIL_DOCUMENT_TYPE);
0243: coinDetail.setCashieringRecordSource(cashieringSource);
0244: businessObjectService.save(coinDetail);
0245:
0246: CurrencyDetail currencyDetail = new CurrencyDetail();
0247: currencyDetail.setDocumentNumber(cmDoc.getDocumentNumber());
0248: currencyDetail
0249: .setFinancialDocumentTypeCode(CashieringTransaction.DETAIL_DOCUMENT_TYPE);
0250: currencyDetail.setCashieringRecordSource(cashieringSource);
0251: businessObjectService.save(currencyDetail);
0252: }
0253:
0254: /**
0255: * This method adds a new deposit to a the given CashManagementDocument.
0256: * <br/>
0257: * The following steps go into adding a deposit to a cash management document.
0258: * <ul>
0259: * <li>The given deposit parameters are validated.
0260: * <li>The corresponding cash drawer is locked
0261: * <li>The given cashiering check records are turned into check records
0262: * <li>The new deposit is created
0263: * <li>The deposit is added to the cash management document and persisted
0264: * <li>The list of cash receipts are associated with the new deposit
0265: * <li>The deposit is saved again to ensure all links and attributes of the deposit are set appropriately and persisted
0266: * <li>The drawer is unlocked
0267: * <ul>
0268: *
0269: * @param cashManagementDoc The document to have the deposit added to.
0270: * @param depositTicketNumber The ticket number of the deposit being added.
0271: * @param bankAccount The bank account on the deposit.
0272: * @param selectedCashReceipts The collection of cash receipts associated with the new deposit.
0273: * @param selectedCashieringChecks The collection of checks associated with the new deposit.
0274: * @param isFinalDeposit A flag used to identify if a deposit is the final deposit to be added to a cash management document.
0275: *
0276: * @see org.kuali.module.financial.service.CashManagementService#addInterimDeposit(org.kuali.module.financial.document.CashManagementDocument,
0277: * java.lang.String, org.kuali.module.financial.bo.BankAccount, java.util.List)
0278: */
0279: @SuppressWarnings("deprecation")
0280: public void addDeposit(CashManagementDocument cashManagementDoc,
0281: String depositTicketNumber, BankAccount bankAccount,
0282: List selectedCashReceipts, List selectedCashieringChecks,
0283: boolean isFinalDeposit) {
0284: validateDepositParams(cashManagementDoc, bankAccount,
0285: selectedCashReceipts);
0286:
0287: String depositTypeCode = DepositConstants.DEPOSIT_TYPE_INTERIM;
0288: if (isFinalDeposit) {
0289: depositTypeCode = DepositConstants.DEPOSIT_TYPE_FINAL;
0290: }
0291:
0292: // lock the cashDrawer
0293: cashDrawerService
0294: .lockCashDrawer(cashManagementDoc.getCashDrawer(),
0295: cashManagementDoc.getDocumentNumber());
0296:
0297: // turn the list of selected check sequence ids into a list of actual check records
0298: Map<Integer, Check> checks = getUndepositedChecksAsMap(cashManagementDoc);
0299: List<Check> checksToSave = new ArrayList<Check>();
0300: if (selectedCashieringChecks != null) {
0301: for (Object o : selectedCashieringChecks) {
0302: Integer sequenceId = (Integer) o;
0303: Check check = checks.get(sequenceId);
0304: checksToSave.add(check);
0305: }
0306: }
0307:
0308: // create the Deposit
0309: Deposit deposit = buildDeposit(cashManagementDoc,
0310: depositTypeCode, depositTicketNumber, bankAccount,
0311: selectedCashReceipts, checksToSave);
0312:
0313: // attach the deposit to the document
0314: List deposits = cashManagementDoc.getDeposits();
0315: deposits.add(deposit);
0316: documentService.updateDocument(cashManagementDoc);
0317:
0318: // associate the CashReceipts with the deposit
0319: List dccList = new ArrayList();
0320: for (Iterator i = selectedCashReceipts.iterator(); i.hasNext();) {
0321: CashReceiptDocument crDoc = (CashReceiptDocument) i.next();
0322: DocumentHeader dh = crDoc.getDocumentHeader();
0323:
0324: String statusCode = isFinalDeposit ? DocumentStatusCodes.CashReceipt.FINAL
0325: : DocumentStatusCodes.CashReceipt.INTERIM;
0326: dh.setFinancialDocumentStatusCode(statusCode);
0327: documentService.updateDocument(crDoc);
0328:
0329: DepositCashReceiptControl dcc = new DepositCashReceiptControl();
0330: dcc.setFinancialDocumentCashReceiptNumber(crDoc
0331: .getCashReceiptHeader().getDocumentNumber());
0332: dcc.setFinancialDocumentDepositNumber(deposit
0333: .getDocumentNumber());
0334: dcc.setFinancialDocumentDepositLineNumber(deposit
0335: .getFinancialDocumentDepositLineNumber());
0336:
0337: dcc.setCashReceiptHeader(crDoc.getCashReceiptHeader());
0338: dcc.setDeposit(deposit);
0339:
0340: dccList.add(dcc);
0341: }
0342: // crHeaders get saved as side-effect of saving dccs
0343: businessObjectService.save(dccList);
0344:
0345: // make sure all checks have the right deposit line number
0346: for (Check check : checksToSave) {
0347: check.setFinancialDocumentDepositLineNumber(deposit
0348: .getFinancialDocumentDepositLineNumber());
0349: }
0350: businessObjectService.save(checksToSave);
0351:
0352: // unlock the cashDrawer, if needed
0353: if (!isFinalDeposit) {
0354: cashDrawerService.unlockCashDrawer(cashManagementDoc
0355: .getCashDrawer(), cashManagementDoc
0356: .getDocumentNumber());
0357: }
0358: }
0359:
0360: /**
0361: * Validates the given Deposit parameters, throwing various (runtime) exceptions if errors exist.
0362: *
0363: * @param cashManagementDoc The document the deposit will be added to.
0364: * @param bankAccount The bank account of the deposit being added.
0365: * @param selectedCashReceipts The collection of cash receipts associated with the new deposit.
0366: */
0367: private void validateDepositParams(
0368: CashManagementDocument cashManagementDoc,
0369: BankAccount bankAccount,
0370: List<CashReceiptDocument> selectedCashReceipts) {
0371: if (cashManagementDoc == null) {
0372: throw new IllegalArgumentException(
0373: "invalid (null) cashManagementDoc");
0374: } else if (!cashManagementDoc.getDocumentHeader()
0375: .getWorkflowDocument().stateIsSaved()) {
0376: throw new IllegalStateException("cashManagementDoc '"
0377: + cashManagementDoc.getDocumentNumber()
0378: + "' is not in 'saved' state");
0379: } else if (cashManagementDoc.hasFinalDeposit()) {
0380: throw new IllegalStateException("cashManagementDoc '"
0381: + cashManagementDoc.getDocumentNumber()
0382: + "' hasFinalDeposit");
0383: }
0384: if (bankAccount == null) {
0385: throw new IllegalArgumentException(
0386: "invalid (null) bankAccount");
0387: }
0388:
0389: if (selectedCashReceipts == null) {
0390: throw new IllegalArgumentException(
0391: "invalid (null) cashReceipts list");
0392: } else {
0393: for (CashReceiptDocument cashReceipt : selectedCashReceipts) {
0394: String statusCode = cashReceipt.getDocumentHeader()
0395: .getFinancialDocumentStatusCode();
0396: if (!StringUtils.equals(statusCode,
0397: DocumentStatusCodes.CashReceipt.VERIFIED)) {
0398: throw new InvalidCashReceiptState(
0399: "cash receipt document "
0400: + cashReceipt.getDocumentNumber()
0401: + " has a status other than 'verified' ");
0402: }
0403: }
0404: }
0405: }
0406:
0407: /**
0408: *
0409: * This method builds a new deposit object from the parameters provided.
0410: *
0411: * @param cashManagementDoc The cash management document the deposit will be added to.
0412: * @param depositTypeCode The type code associated with the deposit.
0413: * @param depositTicketNumber The deposit ticket number to be set on the deposit object.
0414: * @param bankAccount The bank account of the deposit.
0415: * @param selectedCashReceipts The cash receipts that make up the deposit.
0416: * @param selectedCashieringChecks The cashiering checks that make up the deposit.
0417: * @return A new instance of a deposit generated from all the parameters provided.
0418: */
0419: private Deposit buildDeposit(
0420: CashManagementDocument cashManagementDoc,
0421: String depositTypeCode, String depositTicketNumber,
0422: BankAccount bankAccount,
0423: List<CashReceiptDocument> selectedCashReceipts,
0424: List selectedCashieringChecks) {
0425: Deposit deposit = new Deposit();
0426: deposit
0427: .setDocumentNumber(cashManagementDoc
0428: .getDocumentNumber());
0429: deposit.setCashManagementDocument(cashManagementDoc);
0430:
0431: deposit.setDepositTypeCode(depositTypeCode);
0432:
0433: deposit.setDepositDate(dateTimeService.getCurrentSqlDate());
0434:
0435: deposit.setBankAccount(bankAccount);
0436: deposit.setDepositBankCode(bankAccount.getBank()
0437: .getFinancialDocumentBankCode());
0438: deposit.setDepositBankAccountNumber(bankAccount
0439: .getFinDocumentBankAccountNumber());
0440:
0441: // derive the line number
0442: int lineNumber = cashManagementDoc.getNextDepositLineNumber();
0443: deposit.setFinancialDocumentDepositLineNumber(new Integer(
0444: lineNumber));
0445:
0446: // trim depositTicketNumber to empty, because the field is optional
0447: deposit.setDepositTicketNumber(StringUtils
0448: .trimToEmpty(depositTicketNumber));
0449:
0450: // total up the cash receipts
0451: KualiDecimal total = KualiDecimal.ZERO;
0452: for (Iterator i = selectedCashReceipts.iterator(); i.hasNext();) {
0453: CashReceiptDocument crDoc = (CashReceiptDocument) i.next();
0454: total = total.add(crDoc.getTotalCheckAmount());
0455: }
0456: Check currCheck;
0457: for (Object checkObj : selectedCashieringChecks) {
0458: currCheck = (Check) checkObj;
0459: total = total.add(currCheck.getAmount());
0460: }
0461: deposit.setDepositAmount(total);
0462:
0463: return deposit;
0464: }
0465:
0466: /**
0467: * Performs a lookup of the Bank using the bank code provided.
0468: *
0469: * @param bankCode The bank code used to identify the Bank.
0470: * @return Bank associated with the given bankCode, or null if none is found.
0471: */
0472: private Bank lookupBank(String bankCode) {
0473: Map keyMap = new HashMap();
0474: keyMap.put("financialDocumentBankCode", bankCode);
0475:
0476: Bank bank = (Bank) businessObjectService.findByPrimaryKey(
0477: Bank.class, keyMap);
0478: return bank;
0479: }
0480:
0481: /**
0482: * Performs a lookup of a BankAccount using the bank code and account number provided.
0483: *
0484: * @param bankCode The bank code used to identify the Bank.
0485: * @param accountNumber The account number used to identify the Account.
0486: * @return BankAccount associated with the given bankCode and accountNumber, or null if none is found.
0487: */
0488: private BankAccount lookupBankAccount(String bankCode,
0489: String accountNumber) {
0490: Map keyMap = new HashMap();
0491: keyMap.put("financialDocumentBankCode", bankCode);
0492: keyMap.put("finDocumentBankAccountNumber", accountNumber);
0493:
0494: BankAccount bankAccount = (BankAccount) businessObjectService
0495: .findByPrimaryKey(BankAccount.class, keyMap);
0496: return bankAccount;
0497: }
0498:
0499: /**
0500: * This method returns all undeposited checks as a map with the key of each value in the map equal to the sequence id
0501: * of the corresponding check.
0502: *
0503: * @param cmDoc The cash management doc to find undeposited checks for.
0504: * @return A map of checks keyed on sequence id.
0505: */
0506: private Map<Integer, Check> getUndepositedChecksAsMap(
0507: CashManagementDocument cmDoc) {
0508: Map<Integer, Check> checks = new HashMap<Integer, Check>();
0509: List<Check> checkList = cashManagementDao
0510: .selectUndepositedCashieringChecks(cmDoc
0511: .getDocumentNumber());
0512: if (checkList != null && checkList.size() > 0) {
0513: for (Check check : checkList) {
0514: checks.put(check.getSequenceId(), check);
0515: }
0516: }
0517: return checks;
0518: }
0519:
0520: /**
0521: * This method cancels a cash management document, effectively nullifying all values and attributes associated with
0522: * the document. Canceling a CashManagementDocument results in the following:
0523: * <ul>
0524: * <li>Cancels (deletes) all deposits associated with the document.</li>
0525: * <li>Recloses the drawer</li>
0526: * <li>Remove all currency and coin records generated by the document.</li>
0527: * </ul>
0528: * <br>
0529: * NOTE: Method should only be called after the appropriate CashManagementDocumentRule has been successfully passed.
0530: *
0531: * @param cmDoc The CashManagementDocument to be canceled.
0532: *
0533: * @see org.kuali.module.financial.service.CashManagementService#cancelCashManagementDocument(org.kuali.module.financial.document.CashManagementDocument)
0534: */
0535: public void cancelCashManagementDocument(
0536: CashManagementDocument cmDoc) {
0537: if (cmDoc == null) {
0538: throw new IllegalArgumentException(
0539: "invalid (null) CashManagementDocument");
0540: }
0541:
0542: // cancel each deposit (which also deletes the records connecting the Deposit to a CashManagementDoc
0543: List deposits = cmDoc.getDeposits();
0544: for (Iterator i = deposits.iterator(); i.hasNext();) {
0545: Deposit deposit = (Deposit) i.next();
0546:
0547: cancelDeposit(deposit);
0548: }
0549:
0550: // reclose the cashDrawer
0551: String unitName = cmDoc.getWorkgroupName();
0552: cashDrawerService.closeCashDrawer(cmDoc.getCashDrawer());
0553:
0554: // cleanup the CMDoc, but let the postprocessor itself save it
0555: cmDoc.setDeposits(new ArrayList());
0556: cmDoc.getDocumentHeader().setFinancialDocumentStatusCode(
0557: DocumentStatusCodes.CANCELLED);
0558:
0559: // kill off cumulative currency/coin detail records for this document (canceling the deposits kills the deposit records)
0560: String[] cashieringSourcesToDelete = {
0561: KFSConstants.CurrencyCoinSources.CASH_RECEIPTS,
0562: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
0563: KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN,
0564: KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_OUT };
0565: for (String cashieringSourceToDelete : cashieringSourcesToDelete) {
0566: CurrencyDetail currencyDetail = cashManagementDao
0567: .findCurrencyDetailByCashieringRecordSource(cmDoc
0568: .getDocumentNumber(),
0569: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
0570: cashieringSourceToDelete);
0571: if (currencyDetail != null) {
0572: businessObjectService.delete(currencyDetail);
0573: }
0574: CoinDetail coinDetail = cashManagementDao
0575: .findCoinDetailByCashieringRecordSource(cmDoc
0576: .getDocumentNumber(),
0577: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
0578: cashieringSourceToDelete);
0579: if (coinDetail != null) {
0580: businessObjectService.delete(coinDetail);
0581: }
0582: }
0583: }
0584:
0585: /**
0586: * This method cancels a given deposit. This equates to the following:
0587: * <ul>
0588: * <li>Resetting all associated CashReceipts to a state of VERIFIED.</li>
0589: * <li>Update all associated cashiering checks to a be un-deposited.</li>
0590: * <li>Unlock the cash drawer if needed.</li>
0591: * <li>Delete the deposit.</li>
0592: * </ul>
0593: *
0594: * @see org.kuali.module.financial.service.CashManagementService#cancelDeposit(org.kuali.module.financial.bo.Deposit)
0595: */
0596: public void cancelDeposit(Deposit deposit) {
0597: if (deposit == null) {
0598: throw new IllegalArgumentException("invalid (null) deposit");
0599: }
0600:
0601: // reload it, to forestall OptimisticLockExceptions
0602: deposit.refresh();
0603:
0604: // save workgroup name, for possible later use
0605: String depositWorkgroup = deposit.getCashManagementDocument()
0606: .getWorkgroupName();
0607:
0608: // update every CashReceipt associated with this Deposit
0609: List depositCashReceiptControls = deposit
0610: .getDepositCashReceiptControl();
0611: for (Iterator j = depositCashReceiptControls.iterator(); j
0612: .hasNext();) {
0613: DepositCashReceiptControl dcc = (DepositCashReceiptControl) j
0614: .next();
0615: CashReceiptHeader crHeader = dcc.getCashReceiptHeader();
0616:
0617: // reset each CashReceipt status
0618: CashReceiptDocument crDoc = crHeader
0619: .getCashReceiptDocument();
0620: DocumentHeader crdh = crDoc.getDocumentHeader();
0621: crdh
0622: .setFinancialDocumentStatusCode(DocumentStatusCodes.CashReceipt.VERIFIED);
0623: documentService.updateDocument(crDoc);
0624: }
0625:
0626: // un-deposit all cashiering checks associated with the deposit
0627: List<Check> depositedChecks = selectCashieringChecksForDeposit(
0628: deposit.getDocumentNumber(), deposit
0629: .getFinancialDocumentDepositLineNumber());
0630: for (Check check : depositedChecks) {
0631: check.setFinancialDocumentDepositLineNumber(null);
0632: }
0633: businessObjectService.save(depositedChecks);
0634:
0635: // unlock the cashDrawer, if needed
0636: if (deposit.getDepositTypeCode() == DepositConstants.DEPOSIT_TYPE_FINAL) {
0637: CashDrawer drawer = cashDrawerService.getByWorkgroupName(
0638: deposit.getCashManagementDocument()
0639: .getWorkgroupName(), false);
0640: CurrencyDetail currencyDetail = cashManagementDao
0641: .findCurrencyDetailByCashieringRecordSource(deposit
0642: .getCashManagementDocument()
0643: .getDocumentNumber(),
0644: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
0645: KFSConstants.CurrencyCoinSources.DEPOSITS);
0646: if (currencyDetail != null) {
0647: drawer.addCurrency(currencyDetail);
0648: businessObjectService.delete(currencyDetail);
0649: }
0650: CoinDetail coinDetail = cashManagementDao
0651: .findCoinDetailByCashieringRecordSource(deposit
0652: .getCashManagementDocument()
0653: .getDocumentNumber(),
0654: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
0655: KFSConstants.CurrencyCoinSources.DEPOSITS);
0656: if (coinDetail != null) {
0657: drawer.addCoin(coinDetail);
0658: businessObjectService.delete(coinDetail);
0659: }
0660: businessObjectService.save(drawer);
0661: cashDrawerService.unlockCashDrawer(drawer, deposit
0662: .getDocumentNumber());
0663: }
0664:
0665: // delete the Deposit from the database
0666: businessObjectService.delete(deposit);
0667: }
0668:
0669: /**
0670: * This method performs the necessary steps to finalize a cash management document. These steps include:
0671: * <ul>
0672: * <li>Finalize all associated cash receipts.
0673: * <li>Generate the master currency and coin details and persist them.
0674: * <li>Update the CashManagementDocument status to APPROVED.
0675: * </ul>
0676: *
0677: * <br>
0678: * NOTE: Method should only be called after the appropriate CashManagementDocumentRule has been successfully passed
0679: *
0680: * @param cmDoc The CashManagementDocument to be finalized.
0681: *
0682: * @see org.kuali.module.financial.service.CashManagementService#finalizeCashManagementDocument(org.kuali.module.financial.document.CashManagementDocument)
0683: */
0684: public void finalizeCashManagementDocument(
0685: CashManagementDocument cmDoc) {
0686: if (cmDoc == null) {
0687: throw new IllegalArgumentException(
0688: "invalid (null) CashManagementDocument");
0689: }
0690: if (!cmDoc.hasFinalDeposit()) {
0691: throw new IllegalStateException("cmDoc "
0692: + cmDoc.getDocumentNumber()
0693: + " is missing a FinalDeposit");
0694: }
0695:
0696: String workgroupName = cmDoc.getWorkgroupName();
0697: cashDrawerService.closeCashDrawer(workgroupName);
0698: CashDrawer cd = cashDrawerService.getByWorkgroupName(
0699: workgroupName, false);
0700:
0701: // finalize the CashReceipts
0702: List<Deposit> deposits = cmDoc.getDeposits();
0703: for (Deposit deposit : deposits) {
0704: List<CashReceiptDocument> receipts = retrieveCashReceipts(deposit);
0705: for (CashReceiptDocument receipt : receipts) {
0706: // marks GLPEs of CRs as APPROVED
0707: for (GeneralLedgerPendingEntry glpe : receipt
0708: .getGeneralLedgerPendingEntries()) {
0709: glpe
0710: .setFinancialDocumentApprovedCode(DocumentStatusCodes.APPROVED);
0711: }
0712:
0713: // mark CRs themselves as APPROVED
0714: receipt.getDocumentHeader()
0715: .setFinancialDocumentStatusCode(
0716: DocumentStatusCodes.APPROVED);
0717:
0718: // persist
0719: documentService.updateDocument(receipt);
0720: }
0721: }
0722:
0723: // generate the master currency and coin details; save those
0724: CurrencyDetail masterCurrencyDetail = this
0725: .generateMasterCurrencyDetail(cmDoc);
0726: businessObjectService.save(masterCurrencyDetail);
0727: CoinDetail masterCoinDetail = this
0728: .generateMasterCoinDetail(cmDoc);
0729: businessObjectService.save(masterCoinDetail);
0730:
0731: // finalize the CMDoc, but let the postprocessor save it
0732: cmDoc.getDocumentHeader().setFinancialDocumentStatusCode(
0733: DocumentStatusCodes.APPROVED);
0734: }
0735:
0736: /**
0737: * This method verifies that all cash receipts for the document are deposited.
0738: *
0739: * @param cmDoc The cash management document to verify.
0740: * @return True if all CashReceipts are deposited, false otherwise.
0741: */
0742: public boolean allVerifiedCashReceiptsAreDeposited(
0743: CashManagementDocument cmDoc) {
0744: boolean result = true;
0745: List verifiedReceipts = SpringContext.getBean(
0746: CashReceiptService.class).getCashReceipts(
0747: cmDoc.getWorkgroupName(),
0748: KFSConstants.DocumentStatusCodes.CashReceipt.VERIFIED);
0749: for (Object o : verifiedReceipts) {
0750: if (!verifyCashReceiptIsDeposited(cmDoc,
0751: (CashReceiptDocument) o)) {
0752: result = false;
0753: break;
0754: }
0755: }
0756: return result;
0757: }
0758:
0759: /**
0760: * This method returns a collection of cash receipts associated with the deposit given.
0761: *
0762: * @param deposit The deposit to retrieve all the cash receipts for.
0763: * @return A collection of cash receipts associated with the deposit given.
0764: *
0765: * @see org.kuali.module.financial.service.CashManagementService#retrieveCashReceipts(org.kuali.module.financial.bo.Deposit)
0766: */
0767: public List retrieveCashReceipts(Deposit deposit) {
0768: List cashReceiptDocuments = null;
0769:
0770: // retrieve CashReceiptHeaders
0771: Map criteriaMap = new HashMap();
0772: criteriaMap
0773: .put(
0774: "depositCashReceiptControl.financialDocumentDepositNumber",
0775: deposit.getDocumentNumber());
0776: criteriaMap
0777: .put(
0778: "depositCashReceiptControl.financialDocumentDepositLineNumber",
0779: deposit.getFinancialDocumentDepositLineNumber());
0780:
0781: List crHeaders = new ArrayList(businessObjectService
0782: .findMatching(CashReceiptHeader.class, criteriaMap));
0783: if (!crHeaders.isEmpty()) {
0784: List idList = new ArrayList();
0785: for (Iterator i = crHeaders.iterator(); i.hasNext();) {
0786: CashReceiptHeader crHeader = (CashReceiptHeader) i
0787: .next();
0788: idList.add(crHeader.getDocumentNumber());
0789: }
0790:
0791: try {
0792: cashReceiptDocuments = documentService
0793: .getDocumentsByListOfDocumentHeaderIds(
0794: CashReceiptDocument.class, idList);
0795: } catch (WorkflowException e) {
0796: throw new InfrastructureException(
0797: "unable to retrieve cashReceipts", e);
0798: }
0799: } else {
0800: cashReceiptDocuments = new ArrayList();
0801: }
0802:
0803: return cashReceiptDocuments;
0804: }
0805:
0806: /**
0807: * Verifies if a given cash receipt is deposited as part of the given cash management document.
0808: *
0809: * @param cmDoc The cash management document to search through.
0810: * @param crDoc The cash receipt to check the deposited status of.
0811: * @return True if the given cash receipt document is deposited as part of the given cash management document, false otherwise.
0812: */
0813: public boolean verifyCashReceiptIsDeposited(
0814: CashManagementDocument cmDoc, CashReceiptDocument crDoc) {
0815: boolean this CRDeposited = false;
0816: for (Deposit deposit : cmDoc.getDeposits()) {
0817: if (deposit.containsCashReceipt(crDoc)) {
0818: this CRDeposited = true;
0819: break;
0820: }
0821: }
0822: return this CRDeposited;
0823: }
0824:
0825: /**
0826: * This method turns the last interim deposit into the final deposit and locks the cash drawer. A deposit is turned into
0827: * a final deposit by updating the deposit type code.
0828: * <br>
0829: * NOTE: This method throws an IllegalStateException if a final deposit already exists for this document or if there
0830: * are any undeposited cash receipts.
0831: *
0832: * @param cmDoc The cash management document to take deposits from for finalization.
0833: */
0834: public void finalizeLastInterimDeposit(CashManagementDocument cmDoc) {
0835: // if there's already a final deposit, throw an IllegalStateException
0836: if (cmDoc.hasFinalDeposit()) {
0837: throw new IllegalStateException("CashManagementDocument #"
0838: + cmDoc.getDocumentNumber()
0839: + " already has a final deposit");
0840: }
0841: // if there are still verified un-deposited cash receipts, throw an IllegalStateException
0842: List verifiedReceipts = SpringContext.getBean(
0843: CashReceiptService.class).getCashReceipts(
0844: cmDoc.getWorkgroupName(),
0845: KFSConstants.DocumentStatusCodes.CashReceipt.VERIFIED);
0846: for (Object o : verifiedReceipts) {
0847: CashReceiptDocument crDoc = (CashReceiptDocument) o;
0848: if (!verifyCashReceiptIsDeposited(cmDoc, crDoc)) {
0849: throw new IllegalStateException(
0850: "Verified Cash Receipt Document #"
0851: + crDoc.getDocumentNumber()
0852: + " must be deposited for this to be a final deposit");
0853: }
0854: }
0855: // lock the cash drawer
0856: cashDrawerService.lockCashDrawer(cmDoc.getCashDrawer(), cmDoc
0857: .getDocumentNumber());
0858:
0859: // change the deposit type code for the last deposit
0860: List<Deposit> allDeposits = cmDoc.getDeposits();
0861: Deposit lastInterim = allDeposits.get(allDeposits.size() - 1);
0862: lastInterim
0863: .setDepositTypeCode(DepositConstants.DEPOSIT_TYPE_FINAL);
0864: finalizeCashReceiptsForDeposit(lastInterim);
0865: documentService.updateDocument(cmDoc);
0866: }
0867:
0868: /**
0869: * This method switches cash receipts to "final" status as opposed to "interim" status.
0870: *
0871: * @param deposit The deposit the cash receipts are associated with.
0872: */
0873: private void finalizeCashReceiptsForDeposit(Deposit deposit) {
0874: List cashReceipts = this .retrieveCashReceipts(deposit);
0875: for (Object o : cashReceipts) {
0876: CashReceiptDocument crDoc = (CashReceiptDocument) o;
0877: crDoc.getDocumentHeader().setFinancialDocumentStatusCode(
0878: KFSConstants.DocumentStatusCodes.CashReceipt.FINAL);
0879: documentService.updateDocument(crDoc);
0880: }
0881: }
0882:
0883: /**
0884: * This method applies the cashiering transaction to the given CashManagementDocument. This is accomplished by
0885: * retrieving a CashieringTransactionRule object and running the appropriate methods to process the cashiering
0886: * application rules.
0887: *
0888: * @see org.kuali.module.financial.service.CashManagementService#applyCashieringTransaction(org.kuali.module.financial.document.CashManagementDocument, org.kuali.module.financial.bo.CashieringTransaction)
0889: * @see org.kuali.module.financial.rules.CashieringTransactionRule#processCashieringTransactionApplicationRules(CashManagementDocument)
0890: */
0891: public void applyCashieringTransaction(CashManagementDocument cmDoc) {
0892: if (cmDoc.getCashDrawer() == null) {
0893: cmDoc.setCashDrawer(cashDrawerService.getByWorkgroupName(
0894: cmDoc.getWorkgroupName(), false));
0895: }
0896: CashieringTransactionRule transactionRule = new CashieringTransactionRule();
0897: transactionRule.setCashDrawerService(cashDrawerService);
0898: if (transactionRule
0899: .processCashieringTransactionApplicationRules(cmDoc)) {
0900: this .transferChecksToCashManagementDocument(cmDoc, cmDoc
0901: .getCurrentTransaction());
0902: this .saveChecks(cmDoc);
0903: this
0904: .completeNewItemInProcess(cmDoc
0905: .getCurrentTransaction());
0906: if (cmDoc.getCurrentTransaction().getNewItemInProcess() != null) {
0907: this .saveNewItemInProcess(cmDoc, cmDoc
0908: .getCurrentTransaction());
0909: }
0910: this .saveExisingItemsInProcess(cmDoc, cmDoc
0911: .getCurrentTransaction());
0912: this .saveMoneyInCash(cmDoc, cmDoc.getCurrentTransaction());
0913: this .saveMoneyOutCash(cmDoc, cmDoc.getCurrentTransaction());
0914: this .updateCashDrawer(cmDoc.getCashDrawer(), cmDoc
0915: .getCurrentTransaction());
0916: cmDoc.resetCurrentTransaction();
0917: }
0918: }
0919:
0920: /**
0921: * This method puts money from the "money in" portion of the transaction into the cash drawer, and takes money from the
0922: * "money out" portion of the cash drawer out.
0923: *
0924: * @param drawer The cash drawer to operate on.
0925: * @param trans The transaction that is the operation.
0926: */
0927: private void updateCashDrawer(CashDrawer drawer,
0928: CashieringTransaction trans) {
0929: // add money in to cash drawer
0930: if (!trans.getMoneyInCurrency().isEmpty()) {
0931: drawer.addCurrency(trans.getMoneyInCurrency());
0932: }
0933: if (!trans.getMoneyInCoin().isEmpty()) {
0934: drawer.addCoin(trans.getMoneyInCoin());
0935: }
0936:
0937: // subtract money out from cash drawer
0938: if (!trans.getMoneyOutCurrency().isEmpty()) {
0939: drawer.removeCurrency(trans.getMoneyOutCurrency());
0940: }
0941: if (!trans.getMoneyOutCoin().isEmpty()) {
0942: drawer.removeCoin(trans.getMoneyOutCoin());
0943: }
0944:
0945: businessObjectService.save(drawer);
0946: }
0947:
0948: /**
0949: *
0950: * This method completes the new item in process by setting the item remaining amount equal to the item amount.
0951: *
0952: * @param trans The transaction being performed.
0953: */
0954: private void completeNewItemInProcess(CashieringTransaction trans) {
0955: if (trans.getNewItemInProcess().isPopulated()) {
0956: trans.getNewItemInProcess().setItemRemainingAmount(
0957: trans.getNewItemInProcess().getItemAmount());
0958: } else {
0959: trans.setNewItemInProcess(null); // we don't want to save it or deal with it
0960: }
0961: }
0962:
0963: /**
0964: *
0965: * This method retrieves all the checks for the given document and persists them.
0966: *
0967: * @param cmDoc The cash management document the checks will be saved against.
0968: */
0969: private void saveChecks(CashManagementDocument cmDoc) {
0970: if (cmDoc.getChecks() != null) {
0971: for (Check check : cmDoc.getChecks()) {
0972: check.setDocumentNumber(cmDoc.getDocumentNumber());
0973: check
0974: .setFinancialDocumentTypeCode(CashieringTransaction.DETAIL_DOCUMENT_TYPE);
0975: check
0976: .setCashieringRecordSource(KFSConstants.CheckSources.CASH_MANAGEMENT);
0977: businessObjectService.save(check);
0978: }
0979: }
0980: }
0981:
0982: /**
0983: *
0984: * This method retrieves the checks from the transaction and adds them to the cash management document.
0985: *
0986: * @param cmDoc The document the checks will be transferred to.
0987: * @param trans The transaction the checks are associated with.
0988: */
0989: private void transferChecksToCashManagementDocument(
0990: CashManagementDocument cmDoc, CashieringTransaction trans) {
0991: for (Check check : trans.getMoneyInChecks()) {
0992: check
0993: .setFinancialDocumentTypeCode(CashieringTransaction.DETAIL_DOCUMENT_TYPE);
0994: check
0995: .setCashieringRecordSource(KFSConstants.CheckSources.CASH_MANAGEMENT);
0996: check.setDocumentNumber(cmDoc.getDocumentNumber());
0997: cmDoc.addCheck(check);
0998: }
0999: }
1000:
1001: /**
1002: * This methods checks if data was actually entered for the new item in process; if so, it saves that item in process.
1003: *
1004: * @param cmDoc The cash management doc that the new item in process will be associated with.
1005: * @param trans The cashiering transaction that created the new item in process.
1006: */
1007: private void saveNewItemInProcess(CashManagementDocument cmDoc,
1008: CashieringTransaction trans) {
1009: if (trans.getNewItemInProcess().isPopulated()) {
1010: trans.getNewItemInProcess().setItemRemainingAmount(
1011: trans.getNewItemInProcess().getItemAmount());
1012: trans.getNewItemInProcess().setItemReducedAmount(
1013: KualiDecimal.ZERO);
1014: trans.getNewItemInProcess().setWorkgroupName(
1015: cmDoc.getWorkgroupName());
1016: businessObjectService.save(trans.getNewItemInProcess());
1017:
1018: // put it in the list of open items in process
1019: trans.getOpenItemsInProcess().add(
1020: trans.getNewItemInProcess());
1021:
1022: CashDrawer drawer = cmDoc.getCashDrawer();
1023: if (drawer.getFinancialDocumentMiscellaneousAdvanceAmount() == null) {
1024: drawer
1025: .setFinancialDocumentMiscellaneousAdvanceAmount(trans
1026: .getNewItemInProcess().getItemAmount());
1027: } else {
1028: drawer
1029: .setFinancialDocumentMiscellaneousAdvanceAmount(drawer
1030: .getFinancialDocumentMiscellaneousAdvanceAmount()
1031: .add(
1032: trans.getNewItemInProcess()
1033: .getItemAmount()));
1034: }
1035: }
1036: }
1037:
1038: /**
1039: * This method checks the cashiering transaction to see if any open items in process were at least partially paid back;
1040: * it then saves the changes.
1041: *
1042: * @param cmDoc The cash management document that the items in process will be associated with
1043: * @param trans The cashiering transaction the items in process are associated with.
1044: */
1045: private void saveExisingItemsInProcess(
1046: CashManagementDocument cmDoc, CashieringTransaction trans) {
1047: if (trans.getOpenItemsInProcess() != null) {
1048: CashDrawer drawer = cmDoc.getCashDrawer();
1049:
1050: for (CashieringItemInProcess itemInProc : trans
1051: .getOpenItemsInProcess()) {
1052: if (itemInProc.getCurrentPayment() != null
1053: && !itemInProc.getCurrentPayment().equals(
1054: KualiDecimal.ZERO)) {
1055: itemInProc.setItemRemainingAmount(itemInProc
1056: .getItemRemainingAmount().subtract(
1057: itemInProc.getCurrentPayment()));
1058: itemInProc.setItemReducedAmount(itemInProc
1059: .getItemReducedAmount().add(
1060: itemInProc.getCurrentPayment()));
1061: if (drawer
1062: .getFinancialDocumentMiscellaneousAdvanceAmount() != null) {
1063: drawer
1064: .setFinancialDocumentMiscellaneousAdvanceAmount(drawer
1065: .getFinancialDocumentMiscellaneousAdvanceAmount()
1066: .subtract(
1067: itemInProc
1068: .getCurrentPayment()));
1069: }
1070: itemInProc.setCurrentPayment(new KualiDecimal(0));
1071: if (itemInProc.getItemRemainingAmount().equals(
1072: KualiDecimal.ZERO)) {
1073: itemInProc.setItemClosedDate(new java.sql.Date(
1074: SpringContext.getBean(
1075: DateTimeService.class)
1076: .getCurrentDate().getTime()));
1077: }
1078: businessObjectService.save(itemInProc);
1079: }
1080: }
1081: }
1082: }
1083:
1084: /**
1085: *
1086: * This method retrieves the amount of cash in the "money in" portion of the transaction and saves it to the
1087: * cash management document.
1088: *
1089: * @param cmDoc The cash management document that the cash will be saved to.
1090: * @param trans The cashiering transaction the cash is currently associated with.
1091: */
1092: private void saveMoneyInCash(CashManagementDocument cmDoc,
1093: CashieringTransaction trans) {
1094: // get the cumulative money in coin for this doc
1095: CoinDetail cumulativeMoneyInCoin = cashManagementDao
1096: .findCoinDetailByCashieringRecordSource(
1097: cmDoc.getDocumentNumber(),
1098: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1099: KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN);
1100: // add the new money in coin
1101: cumulativeMoneyInCoin.add(trans.getMoneyInCoin());
1102: // save the cumulative
1103: businessObjectService.save(cumulativeMoneyInCoin);
1104:
1105: CurrencyDetail cumulativeMoneyInCurrency = cashManagementDao
1106: .findCurrencyDetailByCashieringRecordSource(
1107: cmDoc.getDocumentNumber(),
1108: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1109: KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN);
1110: cumulativeMoneyInCurrency.add(trans.getMoneyInCurrency());
1111: businessObjectService.save(cumulativeMoneyInCurrency);
1112: }
1113:
1114: /**
1115: *
1116: * This method retrieves the amount of cash in the "money out" portion of the transaction and saves it to the
1117: * cash management document.
1118: *
1119: * @param cmDoc The cash management document that the cash will be saved to.
1120: * @param trans The cashiering transaction the cash is currently associated with.
1121: */
1122: private void saveMoneyOutCash(CashManagementDocument cmDoc,
1123: CashieringTransaction trans) {
1124: CoinDetail cumulativeMoneyOutCoin = cashManagementDao
1125: .findCoinDetailByCashieringRecordSource(
1126: cmDoc.getDocumentNumber(),
1127: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1128: KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_OUT);
1129: cumulativeMoneyOutCoin.add(trans.getMoneyOutCoin());
1130: businessObjectService.save(cumulativeMoneyOutCoin);
1131:
1132: CurrencyDetail cumulativeMoneyOutCurrency = cashManagementDao
1133: .findCurrencyDetailByCashieringRecordSource(
1134: cmDoc.getDocumentNumber(),
1135: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1136: KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_OUT);
1137: cumulativeMoneyOutCurrency.add(trans.getMoneyOutCurrency());
1138: businessObjectService.save(cumulativeMoneyOutCurrency);
1139: }
1140:
1141: /**
1142: * This method retrieves a collection of open CashieringItemInProcess objects from the cash management document given
1143: * and returns that collection.
1144: *
1145: * @param cmDoc The document the open items in process will be retrieved from.
1146: * @return The collection of open items.
1147: *
1148: * @see org.kuali.module.financial.service.CashManagementService#getOpenItemsInProcess(org.kuali.module.financial.document.CashManagementDocument)
1149: */
1150: public List<CashieringItemInProcess> getOpenItemsInProcess(
1151: CashManagementDocument cmDoc) {
1152: List<CashieringItemInProcess> itemsInProcess = cashManagementDao
1153: .findOpenItemsInProcessByWorkgroupName(cmDoc
1154: .getWorkgroupName());
1155: return (itemsInProcess == null) ? new ArrayList<CashieringItemInProcess>()
1156: : itemsInProcess;
1157: }
1158:
1159: /**
1160: * This method retrieves a collection of recently closed CashieringItemInProcess objects from the cash management
1161: * document given and returns the collection.
1162: *
1163: * @param cmDoc The cash management document the recently closed items will be retrieved from.
1164: * @return The collection of recently closed items.
1165: *
1166: * @see org.kuali.module.financial.service.CashManagementService#getRecentlyClosedItemsInProcess(org.kuali.module.financial.document.CashManagementDocument)
1167: */
1168: public List<CashieringItemInProcess> getRecentlyClosedItemsInProcess(
1169: CashManagementDocument cmDoc) {
1170: return cashManagementDao.findRecentlyClosedItemsInProcess(cmDoc
1171: .getWorkgroupName());
1172: }
1173:
1174: /**
1175: * This method generates a master coin detail for the cash management document given. A master coin detail is a CoinDetail
1176: * that represents the result of all the money in and out of the cash drawer via the given cash management document. The
1177: * following formula is used to perform this calculation:
1178: * <ul>
1179: * <li>
1180: * "coin detail for cash receipt - coin detail for deposits + coin detail for money in - coin detail for money out"
1181: * </li>
1182: * </ul>
1183: *
1184: * @param cmDoc The document the master coin detail will be generated from.
1185: * @return The resulting coin detail.
1186: *
1187: * @see org.kuali.module.financial.service.CashManagementService#generateMasterCoinDetail(org.kuali.module.financial.document.CashManagementDocument)
1188: */
1189: public CoinDetail generateMasterCoinDetail(
1190: CashManagementDocument cmDoc) {
1191: CoinDetail masterDetail = new CoinDetail();
1192: masterDetail.setDocumentNumber(cmDoc.getDocumentNumber());
1193: masterDetail
1194: .setFinancialDocumentTypeCode(CashieringTransaction.DETAIL_DOCUMENT_TYPE);
1195: masterDetail
1196: .setCashieringRecordSource(KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_MASTER);
1197:
1198: masterDetail.zeroOutAmounts();
1199:
1200: CoinDetail cashReceiptDetail = cashManagementDao
1201: .findCoinDetailByCashieringRecordSource(cmDoc
1202: .getDocumentNumber(),
1203: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1204: KFSConstants.CurrencyCoinSources.CASH_RECEIPTS);
1205: if (cashReceiptDetail != null) {
1206: masterDetail.add(cashReceiptDetail);
1207: }
1208:
1209: CoinDetail depositDetail = cashManagementDao
1210: .findCoinDetailByCashieringRecordSource(cmDoc
1211: .getDocumentNumber(),
1212: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1213: KFSConstants.CurrencyCoinSources.DEPOSITS);
1214: if (depositDetail != null) {
1215: masterDetail.subtract(depositDetail);
1216: }
1217:
1218: CoinDetail moneyInDetail = cashManagementDao
1219: .findCoinDetailByCashieringRecordSource(
1220: cmDoc.getDocumentNumber(),
1221: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1222: KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN);
1223: if (moneyInDetail != null) {
1224: masterDetail.add(moneyInDetail);
1225: }
1226:
1227: CoinDetail moneyOutDetail = cashManagementDao
1228: .findCoinDetailByCashieringRecordSource(
1229: cmDoc.getDocumentNumber(),
1230: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1231: KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_OUT);
1232: if (moneyOutDetail != null) {
1233: masterDetail.subtract(moneyOutDetail);
1234: }
1235:
1236: return masterDetail;
1237: }
1238:
1239: /**
1240: * This method generates a master currency detail for the cash management document given. A master currency detail is a currencyDetail
1241: * that represents the result of all the money in and out of the cash drawer via the given cash management document. The
1242: * following formula is used to perform this calculation:
1243: * <ul>
1244: * <li>
1245: * "currency detail for cash receipt - currency detail for deposits + currency detail for money in - currency detail for money out"
1246: * </li>
1247: * </ul>
1248: *
1249: * @param cmDoc The document the master currency detail will be generated from.
1250: * @return The resulting currency detail.
1251: *
1252: * @see org.kuali.module.financial.service.CashManagementService#generateMasterCurrencyDetail(org.kuali.module.financial.document.CashManagementDocument)
1253: */
1254: public CurrencyDetail generateMasterCurrencyDetail(
1255: CashManagementDocument cmDoc) {
1256: CurrencyDetail masterDetail = new CurrencyDetail();
1257: masterDetail.setDocumentNumber(cmDoc.getDocumentNumber());
1258: masterDetail
1259: .setFinancialDocumentTypeCode(CashieringTransaction.DETAIL_DOCUMENT_TYPE);
1260: masterDetail
1261: .setCashieringRecordSource(KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_MASTER);
1262:
1263: masterDetail.zeroOutAmounts();
1264:
1265: CurrencyDetail cashReceiptDetail = cashManagementDao
1266: .findCurrencyDetailByCashieringRecordSource(cmDoc
1267: .getDocumentNumber(),
1268: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1269: KFSConstants.CurrencyCoinSources.CASH_RECEIPTS);
1270: if (cashReceiptDetail != null) {
1271: masterDetail.add(cashReceiptDetail);
1272: }
1273:
1274: CurrencyDetail depositDetail = cashManagementDao
1275: .findCurrencyDetailByCashieringRecordSource(cmDoc
1276: .getDocumentNumber(),
1277: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1278: KFSConstants.CurrencyCoinSources.DEPOSITS);
1279: if (depositDetail != null) {
1280: masterDetail.subtract(depositDetail);
1281: }
1282:
1283: CurrencyDetail moneyInDetail = cashManagementDao
1284: .findCurrencyDetailByCashieringRecordSource(
1285: cmDoc.getDocumentNumber(),
1286: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1287: KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN);
1288: if (moneyInDetail != null) {
1289: masterDetail.add(moneyInDetail);
1290: }
1291:
1292: CurrencyDetail moneyOutDetail = cashManagementDao
1293: .findCurrencyDetailByCashieringRecordSource(
1294: cmDoc.getDocumentNumber(),
1295: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1296: KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_OUT);
1297: if (moneyOutDetail != null) {
1298: masterDetail.subtract(moneyOutDetail);
1299: }
1300:
1301: return masterDetail;
1302: }
1303:
1304: /**
1305: * Populates the currency and coin detail for final deposits by setting the deposited currency or coin amount equal to the
1306: * associated cashiering record currency or coin amount.
1307: *
1308: * @param cmDoc The cash management document which has deposits to populate.
1309: */
1310: public void populateCashDetailsForDeposit(
1311: CashManagementDocument cmDoc) {
1312: // if this ever gets changed so that each deposit has currency/coin lines, then
1313: // we can just do this with the ORM, which would be *much* easier
1314: for (Deposit d : cmDoc.getDeposits()) {
1315: if (d.getDepositTypeCode().equals(
1316: DepositConstants.DEPOSIT_TYPE_FINAL)) {
1317: if (d.getDepositedCurrency() == null) {
1318: d
1319: .setDepositedCurrency(cashManagementDao
1320: .findCurrencyDetailByCashieringRecordSource(
1321: cmDoc.getDocumentNumber(),
1322: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1323: CurrencyCoinSources.DEPOSITS));
1324: }
1325: if (d.getDepositedCoin() == null) {
1326: d
1327: .setDepositedCoin(cashManagementDao
1328: .findCoinDetailByCashieringRecordSource(
1329: cmDoc.getDocumentNumber(),
1330: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1331: CurrencyCoinSources.DEPOSITS));
1332: }
1333: }
1334: }
1335: }
1336:
1337: /**
1338: * This method retrieves the collection of cashiering checks associated with a given deposit.
1339: *
1340: * @param documentNumber The id of the document to search for the deposit within.
1341: * @param depositLineNumber The line number of the deposit to be found.
1342: * @return A collection of checks for the deposit and document given.
1343: *
1344: * @see org.kuali.module.financial.service.CashManagementService#selectCashieringChecksForDeposit(java.lang.String, java.lang.Integer)
1345: */
1346: public List<Check> selectCashieringChecksForDeposit(
1347: String documentNumber, Integer depositLineNumber) {
1348: return cashManagementDao.selectCashieringChecksForDeposit(
1349: documentNumber, depositLineNumber);
1350: }
1351:
1352: /**
1353: * This method retrieves the collection of undeposited cashiering checks associated with the document given.
1354: *
1355: * @param documentNumber The id of the document to search for the undeposited checks within.
1356: * @return A collection of any undeposited checks for the document given.
1357: *
1358: * @see org.kuali.module.financial.service.CashManagementService#selectUndepositedCashieringChecks(java.lang.String)
1359: */
1360: public List<Check> selectUndepositedCashieringChecks(
1361: String documentNumber) {
1362: return cashManagementDao
1363: .selectUndepositedCashieringChecks(documentNumber);
1364: }
1365:
1366: /**
1367: * This method retrieves a collection of all deposited checks associated with the given document.
1368: *
1369: * @param documentNumber The document to retrieve the deposited checks from.
1370: * @return A collection of all deposited checks for the document given.
1371: *
1372: * @see org.kuali.module.financial.service.CashManagementService#selectDepositedCashieringChecks(java.lang.String)
1373: */
1374: public List<Check> selectDepositedCashieringChecks(
1375: String documentNumber) {
1376: return cashManagementDao
1377: .selectDepositedCashieringChecks(documentNumber);
1378: }
1379:
1380: /**
1381: * Total up the amounts of all checks so far deposited as part of the given cash management document.
1382: *
1383: * @param documentNumber The id of a cash management document.
1384: * @return The total amount of cashiering checks deposited so far as part of that document.
1385: */
1386: public KualiDecimal calculateDepositedCheckTotal(
1387: String documentNumber) {
1388: KualiDecimal total = new KualiDecimal(0);
1389: for (Check check : cashManagementDao
1390: .selectDepositedCashieringChecks(documentNumber)) {
1391: if (check != null
1392: && check.getAmount() != null
1393: && check.getAmount().isGreaterThan(
1394: KualiDecimal.ZERO)) {
1395: total = total.add(check.getAmount());
1396: }
1397: }
1398: return total;
1399: }
1400:
1401: /**
1402: * Calculates the total amount of all the undeposited checks for a cash management document.
1403: *
1404: * @param documentNumber The id of the cash management document to pull the undeposited checks from.
1405: * @return The total amount of all undeposited checks for the document given.
1406: *
1407: * @see org.kuali.module.financial.service.CashManagementService#calculateUndepositedCheckTotal(java.lang.String)
1408: */
1409: public KualiDecimal calculateUndepositedCheckTotal(
1410: String documentNumber) {
1411: KualiDecimal total = new KualiDecimal(0);
1412: for (Check check : cashManagementDao
1413: .selectUndepositedCashieringChecks(documentNumber)) {
1414: if (check != null
1415: && check.getAmount() != null
1416: && check.getAmount().isGreaterThan(
1417: KualiDecimal.ZERO)) {
1418: total = total.add(check.getAmount());
1419: }
1420: }
1421: return total;
1422: }
1423:
1424: /**
1425: * This method determines if a document can be cancelled, by reviewing a set of criteria:
1426: * - do any cash receipts exist in this document?
1427: * - do any cashiering checks exist in this document?
1428: * - do any cash details exist in this document?
1429: * If any of these questions comes back as true, then the document cannot be canceled.
1430: *
1431: * @param cmDoc The document that would be canceled.
1432: * @return True if the document can be canceled, false otherwise.
1433: *
1434: * @see org.kuali.module.financial.service.CashManagementService#allowDocumentCancellation(org.kuali.module.financial.document.CashManagementDocument)
1435: */
1436: public boolean allowDocumentCancellation(
1437: CashManagementDocument cmDoc) {
1438: return !existCashReceipts(cmDoc)
1439: && !existCashieringChecks(cmDoc)
1440: && !existCashDetails(cmDoc);
1441: }
1442:
1443: /**
1444: * This method determines if any verified, interim, or final cash receipts currently exist.
1445: *
1446: * @param cmDoc The cash management document to find cash receipts associated with the workgroup of.
1447: * @return True if there's some cash receipts that verified, interim, or final in this workgroup; false if otherwise.
1448: */
1449: private boolean existCashReceipts(CashManagementDocument cmDoc) {
1450: List<CashReceiptDocument> cashReceipts = SpringContext
1451: .getBean(CashReceiptService.class)
1452: .getCashReceipts(
1453: cmDoc.getWorkgroupName(),
1454: new String[] {
1455: KFSConstants.DocumentStatusCodes.CashReceipt.VERIFIED,
1456: KFSConstants.DocumentStatusCodes.CashReceipt.INTERIM,
1457: KFSConstants.DocumentStatusCodes.CashReceipt.FINAL });
1458: return cashReceipts != null && cashReceipts.size() > 0;
1459: }
1460:
1461: /**
1462: * This method determines if any populated currency or coin details exist for the given document.
1463: *
1464: * @param cmDoc A cash management document to find details.
1465: * @return True if it finds populated currency or coin details, false if otherwise.
1466: */
1467: private boolean existCashDetails(CashManagementDocument cmDoc) {
1468: boolean result = false;
1469: List<CurrencyDetail> currencyDetails = cashManagementDao
1470: .getAllCurrencyDetails(cmDoc.getDocumentNumber());
1471: if (currencyDetails != null && currencyDetails.size() > 0) {
1472: for (CurrencyDetail detail : currencyDetails) {
1473: result |= !detail.isEmpty();
1474: }
1475: }
1476: if (!result) {
1477: List<CoinDetail> coinDetails = cashManagementDao
1478: .getAllCoinDetails(cmDoc.getDocumentNumber());
1479: if (coinDetails != null && coinDetails.size() > 0) {
1480: for (CoinDetail detail : coinDetails) {
1481: result |= !detail.isEmpty();
1482: }
1483: }
1484: }
1485: return result;
1486: }
1487:
1488: /**
1489: * This method determines if cashiering checks exist for the cash management document.
1490: *
1491: * @param cmDoc The cash management document to test.
1492: * @return True if it finds some checks, false if otherwise.
1493: */
1494: private boolean existCashieringChecks(CashManagementDocument cmDoc) {
1495: List<Check> undepositedChecks = this
1496: .selectUndepositedCashieringChecks(cmDoc
1497: .getDocumentNumber());
1498: List<Check> depositedChecks = cashManagementDao
1499: .selectDepositedCashieringChecks(cmDoc
1500: .getDocumentNumber());
1501: return (undepositedChecks != null && undepositedChecks.size() > 0)
1502: || (depositedChecks != null && depositedChecks.size() > 0);
1503: }
1504:
1505: /**
1506: * This method retrieves the next available check line number from the document provided.
1507: *
1508: * @param documentNumber The document to get the next check line number from.
1509: * @return The next available check line number.
1510: *
1511: * @see org.kuali.module.financial.service.CashManagementService#selectNextAvailableCheckLineNumber(java.lang.String)
1512: */
1513: public Integer selectNextAvailableCheckLineNumber(
1514: String documentNumber) {
1515: return cashManagementDao
1516: .selectNextAvailableCheckLineNumber(documentNumber);
1517: }
1518:
1519: /**
1520: * This method retrieves the cash details for the final deposit object. The resulting map contains a CurrencyDetail and a
1521: * CoinDetail object, both keyed by the class of detail they represent (ie. CurrencyDetail.class is the map key for the
1522: * CurrencyDetail of the document).
1523: *
1524: * @param documentNumber The document the details will be generated from.
1525: * @return A map of the resulting cash details. This map is keyed by the detail class object.
1526: *
1527: * @see org.kuali.module.financial.service.CashManagementService#getCashDetailsForFinalDeposit(java.lang.String)
1528: */
1529: public Map<Class, Object> getCashDetailsForFinalDeposit(
1530: String documentNumber) {
1531: CurrencyDetail finalDepositCurrencyDetail = cashManagementDao
1532: .findCurrencyDetailByCashieringRecordSource(
1533: documentNumber,
1534: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1535: KFSConstants.CurrencyCoinSources.DEPOSITS);
1536: CoinDetail finalDepositCoinDetail = cashManagementDao
1537: .findCoinDetailByCashieringRecordSource(documentNumber,
1538: CashieringTransaction.DETAIL_DOCUMENT_TYPE,
1539: KFSConstants.CurrencyCoinSources.DEPOSITS);
1540: Map<Class, Object> result = new HashMap<Class, Object>();
1541: if (finalDepositCurrencyDetail != null) {
1542: result
1543: .put(CurrencyDetail.class,
1544: finalDepositCurrencyDetail);
1545: }
1546: if (finalDepositCoinDetail != null) {
1547: result.put(CoinDetail.class, finalDepositCoinDetail);
1548: }
1549: return result;
1550: }
1551:
1552: // injected dependencies
1553: /**
1554: * Getter for retrieving an instance of the BusinessObjectService attribute.
1555: *
1556: * @return Current value of businessObjectService.
1557: */
1558: public BusinessObjectService getBusinessObjectService() {
1559: return businessObjectService;
1560: }
1561:
1562: /**
1563: * Sets the businessObjectService attribute value.
1564: *
1565: * @param businessObjectService The businessObjectService to set.
1566: */
1567: public void setBusinessObjectService(
1568: BusinessObjectService businessObjectService) {
1569: this .businessObjectService = businessObjectService;
1570: }
1571:
1572: /**
1573: * Getter for retrieving an instance of the CashDrawerService attribute.
1574: *
1575: * @return Current value of cashDrawerService.
1576: */
1577: public CashDrawerService getCashDrawerService() {
1578: return cashDrawerService;
1579: }
1580:
1581: /**
1582: * Sets the cashDrawerService attribute value.
1583: *
1584: * @param cashDrawerService The cashDrawerService to set.
1585: */
1586: public void setCashDrawerService(CashDrawerService cashDrawerService) {
1587: this .cashDrawerService = cashDrawerService;
1588: }
1589:
1590: /**
1591: * Gets the documentService attribute.
1592: *
1593: * @return Current value of documentService.
1594: */
1595: public DocumentService getDocumentService() {
1596: return documentService;
1597: }
1598:
1599: /**
1600: * Sets the documentService attribute value.
1601: *
1602: * @param documentService
1603: */
1604: public void setDocumentService(DocumentService documentService) {
1605: this .documentService = documentService;
1606: }
1607:
1608: /**
1609: * Gets the dateTimeService attribute.
1610: *
1611: * @return Current value of dateTimeService.
1612: */
1613: public DateTimeService getDateTimeService() {
1614: return dateTimeService;
1615: }
1616:
1617: /**
1618: * Sets the dateTimeService attribute value.
1619: *
1620: * @param dateTimeService The dateTimeService to set.
1621: */
1622: public void setDateTimeService(DateTimeService dateTimeService) {
1623: this .dateTimeService = dateTimeService;
1624: }
1625:
1626: /**
1627: * Gets the cashManagementDao attribute.
1628: *
1629: * @return Returns the cashManagementDao.
1630: */
1631: public CashManagementDao getCashManagementDao() {
1632: return cashManagementDao;
1633: }
1634:
1635: /**
1636: * Sets the cashManagementDao attribute value.
1637: *
1638: * @param cashManagementDao The cashManagementDao to set.
1639: */
1640: public void setCashManagementDao(CashManagementDao cashManagementDao) {
1641: this.cashManagementDao = cashManagementDao;
1642: }
1643: }
|