001/* 002 * The Kuali Financial System, a comprehensive financial management system for higher education. 003 * 004 * Copyright 2005-2014 The Kuali Foundation 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU Affero General Public License as 008 * published by the Free Software Foundation, either version 3 of the 009 * License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU Affero General Public License for more details. 015 * 016 * You should have received a copy of the GNU Affero General Public License 017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package org.kuali.kfs.fp.document; 020 021import java.util.ArrayList; 022import java.util.List; 023 024import org.kuali.kfs.fp.businessobject.AdvanceDepositDetail; 025import org.kuali.kfs.sys.KFSConstants; 026import org.kuali.kfs.sys.KFSKeyConstants; 027import org.kuali.kfs.sys.KFSPropertyConstants; 028import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry; 029import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper; 030import org.kuali.kfs.sys.context.SpringContext; 031import org.kuali.kfs.sys.document.AmountTotaling; 032import org.kuali.kfs.sys.document.Correctable; 033import org.kuali.kfs.sys.document.service.AccountingDocumentRuleHelperService; 034import org.kuali.kfs.sys.service.BankService; 035import org.kuali.kfs.sys.service.ElectronicPaymentClaimingService; 036import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService; 037import org.kuali.rice.core.api.util.type.KualiDecimal; 038import org.kuali.rice.core.web.format.CurrencyFormatter; 039import org.kuali.rice.kew.api.exception.WorkflowException; 040import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange; 041import org.kuali.rice.kns.service.DataDictionaryService; 042import org.kuali.rice.krad.document.Copyable; 043import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent; 044import org.kuali.rice.krad.rules.rule.event.SaveDocumentEvent; 045 046/** 047 * This is the business object that represents the AdvanceDeposit document in Kuali. This is a transactional document that will 048 * eventually post transactions to the G/L. It integrates with workflow. Since an Advance Deposit document is a one sided 049 * transactional document, only accepting funds into the university, the accounting line data will be held in the source accounting 050 * line data structure only. 051 */ 052public class AdvanceDepositDocument extends CashReceiptFamilyBase implements Copyable, AmountTotaling, Correctable { 053 public static final String ADVANCE_DEPOSIT_DOCUMENT_TYPE_CODE = "AD"; 054 055 // holds details about each advance deposit 056 protected List<AdvanceDepositDetail> advanceDeposits = new ArrayList<AdvanceDepositDetail>(); 057 058 // incrementers for detail lines 059 protected Integer nextAdvanceDepositLineNumber = 1; 060 061 // monetary attributes 062 protected KualiDecimal totalAdvanceDepositAmount = KualiDecimal.ZERO; 063 064 /** 065 * Default constructor that calls super. 066 */ 067 public AdvanceDepositDocument() { 068 super(); 069 } 070 071 /** 072 * Gets the total advance deposit amount. 073 * 074 * @return KualiDecimal 075 */ 076 public KualiDecimal getTotalAdvanceDepositAmount() { 077 return totalAdvanceDepositAmount; 078 } 079 080 /** 081 * This method returns the advance deposit total amount as a currency formatted string. 082 * 083 * @return String 084 */ 085 public String getCurrencyFormattedTotalAdvanceDepositAmount() { 086 return (String) new CurrencyFormatter().format(totalAdvanceDepositAmount); 087 } 088 089 /** 090 * Sets the total advance deposit amount which is the sum of all advance deposits on this document. 091 * 092 * @param advanceDepositAmount 093 */ 094 public void setTotalAdvanceDepositAmount(KualiDecimal advanceDepositAmount) { 095 this.totalAdvanceDepositAmount = advanceDepositAmount; 096 } 097 098 /** 099 * Gets the list of advance deposits which is a list of AdvanceDepositDetail business objects. 100 * 101 * @return List 102 */ 103 public List<AdvanceDepositDetail> getAdvanceDeposits() { 104 return advanceDeposits; 105 } 106 107 /** 108 * Sets the advance deposits list. 109 * 110 * @param advanceDeposits 111 */ 112 public void setAdvanceDeposits(List<AdvanceDepositDetail> advanceDeposits) { 113 this.advanceDeposits = advanceDeposits; 114 } 115 116 /** 117 * Adds a new advance deposit to the list. 118 * 119 * @param advanceDepositDetail 120 */ 121 public void addAdvanceDeposit(AdvanceDepositDetail advanceDepositDetail) { 122 // these three make up the primary key for an advance deposit detail record 123 prepareNewAdvanceDeposit(advanceDepositDetail); 124 125 // add the new detail record to the list 126 this.advanceDeposits.add(advanceDepositDetail); 127 128 // increment line number 129 this.nextAdvanceDepositLineNumber++; 130 131 // update the overall amount 132 this.totalAdvanceDepositAmount = this.totalAdvanceDepositAmount.add(advanceDepositDetail.getFinancialDocumentAdvanceDepositAmount()); 133 } 134 135 /** 136 * This is a helper method that automatically populates document specfic information into the advance deposit 137 * (AdvanceDepositDetail) instance. 138 * 139 * @param advanceDepositDetail 140 */ 141 public final void prepareNewAdvanceDeposit(AdvanceDepositDetail advanceDepositDetail) { 142 advanceDepositDetail.setFinancialDocumentLineNumber(this.nextAdvanceDepositLineNumber); 143 advanceDepositDetail.setDocumentNumber(this.getDocumentNumber()); 144 advanceDepositDetail.setFinancialDocumentTypeCode(SpringContext.getBean(DataDictionaryService.class).getDocumentTypeNameByClass(this.getClass())); 145 } 146 147 /** 148 * Retrieve a particular advance deposit at a given index in the list of advance deposits. 149 * 150 * @param index 151 * @return AdvanceDepositDetail 152 */ 153 public AdvanceDepositDetail getAdvanceDepositDetail(int index) { 154 while (this.advanceDeposits.size() <= index) { 155 advanceDeposits.add(new AdvanceDepositDetail()); 156 } 157 return advanceDeposits.get(index); 158 } 159 160 /** 161 * This method removes an advance deposit from the list and updates the total appropriately. 162 * 163 * @param index 164 */ 165 public void removeAdvanceDeposit(int index) { 166 AdvanceDepositDetail advanceDepositDetail = advanceDeposits.remove(index); 167 this.totalAdvanceDepositAmount = this.totalAdvanceDepositAmount.subtract(advanceDepositDetail.getFinancialDocumentAdvanceDepositAmount()); 168 } 169 170 /** 171 * @return Integer 172 */ 173 public Integer getNextAdvanceDepositLineNumber() { 174 return nextAdvanceDepositLineNumber; 175 } 176 177 /** 178 * @param nextAdvanceDepositLineNumber 179 */ 180 public void setNextAdvanceDepositLineNumber(Integer nextAdvanceDepositLineNumber) { 181 this.nextAdvanceDepositLineNumber = nextAdvanceDepositLineNumber; 182 } 183 184 /** 185 * This method returns the overall total of the document - the advance deposit total. 186 * 187 * @see org.kuali.kfs.sys.document.AccountingDocumentBase#getTotalDollarAmount() 188 * @return KualiDecimal 189 */ 190 @Override 191 public KualiDecimal getTotalDollarAmount() { 192 return this.totalAdvanceDepositAmount; 193 } 194 195 /** 196 * This method defers to its parent's version of handleRouteStatusChange, but then, if the document is processed, it creates 197 * ElectronicPaymentClaim records for any qualifying accountings lines in the document. 198 * 199 * @see org.kuali.kfs.sys.document.GeneralLedgerPostingDocumentBase#doRouteStatusChange() 200 */ 201 @Override 202 public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) { 203 super.doRouteStatusChange(statusChangeEvent); 204 if (getDocumentHeader().getWorkflowDocument().isProcessed()) { 205 SpringContext.getBean(ElectronicPaymentClaimingService.class).generateElectronicPaymentClaimRecords(this); 206 } 207 this.getCapitalAssetManagementModuleService().deleteDocumentAssetLocks(this); 208 } 209 210 211 /** 212 * Overrides super to call super and then also add in the new list of advance deposits that have to be managed. 213 * 214 * @see org.kuali.rice.krad.document.TransactionalDocumentBase#buildListOfDeletionAwareLists() 215 */ 216 @Override 217 public List buildListOfDeletionAwareLists() { 218 List managedLists = super.buildListOfDeletionAwareLists(); 219 managedLists.add(getAdvanceDeposits()); 220 221 return managedLists; 222 } 223 224 /** 225 * Generates bank offset GLPEs for deposits, if enabled. 226 * 227 * @param financialDocument submitted financial document 228 * @param sequenceHelper helper class which will allows us to increment a reference without using an Integer 229 * @return true if there are no issues creating GLPE's 230 * @see org.kuali.rice.krad.rule.GenerateGeneralLedgerDocumentPendingEntriesRule#processGenerateDocumentGeneralLedgerPendingEntries(org.kuali.rice.krad.document.FinancialDocument,org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper) 231 */ 232 @Override 233 public boolean generateDocumentGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySequenceHelper sequenceHelper) { 234 boolean success = true; 235 236 GeneralLedgerPendingEntryService glpeService = SpringContext.getBean(GeneralLedgerPendingEntryService.class); 237 238 if (SpringContext.getBean(BankService.class).isBankSpecificationEnabled()) { 239 int displayedDepositNumber = 1; 240 for (AdvanceDepositDetail detail : getAdvanceDeposits()) { 241 detail.refreshReferenceObject(KFSPropertyConstants.BANK); 242 243 GeneralLedgerPendingEntry bankOffsetEntry = new GeneralLedgerPendingEntry(); 244 if (!glpeService.populateBankOffsetGeneralLedgerPendingEntry(detail.getBank(), detail.getFinancialDocumentAdvanceDepositAmount(), this, getPostingYear(), sequenceHelper, bankOffsetEntry, KFSConstants.ADVANCE_DEPOSITS_LINE_ERRORS)) { 245 success = false; 246 continue; // An unsuccessfully populated bank offset entry may contain invalid relations, so don't add it 247 } 248 249 AccountingDocumentRuleHelperService accountingDocumentRuleUtil = SpringContext.getBean(AccountingDocumentRuleHelperService.class); 250 bankOffsetEntry.setTransactionLedgerEntryDescription(accountingDocumentRuleUtil.formatProperty(KFSKeyConstants.AdvanceDeposit.DESCRIPTION_GLPE_BANK_OFFSET, displayedDepositNumber++)); 251 addPendingEntry(bankOffsetEntry); 252 sequenceHelper.increment(); 253 254 GeneralLedgerPendingEntry offsetEntry = new GeneralLedgerPendingEntry(bankOffsetEntry); 255 success &= glpeService.populateOffsetGeneralLedgerPendingEntry(getPostingYear(), bankOffsetEntry, sequenceHelper, offsetEntry); 256 addPendingEntry(offsetEntry); 257 sequenceHelper.increment(); 258 } 259 } 260 261 return success; 262 } 263 264 @Override 265 public void postProcessSave(KualiDocumentEvent event) { 266 super.postProcessSave(event); 267 if (!(event instanceof SaveDocumentEvent)) { // don't lock until they route 268 String documentTypeName = SpringContext.getBean(DataDictionaryService.class).getDocumentTypeNameByClass(this.getClass()); 269 this.getCapitalAssetManagementModuleService().generateCapitalAssetLock(this,documentTypeName); 270 } 271 } 272 273 /** 274 * @see org.kuali.kfs.sys.document.AccountingDocumentBase#toErrorCorrection() 275 */ 276 @Override 277 public void toErrorCorrection() throws WorkflowException { 278 super.toErrorCorrection(); 279 correctAdvanceDepositDetails(); 280 correctCapitalAccountingLines(); 281 } 282 283 /** 284 * Upon error correction, negates amount in each advance deposit detail, and updates the documentNumber to point to the new document. 285 */ 286 protected void correctAdvanceDepositDetails() { 287 for (AdvanceDepositDetail deposit: advanceDeposits) { 288 deposit.setVersionNumber(new Long(1)); 289 deposit.setDocumentNumber(documentNumber); 290 deposit.setFinancialDocumentAdvanceDepositAmount(deposit.getFinancialDocumentAdvanceDepositAmount().negated()); 291 } 292 } 293 294}