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 }