001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.module.financial.rules;
017:
018: import static org.kuali.kfs.KFSConstants.DOCUMENT_PROPERTY_NAME;
019:
020: import java.util.HashMap;
021: import java.util.Map;
022:
023: import org.kuali.core.document.Document;
024: import org.kuali.core.rule.event.ApproveDocumentEvent;
025: import org.kuali.core.service.BusinessObjectService;
026: import org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper;
027: import org.kuali.core.util.GlobalVariables;
028: import org.kuali.core.util.KualiDecimal;
029: import org.kuali.core.util.ObjectUtils;
030: import org.kuali.kfs.KFSConstants;
031: import org.kuali.kfs.KFSKeyConstants;
032: import org.kuali.kfs.KFSPropertyConstants;
033: import org.kuali.kfs.bo.GeneralLedgerPendingEntry;
034: import org.kuali.kfs.context.SpringContext;
035: import org.kuali.kfs.document.AccountingDocument;
036: import org.kuali.kfs.rule.GenerateGeneralLedgerDocumentPendingEntriesRule;
037: import org.kuali.kfs.rules.AccountingDocumentRuleUtil;
038: import org.kuali.kfs.service.ParameterService;
039: import org.kuali.module.financial.bo.BankAccount;
040: import org.kuali.module.financial.document.CashReceiptFamilyBase;
041: import org.kuali.module.financial.document.CreditCardReceiptDocument;
042:
043: /**
044: * Business rules applicable to Credit Card Receipt documents.
045: */
046: public class CreditCardReceiptDocumentRule extends
047: CashReceiptFamilyRule
048: implements
049: GenerateGeneralLedgerDocumentPendingEntriesRule<AccountingDocument> {
050: /**
051: * For Credit Card Receipt documents, the document is balanced if the sum total of credit card receipts equals the sum total of
052: * the accounting lines.
053: *
054: * @param financialDocument submitted accoutting document
055: * @return true if cash credit receipt document equals the cash credit document total dollar amount
056: *
057: * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isDocumentBalanceValid(org.kuali.core.document.FinancialDocument)
058: */
059: @Override
060: protected boolean isDocumentBalanceValid(
061: AccountingDocument finanacialDocument) {
062: CreditCardReceiptDocument ccr = (CreditCardReceiptDocument) finanacialDocument;
063:
064: // make sure the document is in balance
065: boolean isValid = ccr.getSourceTotal().equals(
066: ccr.getTotalDollarAmount());
067:
068: if (!isValid) {
069: GlobalVariables
070: .getErrorMap()
071: .putError(
072: KFSPropertyConstants.NEW_CREDIT_CARD_RECEIPT,
073: KFSKeyConstants.CreditCardReceipt.ERROR_DOCUMENT_CREDIT_CARD_RECEIPT_OUT_OF_BALANCE);
074: }
075:
076: return isValid;
077: }
078:
079: /**
080: * Overrides to call super and then make sure the minimum number of credit card receipt lines exist on this document.
081: *
082: * @param document submitted document
083: * @return true if super method returns true and there is at least one credit card receipt
084: *
085: * @see org.kuali.core.rule.DocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.core.document.Document)
086: */
087: @Override
088: protected boolean processCustomRouteDocumentBusinessRules(
089: Document document) {
090: boolean isValid = super
091: .processCustomRouteDocumentBusinessRules(document);
092:
093: isValid &= isMinimumNumberOfCreditCardReceiptsMet(document);
094:
095: if (isValid) {
096: isValid &= validateAccountingLineTotal((CashReceiptFamilyBase) document);
097: isValid &= !CreditCardReceiptDocumentRuleUtil
098: .areCashTotalsInvalid((CreditCardReceiptDocument) document);
099: }
100:
101: if (isValid) {
102: isValid &= validateCreditCardReceipts((CreditCardReceiptDocument) document);
103: }
104:
105: return isValid;
106: }
107:
108: /**
109: * This method is a helper that checks to make sure that at least one credit card receipt line exists for the document.
110: *
111: * @param document submitted document
112: * @return boolean return true if there is at least one credit card receipt
113: */
114: private boolean isMinimumNumberOfCreditCardReceiptsMet(
115: Document document) {
116: CreditCardReceiptDocument ccr = (CreditCardReceiptDocument) document;
117:
118: if (ccr.getCreditCardReceipts().size() == 0) {
119: GlobalVariables
120: .getErrorMap()
121: .putError(
122: KFSPropertyConstants.NEW_CREDIT_CARD_RECEIPT,
123: KFSKeyConstants.CreditCardReceipt.ERROR_DOCUMENT_CREDIT_CARD_RECEIPT_REQ_NUMBER_RECEIPTS_NOT_MET);
124: return false;
125: }
126: return true;
127: }
128:
129: /**
130: * Validates all the CreditCardReceipts in the given Document.
131: *
132: * @param creditCardReceiptDocument submitted credit card receipt document
133: * @return true if all credit cards are valid (i.e. each credit card receipt has a non-zero amount and has valid
134: * credit card vendor and type references)
135: */
136: private boolean validateCreditCardReceipts(
137: CreditCardReceiptDocument creditCardReceiptDocument) {
138: GlobalVariables.getErrorMap().addToErrorPath(
139: DOCUMENT_PROPERTY_NAME);
140: boolean isValid = true;
141: for (int i = 0; i < creditCardReceiptDocument
142: .getCreditCardReceipts().size(); i++) {
143: String propertyName = KFSPropertyConstants.CREDIT_CARD_RECEIPT
144: + "[" + i + "]";
145: GlobalVariables.getErrorMap().addToErrorPath(propertyName);
146: isValid &= CreditCardReceiptDocumentRuleUtil
147: .validateCreditCardReceipt(creditCardReceiptDocument
148: .getCreditCardReceipt(i));
149: GlobalVariables.getErrorMap().removeFromErrorPath(
150: propertyName);
151: }
152: GlobalVariables.getErrorMap().removeFromErrorPath(
153: DOCUMENT_PROPERTY_NAME);
154: return isValid;
155: }
156:
157: /**
158: * Generates bank offset GLPEs for deposits, if enabled.
159: *
160: * @param financialDocument submitted accounting document
161: * @param sequenceHelper helper class for keep track of sequence for GLPEs
162: * @return true if generation of GLPE's is successful for credit card receipt document
163: *
164: * @see org.kuali.core.rule.GenerateGeneralLedgerDocumentPendingEntriesRule#processGenerateDocumentGeneralLedgerPendingEntries(org.kuali.core.document.FinancialDocument,org.kuali.core.util.GeneralLedgerPendingEntrySequenceHelper)
165: */
166: public boolean processGenerateDocumentGeneralLedgerPendingEntries(
167: AccountingDocument financialDocument,
168: GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
169: boolean success = true;
170: CreditCardReceiptDocument ccrDoc = (CreditCardReceiptDocument) financialDocument;
171: if (ccrDoc.isBankCashOffsetEnabled()) {
172: KualiDecimal depositTotal = ccrDoc
173: .calculateCreditCardReceiptTotal();
174: // todo: what if the total is 0? e.g., 5 minus 5, should we generate a 0 amount GLPE and offset? I think the other rules
175: // combine to prevent a 0 total, though.
176: GeneralLedgerPendingEntry bankOffsetEntry = new GeneralLedgerPendingEntry();
177: final BankAccount offsetBankAccount = getOffsetBankAccount();
178: if (ObjectUtils.isNull(offsetBankAccount)) {
179: success = false;
180: GlobalVariables
181: .getErrorMap()
182: .putError(
183: "newCreditCardReceipt.financialDocumentCreditCardTypeCode",
184: KFSKeyConstants.CreditCardReceipt.ERROR_DOCUMENT_CREDIT_CARD_BANK_MUST_EXIST_WHEN_FLEXIBLE,
185: new String[] {
186: KFSConstants.SystemGroupParameterNames.FLEXIBLE_CLAIM_ON_CASH_BANK_ENABLED_FLAG,
187: CreditCardReceiptDocumentRuleConstants.CASH_OFFSET_BANK_ACCOUNT });
188: } else {
189: success &= AccountingDocumentRuleUtil
190: .populateBankOffsetGeneralLedgerPendingEntry(
191: offsetBankAccount,
192: depositTotal,
193: ccrDoc,
194: ccrDoc.getPostingYear(),
195: sequenceHelper,
196: bankOffsetEntry,
197: KFSConstants.CREDIT_CARD_RECEIPTS_LINE_ERRORS);
198: // An unsuccessfully populated bank offset entry may contain invalid relations, so don't add it at all if not
199: // successful.
200: if (success) {
201: bankOffsetEntry
202: .setTransactionLedgerEntryDescription(AccountingDocumentRuleUtil
203: .formatProperty(KFSKeyConstants.CreditCardReceipt.DESCRIPTION_GLPE_BANK_OFFSET));
204: ccrDoc.getGeneralLedgerPendingEntries().add(
205: bankOffsetEntry);
206: sequenceHelper.increment();
207:
208: GeneralLedgerPendingEntry offsetEntry = (GeneralLedgerPendingEntry) ObjectUtils
209: .deepCopy(bankOffsetEntry);
210: success &= populateOffsetGeneralLedgerPendingEntry(
211: ccrDoc.getPostingYear(), bankOffsetEntry,
212: sequenceHelper, offsetEntry);
213: // unsuccessful offsets may be added, but that's consistent with the offsets for regular GLPEs (i.e., maybe
214: // neither
215: // should?)
216: ccrDoc.getGeneralLedgerPendingEntries().add(
217: offsetEntry);
218: sequenceHelper.increment();
219: }
220: }
221: }
222: return success;
223: }
224:
225: /**
226: * Returns a credit cards flexible offset bank account
227: *
228: * @return the Credit Card Receipt's flexible offset bank account, as configured in the APC.
229: * @throws ApplicationParameterException if the CCR offset BankAccount is not defined in the APC.
230: */
231: private BankAccount getOffsetBankAccount() {
232: final String[] parameterValues = SpringContext
233: .getBean(ParameterService.class)
234: .getParameterValues(
235: CreditCardReceiptDocument.class,
236: CreditCardReceiptDocumentRuleConstants.CASH_OFFSET_BANK_ACCOUNT)
237: .toArray(new String[] {});
238: if (parameterValues.length != 2) {
239: throw new RuntimeException(
240: CreditCardReceiptDocument.class.getSimpleName()
241: + "/"
242: + CreditCardReceiptDocumentRuleConstants.CASH_OFFSET_BANK_ACCOUNT
243: + ": invalid parameter format: must be 'bankCode;bankAccountNumber'");
244: }
245: final String bankCode = parameterValues[0];
246: final String bankAccountNumber = parameterValues[1];
247: final Map<String, Object> primaryKeys = new HashMap<String, Object>();
248: primaryKeys.put(
249: KFSPropertyConstants.FINANCIAL_DOCUMENT_BANK_CODE,
250: bankCode);
251: primaryKeys.put(
252: KFSPropertyConstants.FIN_DOCUMENT_BANK_ACCOUNT_NUMBER,
253: bankAccountNumber);
254: return (BankAccount) SpringContext.getBean(
255: BusinessObjectService.class).findByPrimaryKey(
256: BankAccount.class, primaryKeys);
257: }
258:
259: /**
260: * We are overriding here and always returning true since we don't care about
261: * cash drawers for this doc type but want the other rules in the super class.
262: * @see org.kuali.module.financial.rules.CashReceiptFamilyRule#processCustomApproveDocumentBusinessRules(org.kuali.core.rule.event.ApproveDocumentEvent)
263: */
264: protected boolean processCustomApproveDocumentBusinessRules(
265: ApproveDocumentEvent approveEvent) {
266: return true;
267: }
268: }
|