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    
017    package org.kuali.kfs.fp.document;
018    
019    import java.util.ArrayList;
020    import java.util.Iterator;
021    import java.util.LinkedHashMap;
022    import java.util.List;
023    
024    import org.kuali.kfs.fp.businessobject.CapitalAssetInformation;
025    import org.kuali.kfs.fp.businessobject.ProcurementCardHolder;
026    import org.kuali.kfs.fp.businessobject.ProcurementCardSourceAccountingLine;
027    import org.kuali.kfs.fp.businessobject.ProcurementCardTargetAccountingLine;
028    import org.kuali.kfs.fp.businessobject.ProcurementCardTransactionDetail;
029    import org.kuali.kfs.integration.cam.CapitalAssetManagementModuleService;
030    import org.kuali.kfs.sys.KFSPropertyConstants;
031    import org.kuali.kfs.sys.businessobject.AccountingLine;
032    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail;
033    import org.kuali.kfs.sys.businessobject.SourceAccountingLine;
034    import org.kuali.kfs.sys.businessobject.TargetAccountingLine;
035    import org.kuali.kfs.sys.context.SpringContext;
036    import org.kuali.kfs.sys.document.AccountingDocumentBase;
037    import org.kuali.kfs.sys.document.AmountTotaling;
038    import org.kuali.kfs.sys.document.service.DebitDeterminerService;
039    import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
040    import org.kuali.rice.kew.util.KEWConstants;
041    import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
042    import org.kuali.rice.kns.rule.event.SaveDocumentEvent;
043    import org.kuali.rice.kns.service.DataDictionaryService;
044    import org.kuali.rice.kns.util.ObjectUtils;
045    import org.kuali.rice.kns.util.TypedArrayList;
046    
047    /**
048     * This is the Procurement Card Document Class. The procurement cards distributes expenses from clearing accounts. It is a two-sided
049     * document, but only target lines are displayed because source lines cannot be changed. Transaction, Card, and Vendor information
050     * are associated with the document to help better distribute the expense.
051     */
052    public class ProcurementCardDocument extends AccountingDocumentBase implements AmountTotaling, CapitalAssetEditable {
053        protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ProcurementCardDocument.class);
054    
055        protected ProcurementCardHolder procurementCardHolder;
056    
057        protected List transactionEntries;
058    
059        protected transient CapitalAssetInformation capitalAssetInformation;
060        protected transient CapitalAssetManagementModuleService capitalAssetManagementModuleService;
061    
062        /**
063         * Default constructor.
064         */
065        public ProcurementCardDocument() {
066            super();
067            transactionEntries = new TypedArrayList(ProcurementCardTransactionDetail.class);
068            // Save Capital Asset Information for PCard document when created.
069            this.capitalAssetInformation = new CapitalAssetInformation();
070        }
071    
072        /**
073         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#buildListOfDeletionAwareLists()
074         */
075        @Override
076        public List buildListOfDeletionAwareLists() {
077            List<List> managedLists = super.buildListOfDeletionAwareLists();
078            if (ObjectUtils.isNotNull(capitalAssetInformation) && ObjectUtils.isNotNull(capitalAssetInformation.getCapitalAssetInformationDetails())) {
079                managedLists.add(capitalAssetInformation.getCapitalAssetInformationDetails());
080            }
081            return managedLists;
082        }
083    
084        /**
085         * @return Returns the transactionEntries.
086         */
087        public List getTransactionEntries() {
088            return transactionEntries;
089        }
090    
091        /**
092         * @param transactionEntries The transactionEntries to set.
093         */
094        public void setTransactionEntries(List transactionEntries) {
095            this.transactionEntries = transactionEntries;
096        }
097    
098        /**
099         * Gets the procurementCardHolder attribute.
100         * 
101         * @return Returns the procurementCardHolder.
102         */
103        public ProcurementCardHolder getProcurementCardHolder() {
104            return procurementCardHolder;
105        }
106    
107        /**
108         * Sets the procurementCardHolder attribute value.
109         * 
110         * @param procurementCardHolder The procurementCardHolder to set.
111         */
112        public void setProcurementCardHolder(ProcurementCardHolder procurementCardHolder) {
113            this.procurementCardHolder = procurementCardHolder;
114        }
115    
116        /**
117         * Removes the target accounting line at the given index from the transaction detail entry.
118         * 
119         * @param index
120         */
121        public void removeTargetAccountingLine(int index) {
122            ProcurementCardTargetAccountingLine line = (ProcurementCardTargetAccountingLine) getTargetAccountingLines().get(index);
123    
124            for (Iterator iter = transactionEntries.iterator(); iter.hasNext();) {
125                ProcurementCardTransactionDetail transactionEntry = (ProcurementCardTransactionDetail) iter.next();
126                if (transactionEntry.getFinancialDocumentTransactionLineNumber().equals(line.getFinancialDocumentTransactionLineNumber())) {
127                    transactionEntry.getTargetAccountingLines().remove(line);
128                }
129            }
130        }
131    
132        /**
133         * Override to set the accounting line in the transaction detail object.
134         * 
135         * @see org.kuali.kfs.sys.document.AccountingDocument#addSourceAccountingLine(SourceAccountingLine)
136         */
137        @Override
138        public void addSourceAccountingLine(SourceAccountingLine sourceLine) {
139            ProcurementCardSourceAccountingLine line = (ProcurementCardSourceAccountingLine) sourceLine;
140    
141            line.setSequenceNumber(this.getNextSourceLineNumber());
142    
143            for (Iterator iter = transactionEntries.iterator(); iter.hasNext();) {
144                ProcurementCardTransactionDetail transactionEntry = (ProcurementCardTransactionDetail) iter.next();
145                if (transactionEntry.getFinancialDocumentTransactionLineNumber().equals(line.getFinancialDocumentTransactionLineNumber())) {
146                    transactionEntry.getSourceAccountingLines().add(line);
147                }
148            }
149    
150            this.nextSourceLineNumber = new Integer(this.getNextSourceLineNumber().intValue() + 1);
151        }
152    
153        /**
154         * Override to set the accounting line in the transaction detail object.
155         * 
156         * @see org.kuali.kfs.sys.document.AccountingDocument#addTargetAccountingLine(TargetAccountingLine)
157         */
158        @Override
159        public void addTargetAccountingLine(TargetAccountingLine targetLine) {
160            ProcurementCardTargetAccountingLine line = (ProcurementCardTargetAccountingLine) targetLine;
161    
162            line.setSequenceNumber(this.getNextTargetLineNumber());
163    
164            for (Iterator iter = transactionEntries.iterator(); iter.hasNext();) {
165                ProcurementCardTransactionDetail transactionEntry = (ProcurementCardTransactionDetail) iter.next();
166                if (transactionEntry.getFinancialDocumentTransactionLineNumber().equals(line.getFinancialDocumentTransactionLineNumber())) {
167                    transactionEntry.getTargetAccountingLines().add(line);
168                }
169            }
170    
171            this.nextTargetLineNumber = new Integer(this.getNextTargetLineNumber().intValue() + 1);
172        }
173    
174        /**
175         * Override to get source accounting lines out of transactions
176         * 
177         * @see org.kuali.kfs.sys.document.AccountingDocument#getSourceAccountingLines()
178         */
179        @Override
180        public List getSourceAccountingLines() {
181            List sourceAccountingLines = new ArrayList();
182    
183            for (Iterator iter = transactionEntries.iterator(); iter.hasNext();) {
184                ProcurementCardTransactionDetail transactionEntry = (ProcurementCardTransactionDetail) iter.next();
185                for (Iterator iterator = transactionEntry.getSourceAccountingLines().iterator(); iterator.hasNext();) {
186                    SourceAccountingLine sourceLine = (SourceAccountingLine) iterator.next();
187                    sourceAccountingLines.add(sourceLine);
188                }
189            }
190    
191            return sourceAccountingLines;
192        }
193    
194        /**
195         * Override to get target accounting lines out of transactions
196         * 
197         * @see org.kuali.kfs.sys.document.AccountingDocument#getTargetAccountingLines()
198         */
199        @Override
200        public List getTargetAccountingLines() {
201            List targetAccountingLines = new ArrayList();
202    
203            for (Iterator iter = transactionEntries.iterator(); iter.hasNext();) {
204                ProcurementCardTransactionDetail transactionEntry = (ProcurementCardTransactionDetail) iter.next();
205                for (Iterator iterator = transactionEntry.getTargetAccountingLines().iterator(); iterator.hasNext();) {
206                    TargetAccountingLine targetLine = (TargetAccountingLine) iterator.next();
207                    targetAccountingLines.add(targetLine);
208                }
209            }
210    
211            return targetAccountingLines;
212        }
213    
214        /**
215         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getSourceAccountingLineClass()
216         */
217        @Override
218        public Class getSourceAccountingLineClass() {
219            return ProcurementCardSourceAccountingLine.class;
220        }
221    
222        /**
223         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getTargetAccountingLineClass()
224         */
225        @Override
226        public Class getTargetAccountingLineClass() {
227            return ProcurementCardTargetAccountingLine.class;
228        }
229    
230        /**
231         * @see org.kuali.rice.kns.bo.BusinessObjectBase#toStringMapper()
232         */
233        @Override
234        protected LinkedHashMap toStringMapper() {
235            LinkedHashMap m = new LinkedHashMap();
236            m.put(KFSPropertyConstants.DOCUMENT_NUMBER, this.documentNumber);
237            return m;
238        }
239    
240        @Override
241        public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) {
242            super.doRouteStatusChange(statusChangeEvent);
243    
244            // Updating for rice-1.0.0 api changes. doRouteStatusChange() went away, so
245            // that functionality needs to be a part of doRouteStatusChange now.
246            // handleRouteStatusChange did not happen on a save
247            if (!KEWConstants.ACTION_TAKEN_SAVED_CD.equals(statusChangeEvent.getDocumentEventCode())) {
248                this.getCapitalAssetManagementModuleService().deleteDocumentAssetLocks(this);
249            }
250        }
251    
252        /**
253         * On procurement card documents, positive source amounts are credits, negative source amounts are debits.
254         * 
255         * @param transactionalDocument The document the accounting line being checked is located in.
256         * @param accountingLine The accounting line being analyzed.
257         * @return True if the accounting line given is a debit accounting line, false otherwise.
258         * @throws Throws an IllegalStateException if one of the following rules are violated: the accounting line amount is zero or the
259         *         accounting line is not an expense or income accounting line.
260         * @see org.kuali.module.financial.rules.FinancialDocumentRuleBase#isDebit(FinancialDocument,
261         *      org.kuali.rice.kns.bo.AccountingLine)
262         * @see org.kuali.kfs.sys.document.validation.impl.AccountingDocumentRuleBase.IsDebitUtils#isDebitConsideringSection(AccountingDocumentRuleBase,
263         *      AccountingDocument, AccountingLine)
264         */
265        public boolean isDebit(GeneralLedgerPendingEntrySourceDetail postable) throws IllegalStateException {
266            // disallow error correction
267            DebitDeterminerService isDebitUtils = SpringContext.getBean(DebitDeterminerService.class);
268            isDebitUtils.disallowErrorCorrectionDocumentCheck(this);
269            return isDebitUtils.isDebitConsideringSection(this, (AccountingLine) postable);
270        }
271    
272        /**
273         * Gets the capitalAssetInformation attribute.
274         * 
275         * @return Returns the capitalAssetInformation.
276         */
277        public CapitalAssetInformation getCapitalAssetInformation() {
278            return ObjectUtils.isNull(capitalAssetInformation) ? null : capitalAssetInformation;
279        }
280    
281        /**
282         * Sets the capitalAssetInformation attribute value.
283         * 
284         * @param capitalAssetInformation The capitalAssetInformation to set.
285         */
286        @Deprecated
287        public void setCapitalAssetInformation(CapitalAssetInformation capitalAssetInformation) {
288            this.capitalAssetInformation = capitalAssetInformation;
289        }
290    
291        /**
292         * @see org.kuali.rice.kns.document.DocumentBase#postProcessSave(org.kuali.rice.kns.rule.event.KualiDocumentEvent)
293         */
294        @Override
295        public void postProcessSave(KualiDocumentEvent event) {
296            super.postProcessSave(event);
297            if (!(event instanceof SaveDocumentEvent)) { // don't lock until they route
298                String documentTypeName = SpringContext.getBean(DataDictionaryService.class).getDocumentTypeNameByClass(this.getClass());
299                this.getCapitalAssetManagementModuleService().generateCapitalAssetLock(this, documentTypeName);
300            }
301        }
302    
303        /**
304         * @return CapitalAssetManagementModuleService
305         */
306        protected CapitalAssetManagementModuleService getCapitalAssetManagementModuleService() {
307            if (capitalAssetManagementModuleService == null) {
308                capitalAssetManagementModuleService = SpringContext.getBean(CapitalAssetManagementModuleService.class);
309            }
310            return capitalAssetManagementModuleService;
311        }
312    
313    }