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;
017
018 import java.util.ArrayList;
019 import java.util.List;
020
021 import org.apache.commons.lang.StringUtils;
022 import org.kuali.kfs.gl.service.SufficientFundsService;
023 import org.kuali.kfs.sys.KFSConstants;
024 import org.kuali.kfs.sys.KFSKeyConstants;
025 import org.kuali.kfs.sys.businessobject.Bank;
026 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
027 import org.kuali.kfs.sys.businessobject.SufficientFundsItem;
028 import org.kuali.kfs.sys.context.SpringContext;
029 import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
030 import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
031 import org.kuali.rice.kew.exception.WorkflowException;
032 import org.kuali.rice.kns.exception.ValidationException;
033 import org.kuali.rice.kns.rule.event.ApproveDocumentEvent;
034 import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
035 import org.kuali.rice.kns.rule.event.RouteDocumentEvent;
036 import org.kuali.rice.kns.service.ParameterService;
037 import org.kuali.rice.kns.util.GlobalVariables;
038
039 /**
040 * Base implementation for a general ledger posting document.
041 */
042 public class GeneralLedgerPostingDocumentBase extends LedgerPostingDocumentBase implements GeneralLedgerPostingDocument {
043 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(GeneralLedgerPostingDocumentBase.class);
044
045 protected List<GeneralLedgerPendingEntry> generalLedgerPendingEntries;
046
047 /**
048 * Default constructor.
049 */
050 public GeneralLedgerPostingDocumentBase() {
051 super();
052 setGeneralLedgerPendingEntries(new ArrayList<GeneralLedgerPendingEntry>());
053 }
054
055 /**
056 * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocument#getGeneralLedgerPendingEntries()
057 */
058 public List<GeneralLedgerPendingEntry> getGeneralLedgerPendingEntries() {
059 return generalLedgerPendingEntries;
060 }
061
062 /**
063 * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocument#getGeneralLedgerPendingEntry(int)
064 */
065 public GeneralLedgerPendingEntry getGeneralLedgerPendingEntry(int index) {
066 while (generalLedgerPendingEntries.size() <= index) {
067 generalLedgerPendingEntries.add(new GeneralLedgerPendingEntry());
068 }
069 return generalLedgerPendingEntries.get(index);
070 }
071
072 /**
073 * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocument#setGeneralLedgerPendingEntries(java.util.List)
074 */
075 public void setGeneralLedgerPendingEntries(List<GeneralLedgerPendingEntry> generalLedgerPendingEntries) {
076 this.generalLedgerPendingEntries = generalLedgerPendingEntries;
077 }
078
079 /**
080 * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocument#checkSufficientFunds()
081 */
082 public List<SufficientFundsItem> checkSufficientFunds() {
083 LOG.debug("checkSufficientFunds() started");
084
085 if (documentPerformsSufficientFundsCheck()) {
086 SufficientFundsService sufficientFundsService = SpringContext.getBean(SufficientFundsService.class);
087 return sufficientFundsService.checkSufficientFunds(this);
088 }
089 else {
090 return new ArrayList<SufficientFundsItem>();
091 }
092 }
093
094 /**
095 * This method checks to see if SF checking should be done for this document. This was originally part of
096 * SufficientFundsService.checkSufficientFunds() but was externalized so documents that need to override any of the SF methods
097 * can still explicitly check this
098 *
099 * @return
100 */
101 public boolean documentPerformsSufficientFundsCheck() {
102 // check for reversing entries generated by an error correction.
103 return StringUtils.isBlank(this.getDocumentHeader().getFinancialDocumentInErrorNumber());
104 }
105
106 /**
107 * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocument#getPendingLedgerEntriesForSufficientFundsChecking()
108 */
109 public List<GeneralLedgerPendingEntry> getPendingLedgerEntriesForSufficientFundsChecking() {
110 return getGeneralLedgerPendingEntries();
111 }
112
113 /**
114 * Override to call super and then iterate over all GLPEs and update the approved code appropriately.
115 *
116 * @see Document#doRouteStatusChange()
117 */
118 @Override
119 public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) {
120 super.doRouteStatusChange(statusChangeEvent);
121 if (getDocumentHeader().getWorkflowDocument().stateIsProcessed()) {
122 changeGeneralLedgerPendingEntriesApprovedStatusCode(); // update all glpes for doc and set their status to approved
123 }
124 else if (getDocumentHeader().getWorkflowDocument().stateIsCanceled() || getDocumentHeader().getWorkflowDocument().stateIsDisapproved()) {
125 removeGeneralLedgerPendingEntries();
126 if (this instanceof ElectronicPaymentClaiming) {
127 ((ElectronicPaymentClaiming)this).declaimElectronicPaymentClaims();
128 }
129 }
130 }
131
132 /**
133 * This method iterates over all of the GLPEs for a document and sets their approved status code to APPROVED "A".
134 */
135 protected void changeGeneralLedgerPendingEntriesApprovedStatusCode() {
136 for (GeneralLedgerPendingEntry glpe : getGeneralLedgerPendingEntries()) {
137 glpe.setFinancialDocumentApprovedCode(KFSConstants.DocumentStatusCodes.APPROVED);
138 }
139 }
140
141 /**
142 * This method calls the service to remove all of the GLPE's associated with this document
143 */
144 protected void removeGeneralLedgerPendingEntries() {
145 GeneralLedgerPendingEntryService glpeService = SpringContext.getBean(GeneralLedgerPendingEntryService.class);
146 glpeService.delete(getDocumentHeader().getDocumentNumber());
147 }
148
149 /**
150 * @see org.kuali.rice.kns.document.DocumentBase#toCopy()
151 */
152 @Override
153 public void toCopy() throws WorkflowException {
154 super.toCopy();
155 getGeneralLedgerPendingEntries().clear();
156 }
157
158 /**
159 * @see org.kuali.rice.kns.document.TransactionalDocumentBase#toErrorCorrection()
160 */
161 @Override
162 public void toErrorCorrection() throws WorkflowException {
163 super.toErrorCorrection();
164 getGeneralLedgerPendingEntries().clear();
165 }
166
167 @Override
168 public void prepareForSave(KualiDocumentEvent event) {
169 super.prepareForSave(event);
170 // TODO - add KFS wrappers of Rice Events to list
171 if (event instanceof RouteDocumentEvent || event instanceof ApproveDocumentEvent) {
172 // generate general ledger pending entries should be called prior to sufficient funds checking
173 List<SufficientFundsItem> sfItems = checkSufficientFunds();
174 if (!sfItems.isEmpty()) {
175 for (SufficientFundsItem sfItem : sfItems) {
176 GlobalVariables.getMessageMap().putError(KFSConstants.ACCOUNTING_LINE_ERRORS, KFSKeyConstants.SufficientFunds.ERROR_INSUFFICIENT_FUNDS, new String[] { sfItem.getAccount().getChartOfAccountsCode(), sfItem.getAccount().getAccountNumber(), StringUtils.isNotBlank(sfItem.getSufficientFundsObjectCode()) ? sfItem.getSufficientFundsObjectCode() : KFSConstants.NOT_AVAILABLE_STRING, sfItem.getAccountSufficientFundsCode() });
177 }
178 throw new ValidationException("Insufficient Funds on this Document:");
179 }
180 }
181 }
182
183 /**
184 * Adds a GeneralLedgerPendingEntry to this document's list of pending entries
185 * @param pendingEntry a pending entry to add
186 */
187 public void addPendingEntry(GeneralLedgerPendingEntry pendingEntry) {
188 generalLedgerPendingEntries.add(pendingEntry);
189 }
190
191 /**
192 * This resets this document's list of general ledger pending etnries, though it does not delete those entries (however, the GeneralLedgerPendingEntryService will in most cases when this method is called).
193 */
194 public void clearAnyGeneralLedgerPendingEntries() {
195 generalLedgerPendingEntries = new ArrayList<GeneralLedgerPendingEntry>();
196 }
197 }