/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.module.ar.document.validation.impl; import org.apache.commons.lang.StringUtils; import org.kuali.kfs.module.ar.ArKeyConstants; import org.kuali.kfs.module.ar.ArPropertyConstants; import org.kuali.kfs.module.ar.businessobject.InvoicePaidApplied; import org.kuali.kfs.module.ar.businessobject.NonInvoiced; import org.kuali.kfs.module.ar.document.PaymentApplicationDocument; import org.kuali.kfs.sys.document.validation.impl.GeneralLedgerPostingDocumentRuleBase; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.krad.document.Document; import org.kuali.rice.krad.rules.rule.event.ApproveDocumentEvent; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.KRADConstants; import org.kuali.rice.core.api.util.type.KualiDecimal; import org.kuali.rice.krad.util.MessageMap; /** * Document rule class for Payment Application. */ public class PaymentApplicationDocumentRule extends GeneralLedgerPostingDocumentRuleBase { private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentApplicationDocumentRule.class); /** * @see org.kuali.rice.krad.rules.DocumentRuleBase#processCustomSaveDocumentBusinessRules(org.kuali.rice.krad.document.Document) */ @Override protected boolean processCustomSaveDocumentBusinessRules(Document document) { boolean isValid = super.processCustomSaveDocumentBusinessRules(document); PaymentApplicationDocument paymentApplicationDocument = (PaymentApplicationDocument)document; // Validate the applied payments int appliedAmountIndex = 0; for(InvoicePaidApplied invoicePaidApplied : paymentApplicationDocument.getInvoicePaidApplieds()) { String fieldName = ArPropertyConstants.PaymentApplicationDocumentFields.AMOUNT_TO_BE_APPLIED_LINE_N; fieldName = StringUtils.replace(fieldName, "{0}", new Integer(appliedAmountIndex).toString()); if(!PaymentApplicationDocumentRuleUtil.validateInvoicePaidApplied(invoicePaidApplied, fieldName, paymentApplicationDocument)) { isValid = false; LOG.info("One of the invoice paid applieds for the payment application document is not valid."); } appliedAmountIndex++; } // Validate the nonInvoiced payments for (NonInvoiced nonInvoiced : paymentApplicationDocument.getNonInvoiceds()) { try { if (!PaymentApplicationDocumentRuleUtil.validateNonInvoiced(nonInvoiced, paymentApplicationDocument, paymentApplicationDocument.getTotalFromControl())) { isValid = false; LOG.info("One of the non-invoiced lines on the payment application document is not valid."); } } catch (WorkflowException workflowException) { isValid = false; LOG.error("Workflow exception encountered when trying to validate non invoiced line of payment application document.", workflowException); } } // Validate non applied holdings try { if (!PaymentApplicationDocumentRuleUtil.validateNonAppliedHolding(paymentApplicationDocument, paymentApplicationDocument.getTotalFromControl())) { isValid = false; LOG.info("The unapplied line on the payment application document is not valid."); } } catch (WorkflowException workflowException) { isValid = false; LOG.error("Workflow exception encountered when trying to validate nonAppliedHolding attribute of payment application document.", workflowException); } // Validate that the cumulative amount applied doesn't exceed the amount owed. try { if (!PaymentApplicationDocumentRuleUtil.validateCumulativeSumOfInvoicePaidAppliedDoesntExceedCashControlTotal(paymentApplicationDocument)) { isValid = false; LOG.info("The total amount applied exceeds the total amount owed per the cash control document total amount."); } } catch (WorkflowException workflowException) { isValid = false; LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException); } // Validate that the cumulative amount applied doesn't exceed the amount owed. try { if (!PaymentApplicationDocumentRuleUtil.validateCumulativeSumOfInvoicePaidAppliedsIsGreaterThanOrEqualToZero(paymentApplicationDocument)) { isValid = false; LOG.info("The total amount applied is less than zero."); } } catch (WorkflowException workflowException) { isValid = false; LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException); } // Validate that the unapplied total doesn't exceed the cash control total try { if (!PaymentApplicationDocumentRuleUtil.validateUnappliedAmountDoesntExceedCashControlTotal(paymentApplicationDocument)) { isValid = false; LOG.info("The total unapplied amount exceeds the total amount owed per the cash control document total amount."); } } catch (WorkflowException workflowException) { isValid = false; LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException); } // Validate that the unapplied total isn't less than zero try { if (!PaymentApplicationDocumentRuleUtil.validateUnappliedAmountIsGreaterThanOrEqualToZero(paymentApplicationDocument)) { isValid = false; LOG.info("The total unapplied amount is less than zero."); } } catch (WorkflowException workflowException) { isValid = false; LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException); } // Validate that the non-invoiced total doesn't exceed the cash control total try { if (!PaymentApplicationDocumentRuleUtil.validateNonInvoicedAmountDoesntExceedCashControlTotal(paymentApplicationDocument)) { isValid = false; LOG.info("The total non-invoiced amount exceeds the total amount owed per the cash control document total amount."); } } catch (WorkflowException workflowException) { isValid = false; LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException); } // Validate that the non-invoiced total isn't less than zero try { if (!PaymentApplicationDocumentRuleUtil.validateNonInvoicedAmountIsGreaterThanOrEqualToZero(paymentApplicationDocument)) { isValid = false; LOG.info("The total unapplied amount is less than zero."); } } catch (WorkflowException workflowException) { isValid = false; LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException); } return isValid; } /** * @see org.kuali.rice.krad.rules.DocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.krad.document.Document) */ @Override protected boolean processCustomRouteDocumentBusinessRules(Document document) { // if the super failed, don't even bother running these rules boolean isValid = super.processCustomRouteDocumentBusinessRules(document); if (!isValid) { return false; } MessageMap errorMap = GlobalVariables.getMessageMap(); PaymentApplicationDocument paymentApplicationDocument = (PaymentApplicationDocument) document; // this rules is only applicable to CashControl generated Application document // dont let PayApp docs started from CashControl docs through if not all funds are applied if (paymentApplicationDocument.hasCashControlDetail()) { if (!KualiDecimal.ZERO.equals(paymentApplicationDocument.getUnallocatedBalance())) { isValid &= false; errorMap.putError( KRADConstants.GLOBAL_ERRORS, ArKeyConstants.PaymentApplicationDocumentErrors.FULL_AMOUNT_NOT_APPLIED); LOG.info("The payment application document was not fully applied."); } } return isValid; } /** * @param doc * @return true if the organization document number on the document header is not blank. */ protected boolean containsCashControlDocument(PaymentApplicationDocument doc) { return (StringUtils.isNotBlank(doc.getDocumentHeader().getOrganizationDocumentNumber())); } /** * @see org.kuali.rice.krad.rules.DocumentRuleBase#processCustomApproveDocumentBusinessRules(org.kuali.rice.krad.rule.event.ApproveDocumentEvent) */ @Override protected boolean processCustomApproveDocumentBusinessRules(ApproveDocumentEvent approveEvent) { boolean isValid = super.processCustomApproveDocumentBusinessRules(approveEvent); return isValid; } }