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.sys.document.validation.impl;
017
018 import org.kuali.kfs.sys.KFSConstants;
019 import org.kuali.kfs.sys.KFSKeyConstants;
020 import org.kuali.kfs.sys.context.SpringContext;
021 import org.kuali.kfs.sys.document.AccountingDocument;
022 import org.kuali.kfs.sys.document.validation.GenericValidation;
023 import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent;
024 import org.kuali.kfs.sys.document.validation.event.AttributedSaveDocumentEvent;
025 import org.kuali.rice.kew.exception.WorkflowException;
026 import org.kuali.rice.kns.service.DocumentService;
027 import org.kuali.rice.kns.util.GlobalVariables;
028 import org.kuali.rice.kns.util.KualiDecimal;
029 import org.kuali.rice.kns.web.format.CurrencyFormatter;
030
031 /**
032 * A validation, used on accounting document approval, that accounting line totals are unchanged
033 */
034 public class AccountingLineGroupTotalsUnchangedValidation extends GenericValidation {
035 private AccountingDocument accountingDocumentForValidation;
036
037 /**
038 * Checks that the source and total amounts on the current version of the accounting document
039 * are equal to the persisted source and total totals.
040 * <strong>Expects a document to be sent in as the first parameter</strong>
041 * @see org.kuali.kfs.sys.document.validation.GenericValidation#validate(java.lang.Object[])
042 */
043 public boolean validate(AttributedDocumentEvent event) {
044 AccountingDocument persistedDocument = null;
045
046 if (event instanceof AttributedSaveDocumentEvent && !accountingDocumentForValidation.getDocumentHeader().getWorkflowDocument().stateIsEnroute()) {
047 return true; // only check save document events if the document is enroute
048 }
049
050 persistedDocument = retrievePersistedDocument(accountingDocumentForValidation);
051
052 boolean isUnchanged = true;
053 if (persistedDocument == null) {
054 handleNonExistentDocumentWhenApproving(accountingDocumentForValidation);
055 }
056 else {
057 // retrieve the persisted totals
058 KualiDecimal persistedSourceLineTotal = persistedDocument.getSourceTotal();
059 KualiDecimal persistedTargetLineTotal = persistedDocument.getTargetTotal();
060
061 // retrieve the updated totals
062 KualiDecimal currentSourceLineTotal = accountingDocumentForValidation.getSourceTotal();
063 KualiDecimal currentTargetLineTotal = accountingDocumentForValidation.getTargetTotal();
064
065 // make sure that totals have remained unchanged, if not, recognize that, and
066 // generate appropriate error messages
067 if (currentSourceLineTotal.compareTo(persistedSourceLineTotal) != 0) {
068 isUnchanged = false;
069
070 // build out error message
071 buildTotalChangeErrorMessage(KFSConstants.SOURCE_ACCOUNTING_LINE_ERRORS, persistedSourceLineTotal, currentSourceLineTotal);
072 }
073
074 if (currentTargetLineTotal.compareTo(persistedTargetLineTotal) != 0) {
075 isUnchanged = false;
076
077 // build out error message
078 buildTotalChangeErrorMessage(KFSConstants.TARGET_ACCOUNTING_LINE_ERRORS, persistedTargetLineTotal, currentTargetLineTotal);
079 }
080 }
081
082 return isUnchanged;
083 }
084
085 /**
086 * attempt to retrieve the document from the DB for comparison
087 *
088 * @param accountingDocument
089 * @return AccountingDocument
090 */
091 protected AccountingDocument retrievePersistedDocument(AccountingDocument accountingDocument) {
092 AccountingDocument persistedDocument = null;
093
094 try {
095 persistedDocument = (AccountingDocument) SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(accountingDocument.getDocumentNumber());
096 }
097 catch (WorkflowException we) {
098 handleNonExistentDocumentWhenApproving(accountingDocument);
099 }
100
101 return persistedDocument;
102 }
103
104 /**
105 * This method builds out the error message for when totals have changed.
106 *
107 * @param propertyName
108 * @param persistedSourceLineTotal
109 * @param currentSourceLineTotal
110 */
111 protected void buildTotalChangeErrorMessage(String propertyName, KualiDecimal persistedSourceLineTotal, KualiDecimal currentSourceLineTotal) {
112 String persistedTotal = (String) new CurrencyFormatter().format(persistedSourceLineTotal);
113 String currentTotal = (String) new CurrencyFormatter().format(currentSourceLineTotal);
114 GlobalVariables.getMessageMap().putError(propertyName, KFSKeyConstants.ERROR_DOCUMENT_SINGLE_ACCOUNTING_LINE_SECTION_TOTAL_CHANGED, new String[] { persistedTotal, currentTotal });
115 }
116
117 /**
118 * Handles the case when a non existent document is attempted to be retrieve and that if it's in an initiated state, it's ok.
119 *
120 * @param accountingDocument
121 */
122 protected final void handleNonExistentDocumentWhenApproving(AccountingDocument accountingDocument) {
123 // check to make sure this isn't an initiated document being blanket approved
124 if (!accountingDocument.getDocumentHeader().getWorkflowDocument().stateIsInitiated()) {
125 throw new IllegalStateException("Document " + accountingDocument.getDocumentNumber() + " is not a valid document that currently exists in the system.");
126 }
127 }
128
129 /**
130 * Gets the accountingDocumentForValidation attribute.
131 * @return Returns the accountingDocumentForValidation.
132 */
133 public AccountingDocument getAccountingDocumentForValidation() {
134 return accountingDocumentForValidation;
135 }
136
137 /**
138 * Sets the accountingDocumentForValidation attribute value.
139 * @param accountingDocumentForValidation The accountingDocumentForValidation to set.
140 */
141 public void setAccountingDocumentForValidation(AccountingDocument accountingDocumentForValidation) {
142 this.accountingDocumentForValidation = accountingDocumentForValidation;
143 }
144 }