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.fp.document;
017    
018    import java.util.ArrayList;
019    import java.util.List;
020    
021    import org.kuali.kfs.fp.businessobject.AdvanceDepositDetail;
022    import org.kuali.kfs.sys.KFSConstants;
023    import org.kuali.kfs.sys.KFSKeyConstants;
024    import org.kuali.kfs.sys.KFSPropertyConstants;
025    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry;
026    import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper;
027    import org.kuali.kfs.sys.context.SpringContext;
028    import org.kuali.kfs.sys.document.AmountTotaling;
029    import org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService;
030    import org.kuali.kfs.sys.service.BankService;
031    import org.kuali.kfs.sys.service.ElectronicPaymentClaimingService;
032    import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService;
033    import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
034    import org.kuali.rice.kns.document.Copyable;
035    import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
036    import org.kuali.rice.kns.rule.event.SaveDocumentEvent;
037    import org.kuali.rice.kns.service.DataDictionaryService;
038    import org.kuali.rice.kns.util.KualiDecimal;
039    import org.kuali.rice.kns.web.format.CurrencyFormatter;
040    
041    /**
042     * This is the business object that represents the AdvanceDeposit document in Kuali. This is a transactional document that will
043     * eventually post transactions to the G/L. It integrates with workflow. Since an Advance Deposit document is a one sided
044     * transactional document, only accepting funds into the university, the accounting line data will be held in the source accounting
045     * line data structure only.
046     */
047    public class AdvanceDepositDocument extends CashReceiptFamilyBase implements Copyable, AmountTotaling {
048        public static final String ADVANCE_DEPOSIT_DOCUMENT_TYPE_CODE = "AD";
049        
050        // holds details about each advance deposit
051        protected List<AdvanceDepositDetail> advanceDeposits = new ArrayList<AdvanceDepositDetail>();
052    
053        // incrementers for detail lines
054        protected Integer nextAdvanceDepositLineNumber = 1;
055    
056        // monetary attributes
057        protected KualiDecimal totalAdvanceDepositAmount = KualiDecimal.ZERO;
058    
059        /**
060         * Default constructor that calls super.
061         */
062        public AdvanceDepositDocument() {
063            super();
064        }
065    
066        /**
067         * Gets the total advance deposit amount.
068         * 
069         * @return KualiDecimal
070         */
071        public KualiDecimal getTotalAdvanceDepositAmount() {
072            return totalAdvanceDepositAmount;
073        }
074    
075        /**
076         * This method returns the advance deposit total amount as a currency formatted string.
077         * 
078         * @return String
079         */
080        public String getCurrencyFormattedTotalAdvanceDepositAmount() {
081            return (String) new CurrencyFormatter().format(totalAdvanceDepositAmount);
082        }
083    
084        /**
085         * Sets the total advance deposit amount which is the sum of all advance deposits on this document.
086         * 
087         * @param advanceDepositAmount
088         */
089        public void setTotalAdvanceDepositAmount(KualiDecimal advanceDepositAmount) {
090            this.totalAdvanceDepositAmount = advanceDepositAmount;
091        }
092    
093        /**
094         * Gets the list of advance deposits which is a list of AdvanceDepositDetail business objects.
095         * 
096         * @return List
097         */
098        public List<AdvanceDepositDetail> getAdvanceDeposits() {
099            return advanceDeposits;
100        }
101    
102        /**
103         * Sets the advance deposits list.
104         * 
105         * @param advanceDeposits
106         */
107        public void setAdvanceDeposits(List<AdvanceDepositDetail> advanceDeposits) {
108            this.advanceDeposits = advanceDeposits;
109        }
110    
111        /**
112         * Adds a new advance deposit to the list.
113         * 
114         * @param advanceDepositDetail
115         */
116        public void addAdvanceDeposit(AdvanceDepositDetail advanceDepositDetail) {
117            // these three make up the primary key for an advance deposit detail record
118            prepareNewAdvanceDeposit(advanceDepositDetail);
119    
120            // add the new detail record to the list
121            this.advanceDeposits.add(advanceDepositDetail);
122    
123            // increment line number
124            this.nextAdvanceDepositLineNumber++;
125    
126            // update the overall amount
127            this.totalAdvanceDepositAmount = this.totalAdvanceDepositAmount.add(advanceDepositDetail.getFinancialDocumentAdvanceDepositAmount());
128        }
129    
130        /**
131         * This is a helper method that automatically populates document specfic information into the advance deposit
132         * (AdvanceDepositDetail) instance.
133         * 
134         * @param advanceDepositDetail
135         */
136        public final void prepareNewAdvanceDeposit(AdvanceDepositDetail advanceDepositDetail) {
137            advanceDepositDetail.setFinancialDocumentLineNumber(this.nextAdvanceDepositLineNumber);
138            advanceDepositDetail.setFinancialDocumentColumnTypeCode(KFSConstants.AdvanceDepositConstants.CASH_RECEIPT_ADVANCE_DEPOSIT_COLUMN_TYPE_CODE);
139            advanceDepositDetail.setDocumentNumber(this.getDocumentNumber());
140            advanceDepositDetail.setFinancialDocumentTypeCode(SpringContext.getBean(DataDictionaryService.class).getDocumentTypeNameByClass(this.getClass()));
141        }
142    
143        /**
144         * Retrieve a particular advance deposit at a given index in the list of advance deposits.
145         * 
146         * @param index
147         * @return AdvanceDepositDetail
148         */
149        public AdvanceDepositDetail getAdvanceDepositDetail(int index) {
150            while (this.advanceDeposits.size() <= index) {
151                advanceDeposits.add(new AdvanceDepositDetail());
152            }
153            return advanceDeposits.get(index);
154        }
155    
156        /**
157         * This method removes an advance deposit from the list and updates the total appropriately.
158         * 
159         * @param index
160         */
161        public void removeAdvanceDeposit(int index) {
162            AdvanceDepositDetail advanceDepositDetail = advanceDeposits.remove(index);
163            this.totalAdvanceDepositAmount = this.totalAdvanceDepositAmount.subtract(advanceDepositDetail.getFinancialDocumentAdvanceDepositAmount());
164        }
165    
166        /**
167         * @return Integer
168         */
169        public Integer getNextAdvanceDepositLineNumber() {
170            return nextAdvanceDepositLineNumber;
171        }
172    
173        /**
174         * @param nextAdvanceDepositLineNumber
175         */
176        public void setNextAdvanceDepositLineNumber(Integer nextAdvanceDepositLineNumber) {
177            this.nextAdvanceDepositLineNumber = nextAdvanceDepositLineNumber;
178        }
179    
180        /**
181         * This method returns the overall total of the document - the advance deposit total.
182         * 
183         * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getTotalDollarAmount()
184         * @return KualiDecimal
185         */
186        @Override
187        public KualiDecimal getTotalDollarAmount() {
188            return this.totalAdvanceDepositAmount;
189        }
190    
191        /**
192         * This method defers to its parent's version of handleRouteStatusChange, but then, if the document is processed, it creates
193         * ElectronicPaymentClaim records for any qualifying accountings lines in the document.
194         * 
195         * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocumentBase#doRouteStatusChange()
196         */
197        @Override
198        public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) {
199            super.doRouteStatusChange(statusChangeEvent);
200            if (getDocumentHeader().getWorkflowDocument().stateIsProcessed()) {
201                SpringContext.getBean(ElectronicPaymentClaimingService.class).generateElectronicPaymentClaimRecords(this);
202            }
203            this.getCapitalAssetManagementModuleService().deleteDocumentAssetLocks(this); 
204        }
205    
206    
207        /**
208         * Overrides super to call super and then also add in the new list of advance deposits that have to be managed.
209         * 
210         * @see org.kuali.rice.kns.document.TransactionalDocumentBase#buildListOfDeletionAwareLists()
211         */
212        @Override
213        public List buildListOfDeletionAwareLists() {
214            List managedLists = super.buildListOfDeletionAwareLists();
215            managedLists.add(getAdvanceDeposits());
216    
217            return managedLists;
218        }
219    
220        /**
221         * Generates bank offset GLPEs for deposits, if enabled.
222         * 
223         * @param financialDocument submitted financial document
224         * @param sequenceHelper helper class which will allows us to increment a reference without using an Integer
225         * @return true if there are no issues creating GLPE's
226         * @see org.kuali.rice.kns.rule.GenerateGeneralLedgerDocumentPendingEntriesRule#processGenerateDocumentGeneralLedgerPendingEntries(org.kuali.rice.kns.document.FinancialDocument,org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper)
227         */
228        @Override
229        public boolean generateDocumentGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySequenceHelper sequenceHelper) {
230            boolean success = true;
231    
232            GeneralLedgerPendingEntryService glpeService = SpringContext.getBean(GeneralLedgerPendingEntryService.class);
233    
234            if (SpringContext.getBean(BankService.class).isBankSpecificationEnabled()) {
235                int displayedDepositNumber = 1;
236                for (AdvanceDepositDetail detail : getAdvanceDeposits()) {
237                    detail.refreshReferenceObject(KFSPropertyConstants.BANK);
238    
239                    GeneralLedgerPendingEntry bankOffsetEntry = new GeneralLedgerPendingEntry();
240                    if (!glpeService.populateBankOffsetGeneralLedgerPendingEntry(detail.getBank(), detail.getFinancialDocumentAdvanceDepositAmount(), this, getPostingYear(), sequenceHelper, bankOffsetEntry, KFSConstants.ADVANCE_DEPOSITS_LINE_ERRORS)) {
241                        success = false;
242                        continue; // An unsuccessfully populated bank offset entry may contain invalid relations, so don't add it
243                    }
244    
245                    AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class);
246                    bankOffsetEntry.setTransactionLedgerEntryDescription(accountingDocumentRuleUtil.formatProperty(KFSKeyConstants.AdvanceDeposit.DESCRIPTION_GLPE_BANK_OFFSET, displayedDepositNumber++));
247                    addPendingEntry(bankOffsetEntry);
248                    sequenceHelper.increment();
249    
250                    GeneralLedgerPendingEntry offsetEntry = new GeneralLedgerPendingEntry(bankOffsetEntry);
251                    success &= glpeService.populateOffsetGeneralLedgerPendingEntry(getPostingYear(), bankOffsetEntry, sequenceHelper, offsetEntry);
252                    addPendingEntry(offsetEntry);
253                    sequenceHelper.increment();
254                }
255            }
256    
257            return success;
258        }
259    
260        
261        @Override
262        public void postProcessSave(KualiDocumentEvent event) {
263            super.postProcessSave(event);
264            if (!(event instanceof SaveDocumentEvent)) { // don't lock until they route
265                String documentTypeName = SpringContext.getBean(DataDictionaryService.class).getDocumentTypeNameByClass(this.getClass());
266                this.getCapitalAssetManagementModuleService().generateCapitalAssetLock(this,documentTypeName);
267            }        
268        }
269    }