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