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.ld.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.fp.document.JournalVoucherDocument;
023    import org.kuali.kfs.integration.ld.LaborLedgerPendingEntryForSearching;
024    import org.kuali.kfs.module.ld.LaborConstants;
025    import org.kuali.kfs.module.ld.LaborConstants.JournalVoucherOffsetType;
026    import org.kuali.kfs.module.ld.businessobject.LaborJournalVoucherAccountingLineParser;
027    import org.kuali.kfs.module.ld.businessobject.LaborJournalVoucherDetail;
028    import org.kuali.kfs.module.ld.businessobject.LaborLedgerPendingEntry;
029    import org.kuali.kfs.module.ld.service.LaborLedgerPendingEntryService;
030    import org.kuali.kfs.sys.KFSConstants;
031    import org.kuali.kfs.sys.ObjectUtil;
032    import org.kuali.kfs.sys.businessobject.AccountingLine;
033    import org.kuali.kfs.sys.businessobject.AccountingLineParser;
034    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
035    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
036    import org.kuali.kfs.sys.context.SpringContext;
037    import org.kuali.kfs.sys.document.AmountTotaling;
038    import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
039    import org.kuali.kfs.sys.service.HomeOriginationService;
040    import org.kuali.rice.kew.doctype.bo.DocumentTypeEBO;
041    import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
042    import org.kuali.rice.kew.service.impl.KEWModuleService;
043    import org.kuali.rice.kns.exception.ValidationException;
044    import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
045    
046    // @latex.ClassSignatureStart
047    /**
048     * Labor Document class for the Labor Ledger Journal Voucher.
049     */
050    public class LaborJournalVoucherDocument extends JournalVoucherDocument implements LaborLedgerPostingDocument, AmountTotaling {
051        // @latex.ClassSignatureStop
052        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(LaborJournalVoucherDocument.class);
053        protected String offsetTypeCode = JournalVoucherOffsetType.NO_OFFSET.typeCode;
054        protected List<LaborLedgerPendingEntry> laborLedgerPendingEntries;
055        protected DocumentTypeEBO financialSystemDocumentTypeCode;
056    
057        /**
058         * Constructs a LaborJournalVoucherDocument.java.
059         */
060        public LaborJournalVoucherDocument() {
061            super();
062            setLaborLedgerPendingEntries(new ArrayList<LaborLedgerPendingEntry>());
063        }
064    
065        /**
066         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getSourceAccountingLineClass()
067         */
068        @Override
069        public Class getSourceAccountingLineClass() {
070            return LaborJournalVoucherDetail.class;
071        }
072    
073        /**
074         * @see org.kuali.kfs.module.ld.document.LaborLedgerPostingDocument#getLaborLedgerPendingEntry(int)
075         */
076        public LaborLedgerPendingEntry getLaborLedgerPendingEntry(int index) {
077            while (laborLedgerPendingEntries.size() <= index) {
078                laborLedgerPendingEntries.add(new LaborLedgerPendingEntry());
079            }
080            return laborLedgerPendingEntries.get(index);
081        }
082    
083        /**
084         * Gets the offsetTypeCode attribute.
085         * 
086         * @return Returns the offsetTypeCode.
087         */
088        public String getOffsetTypeCode() {
089            return offsetTypeCode;
090        }
091    
092        /**
093         * Sets the offsetTypeCode attribute value.
094         * 
095         * @param offsetTypeCode The offsetTypeCode to set.
096         */
097        public void setOffsetTypeCode(String offsetTypeCode) {
098            this.offsetTypeCode = offsetTypeCode;
099        }
100    
101        /**
102         * Gets the laborLedgerPendingEntries attribute.
103         * 
104         * @return Returns the laborLedgerPendingEntries.
105         */
106        public List<LaborLedgerPendingEntry> getLaborLedgerPendingEntries() {
107            return laborLedgerPendingEntries;
108        }
109    
110        /**
111         * Sets the laborLedgerPendingEntries attribute value.
112         * 
113         * @param laborLedgerPendingEntries The laborLedgerPendingEntries to set.
114         */
115        public void setLaborLedgerPendingEntries(List<LaborLedgerPendingEntry> laborLedgerPendingEntries) {
116            this.laborLedgerPendingEntries = laborLedgerPendingEntries;
117        }
118    
119        /**
120         * Gets the financialSystemDocumentTypeCode attribute.
121         * 
122         * @return Returns the financialSystemDocumentTypeCode.
123         */
124        public DocumentTypeEBO getFinancialSystemDocumentTypeCode() {
125            return financialSystemDocumentTypeCode = SpringContext.getBean(KEWModuleService.class).retrieveExternalizableBusinessObjectIfNecessary(this, financialSystemDocumentTypeCode, "financialSystemDocumentTypeCode");
126        }
127    
128        /**
129         * Used to get the appropriate <code>{@link AccountingLineParser}</code> for the <code>Document</code>
130         * 
131         * @return AccountingLineParser
132         */
133        @Override
134        public AccountingLineParser getAccountingLineParser() {
135            return new LaborJournalVoucherAccountingLineParser(getBalanceTypeCode());
136        }
137    
138        /**
139         * Override to call super and then iterate over all GLPEs and update the approved code appropriately.
140         * 
141         * @see Document#doRouteStatusChange()
142         */
143        @Override
144        public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) {
145            super.doRouteStatusChange(statusChangeEvent);
146            if (getDocumentHeader().getWorkflowDocument().stateIsProcessed()) {
147                changeLedgerPendingEntriesApprovedStatusCode();
148            }
149            else if (getDocumentHeader().getWorkflowDocument().stateIsCanceled() || getDocumentHeader().getWorkflowDocument().stateIsDisapproved()) {
150                removeLedgerPendingEntries();
151            }
152        }
153    
154        /**
155         * This method iterates over all of the pending entries for a document and sets their approved status code to APPROVED "A".
156         */
157        protected void changeLedgerPendingEntriesApprovedStatusCode() {
158            for (LaborLedgerPendingEntry pendingEntry : laborLedgerPendingEntries) {
159                pendingEntry.setFinancialDocumentApprovedCode(KFSConstants.DocumentStatusCodes.APPROVED);
160            }
161        }
162    
163        /**
164         * This method calls the service to remove all of the pending entries associated with this document
165         */
166        protected void removeLedgerPendingEntries() {
167            LaborLedgerPendingEntryService laborLedgerPendingEntryService = SpringContext.getBean(LaborLedgerPendingEntryService.class);
168            laborLedgerPendingEntryService.delete(getDocumentHeader().getDocumentNumber());
169        }
170    
171        /**
172         * @see org.kuali.kfs.module.ld.document.LaborLedgerPostingDocument#generateLaborLedgerBenefitClearingPendingEntries(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper)
173         */
174        public boolean generateLaborLedgerBenefitClearingPendingEntries(GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
175            return true;
176        }
177    
178        /**
179         * @see org.kuali.kfs.module.ld.document.LaborLedgerPostingDocument#generateLaborLedgerPendingEntries(org.kuali.kfs.sys.businessobject.AccountingLine,
180         *      org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper)
181         */
182        public boolean generateLaborLedgerPendingEntries(AccountingLine accountingLine, GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
183            LOG.debug("processGenerateLaborLedgerPendingEntries() started");
184    
185            try {
186                LaborLedgerPendingEntry pendingLedgerEntry = new LaborLedgerPendingEntry();
187    
188                // populate the explicit entry
189                ObjectUtil.buildObject(pendingLedgerEntry, accountingLine);
190                
191                GeneralLedgerPendingEntryService pendingEntryService = SpringContext.getBean(GeneralLedgerPendingEntryService.class);
192                pendingEntryService.populateExplicitGeneralLedgerPendingEntry(this, accountingLine, sequenceHelper, pendingLedgerEntry);
193    
194                // apply the labor JV specific information
195                this.customizeExplicitGeneralLedgerPendingEntry(accountingLine, pendingLedgerEntry);
196                pendingLedgerEntry.setFinancialDocumentTypeCode(this.getOffsetTypeCode());
197    
198                if (StringUtils.isBlank(((LaborJournalVoucherDetail) accountingLine).getEmplid())) {
199                    pendingLedgerEntry.setEmplid(LaborConstants.getDashEmplId());
200                }
201    
202                if (StringUtils.isBlank(((LaborJournalVoucherDetail) accountingLine).getPositionNumber())) {
203                    pendingLedgerEntry.setPositionNumber(LaborConstants.getDashPositionNumber());
204                }
205    
206                String originationCode = SpringContext.getBean(HomeOriginationService.class).getHomeOrigination().getFinSystemHomeOriginationCode();
207                pendingLedgerEntry.setFinancialSystemOriginationCode(originationCode);
208    
209                pendingLedgerEntry.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter());
210    
211                this.getLaborLedgerPendingEntries().add(pendingLedgerEntry);
212    
213                sequenceHelper.increment();
214            }
215            catch (Exception e) {
216                LOG.error("Cannot add a Labor Ledger Pending Entry into the list");
217                return false;
218            }
219    
220            return true;
221        }
222    
223        /**
224         * If the document has a total amount, call method on document to get the total and set in doc header.
225         * 
226         * @see org.kuali.rice.kns.document.Document#prepareForSave()
227         */
228        @Override
229        public void prepareForSave() {
230            if (!SpringContext.getBean(LaborLedgerPendingEntryService.class).generateLaborLedgerPendingEntries(this)) {
231                logErrors();
232                throw new ValidationException("labor ledger LLPE generation failed");
233            }
234    
235            super.prepareForSave();
236        }
237    
238        /**
239         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#prepareForSave(org.kuali.rice.kns.rule.event.KualiDocumentEvent)
240         */
241        @Override
242        public void prepareForSave(KualiDocumentEvent event) {
243            this.prepareForSave();
244            super.prepareForSave(event);
245        }
246    
247        /**
248         * This is a "do nothing" version of the method - it just won't create GLPEs
249         * 
250         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#generateGeneralLedgerPendingEntries(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail,
251         *      org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper)
252         */
253        @Override
254        public boolean generateGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
255            return true;
256        }
257    
258        /**
259         * Labor docs never generate general ledger pending entries, and therefore, this method is never called, but we always return
260         * true, since we're required to have a concrete representation
261         * 
262         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#isDebit(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail)
263         */
264        @Override
265        public boolean isDebit(GeneralLedgerPendingEntrySourceDetail postable) {
266            return true;
267        }
268        
269        public List getLaborLedgerPendingEntriesForSearching() {
270            return getLaborLedgerPendingEntries();
271        }
272    }