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.module.ar.document.validation.impl;
017
018 import org.apache.commons.lang.StringUtils;
019 import org.kuali.kfs.module.ar.ArKeyConstants;
020 import org.kuali.kfs.module.ar.ArPropertyConstants;
021 import org.kuali.kfs.module.ar.businessobject.InvoicePaidApplied;
022 import org.kuali.kfs.module.ar.businessobject.NonInvoiced;
023 import org.kuali.kfs.module.ar.document.PaymentApplicationDocument;
024 import org.kuali.kfs.sys.document.validation.impl.GeneralLedgerPostingDocumentRuleBase;
025 import org.kuali.rice.kew.exception.WorkflowException;
026 import org.kuali.rice.kns.document.Document;
027 import org.kuali.rice.kns.rule.event.ApproveDocumentEvent;
028 import org.kuali.rice.kns.util.GlobalVariables;
029 import org.kuali.rice.kns.util.KNSConstants;
030 import org.kuali.rice.kns.util.KualiDecimal;
031 import org.kuali.rice.kns.util.MessageMap;
032
033 public class PaymentApplicationDocumentRule extends GeneralLedgerPostingDocumentRuleBase {
034
035 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentApplicationDocumentRule.class);
036
037 protected boolean processCustomSaveDocumentBusinessRules(Document document) {
038 boolean isValid = super.processCustomSaveDocumentBusinessRules(document);
039
040 PaymentApplicationDocument paymentApplicationDocument = (PaymentApplicationDocument)document;
041
042 // Validate the applied payments
043 int appliedAmountIndex = 0;
044 for(InvoicePaidApplied invoicePaidApplied : paymentApplicationDocument.getInvoicePaidApplieds()) {
045 String fieldName = ArPropertyConstants.PaymentApplicationDocumentFields.AMOUNT_TO_BE_APPLIED_LINE_N;
046 fieldName = StringUtils.replace(fieldName, "{0}", new Integer(appliedAmountIndex).toString());
047 if(!PaymentApplicationDocumentRuleUtil.validateInvoicePaidApplied(invoicePaidApplied, fieldName, paymentApplicationDocument.getTotalFromControl())) {
048 isValid = false;
049 LOG.info("One of the invoice paid applieds for the payment application document is not valid.");
050 }
051 appliedAmountIndex++;
052 }
053
054 // Validate the nonInvoiced payments
055 for(NonInvoiced nonInvoiced : paymentApplicationDocument.getNonInvoiceds()) {
056 try {
057 if(!PaymentApplicationDocumentRuleUtil.validateNonInvoiced(nonInvoiced, paymentApplicationDocument, paymentApplicationDocument.getTotalFromControl())) {
058 isValid = false;
059 LOG.info("One of the non-invoiced lines on the payment application document is not valid.");
060 }
061 } catch(WorkflowException workflowException) {
062 isValid = false;
063 LOG.error("Workflow exception encountered when trying to validate non invoiced line of payment application document.", workflowException);
064 }
065 }
066
067 // Validate non applied holdings
068 try {
069 if(!PaymentApplicationDocumentRuleUtil.validateNonAppliedHolding(paymentApplicationDocument, paymentApplicationDocument.getTotalFromControl())) {
070 isValid = false;
071 LOG.info("The unapplied line on the payment application document is not valid.");
072 }
073 } catch(WorkflowException workflowException) {
074 isValid = false;
075 LOG.error("Workflow exception encountered when trying to validate nonAppliedHolding attribute of payment application document.", workflowException);
076 }
077
078 // Validate that the cumulative amount applied doesn't exceed the amount owed.
079 try {
080 if(!PaymentApplicationDocumentRuleUtil.validateCumulativeSumOfInvoicePaidAppliedDoesntExceedCashControlTotal(paymentApplicationDocument)) {
081 isValid = false;
082 LOG.info("The total amount applied exceeds the total amount owed per the cash control document total amount.");
083 }
084 } catch(WorkflowException workflowException) {
085 isValid = false;
086 LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException);
087 }
088
089 // Validate that the cumulative amount applied doesn't exceed the amount owed.
090 try {
091 if(!PaymentApplicationDocumentRuleUtil.validateCumulativeSumOfInvoicePaidAppliedsIsGreaterThanOrEqualToZero(paymentApplicationDocument)) {
092 isValid = false;
093 LOG.info("The total amount applied is less than zero.");
094 }
095 } catch(WorkflowException workflowException) {
096 isValid = false;
097 LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException);
098 }
099
100 // Validate that the unapplied total doesn't exceed the cash control total
101 try {
102 if(!PaymentApplicationDocumentRuleUtil.validateUnappliedAmountDoesntExceedCashControlTotal(paymentApplicationDocument)) {
103 isValid = false;
104 LOG.info("The total unapplied amount exceeds the total amount owed per the cash control document total amount.");
105 }
106 } catch(WorkflowException workflowException) {
107 isValid = false;
108 LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException);
109 }
110
111 // Validate that the unapplied total isn't less than zero
112 try {
113 if(!PaymentApplicationDocumentRuleUtil.validateUnappliedAmountIsGreaterThanOrEqualToZero(paymentApplicationDocument)) {
114 isValid = false;
115 LOG.info("The total unapplied amount is less than zero.");
116 }
117 } catch(WorkflowException workflowException) {
118 isValid = false;
119 LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException);
120 }
121
122 // Validate that the non-invoiced total doesn't exceed the cash control total
123 try {
124 if(!PaymentApplicationDocumentRuleUtil.validateNonInvoicedAmountDoesntExceedCashControlTotal(paymentApplicationDocument)) {
125 isValid = false;
126 LOG.info("The total non-invoiced amount exceeds the total amount owed per the cash control document total amount.");
127 }
128 } catch(WorkflowException workflowException) {
129 isValid = false;
130 LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException);
131 }
132
133 // Validate that the non-invoiced total isn't less than zero
134 try {
135 if(!PaymentApplicationDocumentRuleUtil.validateNonInvoicedAmountIsGreaterThanOrEqualToZero(paymentApplicationDocument)) {
136 isValid = false;
137 LOG.info("The total unapplied amount is less than zero.");
138 }
139 } catch(WorkflowException workflowException) {
140 isValid = false;
141 LOG.error("Workflow exception encountered when trying to get validate the total applied amount for payment application document.", workflowException);
142 }
143
144 return isValid;
145 }
146
147 /**
148 * @see org.kuali.rice.kns.rules.DocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.Document)
149 */
150 protected boolean processCustomRouteDocumentBusinessRules(Document document) {
151
152 // if the super failed, don't even bother running these rules
153 boolean isValid = super.processCustomRouteDocumentBusinessRules(document);
154 if (!isValid) return false;
155
156 MessageMap errorMap = GlobalVariables.getMessageMap();
157 PaymentApplicationDocument paymentApplicationDocument = (PaymentApplicationDocument) document;
158
159 // this rules is only applicable to CashControl generated Application document
160 // dont let PayApp docs started from CashControl docs through if not all funds are applied
161 if (paymentApplicationDocument.hasCashControlDetail()) {
162 if (!KualiDecimal.ZERO.equals(paymentApplicationDocument.getUnallocatedBalance())) {
163 isValid &= false;
164 errorMap.putError(
165 KNSConstants.GLOBAL_ERRORS,
166 ArKeyConstants.PaymentApplicationDocumentErrors.FULL_AMOUNT_NOT_APPLIED);
167 LOG.info("The payment application document was not fully applied.");
168 }
169 }
170
171
172 return isValid;
173 }
174
175 /**
176 * @param doc
177 * @return true if the organization document number on the document header is not blank.
178 */
179 protected boolean containsCashControlDocument(PaymentApplicationDocument doc) {
180 return (StringUtils.isNotBlank(doc.getDocumentHeader().getOrganizationDocumentNumber()));
181 }
182
183 /**
184 * @see org.kuali.rice.kns.rules.DocumentRuleBase#processCustomApproveDocumentBusinessRules(org.kuali.rice.kns.rule.event.ApproveDocumentEvent)
185 */
186 protected boolean processCustomApproveDocumentBusinessRules(ApproveDocumentEvent approveEvent) {
187 boolean isValid = super.processCustomApproveDocumentBusinessRules(approveEvent);
188 //PaymentApplicationDocument aDocument = (PaymentApplicationDocument)approveEvent.getDocument();
189 return isValid;
190 }
191
192 }