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.ar.document; 017 018 import java.util.ArrayList; 019 import java.util.Collection; 020 import java.util.HashMap; 021 import java.util.List; 022 import java.util.Map; 023 024 import org.apache.commons.lang.StringUtils; 025 import org.kuali.kfs.coa.businessobject.Account; 026 import org.kuali.kfs.coa.businessobject.ObjectCode; 027 import org.kuali.kfs.coa.businessobject.OffsetDefinition; 028 import org.kuali.kfs.coa.service.BalanceTypeService; 029 import org.kuali.kfs.coa.service.OffsetDefinitionService; 030 import org.kuali.kfs.module.ar.ArConstants; 031 import org.kuali.kfs.module.ar.businessobject.AccountsReceivableDocumentHeader; 032 import org.kuali.kfs.module.ar.businessobject.CashControlDetail; 033 import org.kuali.kfs.module.ar.businessobject.CustomerInvoiceDetail; 034 import org.kuali.kfs.module.ar.businessobject.InvoicePaidApplied; 035 import org.kuali.kfs.module.ar.businessobject.NonAppliedDistribution; 036 import org.kuali.kfs.module.ar.businessobject.NonAppliedHolding; 037 import org.kuali.kfs.module.ar.businessobject.NonInvoiced; 038 import org.kuali.kfs.module.ar.businessobject.NonInvoicedDistribution; 039 import org.kuali.kfs.module.ar.businessobject.ReceivableCustomerInvoiceDetail; 040 import org.kuali.kfs.module.ar.businessobject.SystemInformation; 041 import org.kuali.kfs.module.ar.document.service.CustomerInvoiceDocumentService; 042 import org.kuali.kfs.module.ar.document.service.NonAppliedHoldingService; 043 import org.kuali.kfs.module.ar.document.service.PaymentApplicationDocumentService; 044 import org.kuali.kfs.module.ar.document.service.SystemInformationService; 045 import org.kuali.kfs.sys.KFSConstants; 046 import org.kuali.kfs.sys.businessobject.ChartOrgHolder; 047 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntry; 048 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper; 049 import org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySourceDetail; 050 import org.kuali.kfs.sys.context.SpringContext; 051 import org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource; 052 import org.kuali.kfs.sys.document.GeneralLedgerPostingDocumentBase; 053 import org.kuali.kfs.sys.service.FinancialSystemUserService; 054 import org.kuali.kfs.sys.service.GeneralLedgerPendingEntryService; 055 import org.kuali.kfs.sys.service.UniversityDateService; 056 import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO; 057 import org.kuali.rice.kew.exception.WorkflowException; 058 import org.kuali.rice.kim.bo.Person; 059 import org.kuali.rice.kim.service.PersonService; 060 import org.kuali.rice.kns.exception.ValidationException; 061 import org.kuali.rice.kns.rule.event.BlanketApproveDocumentEvent; 062 import org.kuali.rice.kns.rule.event.KualiDocumentEvent; 063 import org.kuali.rice.kns.rule.event.RouteDocumentEvent; 064 import org.kuali.rice.kns.service.BusinessObjectService; 065 import org.kuali.rice.kns.service.DataDictionaryService; 066 import org.kuali.rice.kns.service.DateTimeService; 067 import org.kuali.rice.kns.service.DocumentService; 068 import org.kuali.rice.kns.service.ParameterService; 069 import org.kuali.rice.kns.util.GlobalVariables; 070 import org.kuali.rice.kns.util.KualiDecimal; 071 import org.kuali.rice.kns.util.ObjectUtils; 072 073 public class PaymentApplicationDocument extends GeneralLedgerPostingDocumentBase implements GeneralLedgerPendingEntrySource { 074 075 protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentApplicationDocument.class); 076 077 protected static final String LAUNCHED_FROM_BATCH = "LaunchedBySystemUser"; 078 079 protected String hiddenFieldForErrors; 080 protected List<InvoicePaidApplied> invoicePaidApplieds; 081 protected List<NonInvoiced> nonInvoiceds; 082 protected Collection<NonInvoicedDistribution> nonInvoicedDistributions; 083 protected Collection<NonAppliedDistribution> nonAppliedDistributions; 084 protected NonAppliedHolding nonAppliedHolding; 085 protected AccountsReceivableDocumentHeader accountsReceivableDocumentHeader; 086 087 protected transient PaymentApplicationDocumentService paymentApplicationDocumentService; 088 protected transient CashControlDetail cashControlDetail; 089 protected transient FinancialSystemUserService fsUserService; 090 protected transient CustomerInvoiceDocumentService invoiceDocService; 091 protected transient DocumentService docService; 092 protected transient NonAppliedHoldingService nonAppliedHoldingService; 093 protected transient BusinessObjectService boService; 094 095 // used for non-cash-control payapps 096 protected ArrayList<NonAppliedHolding> nonAppliedHoldingsForCustomer; // control docs for non-cash-control payapps 097 098 public PaymentApplicationDocument() { 099 super(); 100 this.invoicePaidApplieds = new ArrayList<InvoicePaidApplied>(); 101 this.nonInvoiceds = new ArrayList<NonInvoiced>(); 102 this.nonInvoicedDistributions = new ArrayList<NonInvoicedDistribution>(); 103 this.nonAppliedDistributions = new ArrayList<NonAppliedDistribution>(); 104 this.nonAppliedHoldingsForCustomer = new ArrayList<NonAppliedHolding>(); 105 } 106 107 /** 108 * Returns the PaymentMediumIdentifier on the associated CashControlDetail, 109 * if one exists, otherwise returns null. 110 * @return CustomerPaymentMediumIdentifier from the associated CashControlDetail if 111 * one exists, otherwise null. 112 */ 113 public String getPaymentNumber() { 114 return hasCashControlDetail() ? getCashControlDetail().getCustomerPaymentMediumIdentifier() : null; 115 } 116 117 public boolean hasCashControlDocument() { 118 return (getCashControlDocument() != null); 119 } 120 121 /** 122 * @return 123 * @throws WorkflowException 124 */ 125 public CashControlDocument getCashControlDocument() { 126 CashControlDetail cashControlDetail = getCashControlDetail(); 127 if(ObjectUtils.isNull(cashControlDetail)) { 128 return null; 129 } 130 return cashControlDetail.getCashControlDocument(); 131 } 132 133 public boolean hasCashControlDetail() { 134 return (null != getCashControlDetail()); 135 } 136 137 /** 138 * @return 139 * @throws WorkflowException 140 */ 141 public CashControlDetail getCashControlDetail() { 142 if (cashControlDetail == null) { 143 cashControlDetail = getPaymentApplicationDocumentService().getCashControlDetailForPayAppDocNumber(getDocumentNumber()); 144 } 145 return cashControlDetail; 146 } 147 148 public void setCashControlDetail(CashControlDetail cashControlDetail) { 149 this.cashControlDetail = cashControlDetail; 150 } 151 152 /** 153 * This method calculates the total amount available to be applied on this document. 154 * 155 * @return The total from the cash control detail if this is a 156 * cash-control based payapp. Otherwise, it just returns the total 157 * available to be applied from previously unapplied holdings. 158 */ 159 public KualiDecimal getTotalFromControl() { 160 if (hasCashControlDetail()) { 161 return getCashControlDetail().getFinancialDocumentLineAmount(); 162 } 163 else { 164 return getNonAppliedControlAvailableUnappliedAmount(); 165 } 166 } 167 168 /** 169 * This method calculates the total amount available to be applied from 170 * previously unapplied funds for the associated customer. 171 * 172 * @return The total amount of previously NonApplied funds available 173 * to apply to invoices and other applications on this document. 174 */ 175 public KualiDecimal getNonAppliedControlAvailableUnappliedAmount() { 176 KualiDecimal amount = KualiDecimal.ZERO; 177 for (NonAppliedHolding nonAppliedHolding : nonAppliedHoldingsForCustomer) { 178 amount = amount.add(nonAppliedHolding.getAvailableUnappliedAmount()); 179 } 180 return amount; 181 } 182 183 /** 184 * @return the sum of all invoice paid applieds. 185 */ 186 public KualiDecimal getSumOfInvoicePaidApplieds() { 187 KualiDecimal amount = KualiDecimal.ZERO; 188 for(InvoicePaidApplied payment : getInvoicePaidApplieds()) { 189 KualiDecimal _amount = payment.getInvoiceItemAppliedAmount(); 190 if (null == _amount) { _amount = KualiDecimal.ZERO; } 191 amount = amount.add(_amount); 192 } 193 return amount; 194 } 195 196 /** 197 * @return the sum of all non-invoiced amounts 198 */ 199 public KualiDecimal getSumOfNonInvoiceds() { 200 KualiDecimal total = KualiDecimal.ZERO; 201 for(NonInvoiced payment : getNonInvoiceds()) { 202 total = total.add(payment.getFinancialDocumentLineAmount()); 203 } 204 return total; 205 } 206 207 /** 208 * @return the sum of all non-invoiced distributions 209 */ 210 public KualiDecimal getSumOfNonInvoicedDistributions() { 211 KualiDecimal amount = KualiDecimal.ZERO; 212 for(NonInvoicedDistribution nonInvoicedDistribution : getNonInvoicedDistributions()) { 213 amount = amount.add(nonInvoicedDistribution.getFinancialDocumentLineAmount()); 214 } 215 return amount; 216 } 217 218 /** 219 * @return the sum of all non-applied distributions 220 */ 221 public KualiDecimal getSumOfNonAppliedDistributions() { 222 KualiDecimal amount = KualiDecimal.ZERO; 223 for(NonAppliedDistribution nonAppliedDistribution : getNonAppliedDistributions()) { 224 amount = amount.add(nonAppliedDistribution.getFinancialDocumentLineAmount()); 225 } 226 return amount; 227 } 228 229 /** 230 * @return the non-applied holding total. 231 */ 232 public KualiDecimal getNonAppliedHoldingAmount() { 233 if(ObjectUtils.isNull(getNonAppliedHolding())) { 234 return KualiDecimal.ZERO; 235 } 236 if(ObjectUtils.isNull(getNonAppliedHolding().getFinancialDocumentLineAmount())) { 237 return KualiDecimal.ZERO; 238 } 239 return getNonAppliedHolding().getFinancialDocumentLineAmount(); 240 } 241 242 /** 243 * This method returns the total amount allocated against the cash 244 * control total. 245 * 246 * @return 247 */ 248 public KualiDecimal getTotalApplied() { 249 KualiDecimal amount = KualiDecimal.ZERO; 250 amount = amount.add(getSumOfInvoicePaidApplieds()); 251 amount = amount.add(getSumOfNonInvoiceds()); 252 amount = amount.add(getNonAppliedHoldingAmount()); 253 return amount; 254 } 255 256 /** 257 * This method subtracts the sum of the invoice paid applieds, non-ar and 258 * unapplied totals from the outstanding amount received via the cash 259 * control document. 260 * 261 * NOTE this method is not useful for a non-cash control PayApp, as it 262 * doesnt have access to the control documents until it is saved. Use 263 * the same named method on the Form instead. 264 * 265 * @return 266 * @throws WorkflowException 267 */ 268 public KualiDecimal getUnallocatedBalance() { 269 270 KualiDecimal amount = getTotalFromControl(); 271 amount = amount.subtract(getTotalApplied()); 272 return amount; 273 } 274 275 public KualiDecimal getNonArTotal() { 276 KualiDecimal total = KualiDecimal.ZERO; 277 for (NonInvoiced item : getNonInvoiceds()) { 278 total = total.add(item.getFinancialDocumentLineAmount()); 279 } 280 return total; 281 } 282 283 public boolean isFinal() { 284 return isApproved(); 285 } 286 287 public boolean isApproved() { 288 return getDocumentHeader().getWorkflowDocument().stateIsApproved(); 289 } 290 291 /** 292 * 293 * This method is very specialized for a specific use. It 294 * retrieves the list of invoices that have been paid-applied 295 * by this PayApp document. 296 * 297 * It is only used to retrieve what invoices were applied to it, 298 * when the document is being viewed in Final state. 299 * 300 * @return 301 */ 302 public List<CustomerInvoiceDocument> getInvoicesPaidAgainst() { 303 List<CustomerInvoiceDocument> invoices = new ArrayList<CustomerInvoiceDocument>(); 304 305 // short circuit if no paidapplieds available 306 if (invoicePaidApplieds == null || invoicePaidApplieds.isEmpty()) { 307 return invoices; 308 } 309 310 // get the list of invoice docnumbers from paidapplieds 311 List<String> invoiceDocNumbers = new ArrayList<String>(); 312 for (InvoicePaidApplied paidApplied : invoicePaidApplieds) { 313 invoiceDocNumbers.add(paidApplied.getFinancialDocumentReferenceInvoiceNumber()); 314 } 315 316 // attempt to retrieve all the invoices paid applied against 317 try { 318 invoices.addAll(getDocService().getDocumentsByListOfDocumentHeaderIds(CustomerInvoiceDocument.class, invoiceDocNumbers)); 319 } 320 catch (WorkflowException e) { 321 throw new RuntimeException("A WorkflowException was thrown while trying to retrieve documents.", e); 322 } 323 return invoices; 324 } 325 326 /** 327 * 328 * This is a very specialized method, that is only intended to be used once the 329 * document is in a Final/Approved state. 330 * 331 * It retrieves the PaymentApplication documents that were used as a control source 332 * for this document, if any, or none, if none. 333 * 334 * @return 335 */ 336 public List<PaymentApplicationDocument> getPaymentApplicationDocumentsUsedAsControlDocuments() { 337 List<PaymentApplicationDocument> payApps = new ArrayList<PaymentApplicationDocument>(); 338 339 // short circuit if no non-applied-distributions available 340 if ((nonAppliedDistributions == null || nonAppliedDistributions.isEmpty()) && 341 (nonInvoicedDistributions == null || nonInvoicedDistributions.isEmpty())) { 342 return payApps; 343 } 344 345 // get the list of payapp docnumbers from non-applied-distributions 346 List<String> payAppDocNumbers = new ArrayList<String>(); 347 for (NonAppliedDistribution nonAppliedDistribution : nonAppliedDistributions) { 348 if (!payAppDocNumbers.contains(nonAppliedDistribution.getReferenceFinancialDocumentNumber())) { 349 payAppDocNumbers.add(nonAppliedDistribution.getReferenceFinancialDocumentNumber()); 350 } 351 } 352 353 // get the list of payapp docnumbers from non-applied-distributions 354 for (NonInvoicedDistribution nonInvoicedDistribution : nonInvoicedDistributions) { 355 if (!payAppDocNumbers.contains(nonInvoicedDistribution.getReferenceFinancialDocumentNumber())) { 356 payAppDocNumbers.add(nonInvoicedDistribution.getReferenceFinancialDocumentNumber()); 357 } 358 } 359 360 // exit out if no results, dont even try to retrieve 361 if (payAppDocNumbers.isEmpty()) { 362 return payApps; 363 } 364 365 // attempt to retrieve all the invoices paid applied against 366 try { 367 payApps.addAll(getDocService().getDocumentsByListOfDocumentHeaderIds(PaymentApplicationDocument.class, payAppDocNumbers)); 368 } 369 catch (WorkflowException e) { 370 throw new RuntimeException("A WorkflowException was thrown while trying to retrieve documents.", e); 371 } 372 return payApps; 373 } 374 375 public List<NonAppliedHolding> getNonAppliedHoldingsUsedAsControls() { 376 List<NonAppliedHolding> nonAppliedHoldingControls = new ArrayList<NonAppliedHolding>(); 377 378 // short circuit if no non-applied-distributions available 379 if ((nonAppliedDistributions == null || nonAppliedDistributions.isEmpty()) && 380 (nonInvoicedDistributions == null || nonInvoicedDistributions.isEmpty())) { 381 return nonAppliedHoldingControls; 382 } 383 384 // get the list of payapp docnumbers from non-applied-distributions 385 List<String> payAppDocNumbers = new ArrayList<String>(); 386 for (NonAppliedDistribution nonAppliedDistribution : nonAppliedDistributions) { 387 if (!payAppDocNumbers.contains(nonAppliedDistribution.getReferenceFinancialDocumentNumber())) { 388 payAppDocNumbers.add(nonAppliedDistribution.getReferenceFinancialDocumentNumber()); 389 } 390 } 391 392 // get the list of non-invoiced/non-ar distro payapp doc numbers 393 for (NonInvoicedDistribution nonInvoicedDistribution : nonInvoicedDistributions) { 394 if (!payAppDocNumbers.contains(nonInvoicedDistribution.getReferenceFinancialDocumentNumber())) { 395 payAppDocNumbers.add(nonInvoicedDistribution.getReferenceFinancialDocumentNumber()); 396 } 397 } 398 399 // attempt to retrieve all the non applied holdings used as controls 400 if (!payAppDocNumbers.isEmpty()) { 401 nonAppliedHoldingControls.addAll(getNonAppliedHoldingService().getNonAppliedHoldingsByListOfDocumentNumbers(payAppDocNumbers)); 402 } 403 return nonAppliedHoldingControls; 404 } 405 406 public List<InvoicePaidApplied> getInvoicePaidApplieds() { 407 return invoicePaidApplieds; 408 } 409 410 public void setInvoicePaidApplieds(List<InvoicePaidApplied> appliedPayments) { 411 this.invoicePaidApplieds = appliedPayments; 412 } 413 414 public List<NonInvoiced> getNonInvoiceds() { 415 return nonInvoiceds; 416 } 417 418 public void setNonInvoiceds(List<NonInvoiced> nonInvoiceds) { 419 this.nonInvoiceds = nonInvoiceds; 420 } 421 422 public Collection<NonInvoicedDistribution> getNonInvoicedDistributions() { 423 return nonInvoicedDistributions; 424 } 425 426 public void setNonInvoicedDistributions(Collection<NonInvoicedDistribution> nonInvoicedDistributions) { 427 this.nonInvoicedDistributions = nonInvoicedDistributions; 428 } 429 430 public Collection<NonAppliedDistribution> getNonAppliedDistributions() { 431 return nonAppliedDistributions; 432 } 433 434 public void setNonAppliedDistributions(Collection<NonAppliedDistribution> nonAppliedDistributions) { 435 this.nonAppliedDistributions = nonAppliedDistributions; 436 } 437 438 public NonAppliedHolding getNonAppliedHolding() { 439 return nonAppliedHolding; 440 } 441 442 public void setNonAppliedHolding(NonAppliedHolding nonAppliedHolding) { 443 this.nonAppliedHolding = nonAppliedHolding; 444 } 445 446 public AccountsReceivableDocumentHeader getAccountsReceivableDocumentHeader() { 447 return accountsReceivableDocumentHeader; 448 } 449 450 public void setAccountsReceivableDocumentHeader(AccountsReceivableDocumentHeader accountsReceivableDocumentHeader) { 451 this.accountsReceivableDocumentHeader = accountsReceivableDocumentHeader; 452 } 453 454 /** 455 * This method retrieves a specific applied payment from the list, by array index 456 * 457 * @param index the index of the applied payment to retrieve 458 * @return an InvoicePaidApplied 459 */ 460 public InvoicePaidApplied getInvoicePaidApplied(int index) { 461 462 return index < getInvoicePaidApplieds().size() ? getInvoicePaidApplieds().get(index) : new InvoicePaidApplied(); 463 } 464 465 /** 466 * This method retrieves a specific non invoiced payment from the list, by array index 467 * 468 * @param index the index of the non invoiced payment to retrieve 469 * @return an NonInvoiced 470 */ 471 public NonInvoiced getNonInvoiced(int index) { 472 return index < getNonInvoiceds().size() ? getNonInvoiceds().get(index) : new NonInvoiced(); 473 } 474 475 /** 476 * This method gets an ObjectCode from an invoice document. 477 * 478 * @param invoicePaidApplied 479 * @return 480 * @throws WorkflowException 481 */ 482 protected ObjectCode getInvoiceReceivableObjectCode(InvoicePaidApplied invoicePaidApplied) throws WorkflowException { 483 CustomerInvoiceDocument customerInvoiceDocument = invoicePaidApplied.getCustomerInvoiceDocument(); 484 CustomerInvoiceDetail customerInvoiceDetail = invoicePaidApplied.getInvoiceDetail(); 485 ReceivableCustomerInvoiceDetail receivableInvoiceDetail = new ReceivableCustomerInvoiceDetail(customerInvoiceDetail, customerInvoiceDocument); 486 ObjectCode objectCode = null; 487 if(ObjectUtils.isNotNull(receivableInvoiceDetail) && ObjectUtils.isNotNull(receivableInvoiceDetail.getFinancialObjectCode())) { 488 objectCode = receivableInvoiceDetail.getObjectCode(); 489 } 490 return objectCode; 491 } 492 493 /** 494 * @param sequenceHelper 495 * @return the pending entries for the document 496 */ 497 protected List<GeneralLedgerPendingEntry> createPendingEntries(GeneralLedgerPendingEntrySequenceHelper sequenceHelper) throws WorkflowException { 498 499 // Collection of all generated entries 500 List<GeneralLedgerPendingEntry> generatedEntries = new ArrayList<GeneralLedgerPendingEntry>(); 501 502 // Get handles to the services we need 503 GeneralLedgerPendingEntryService glpeService = SpringContext.getBean(GeneralLedgerPendingEntryService.class); 504 BalanceTypeService balanceTypeService = SpringContext.getBean(BalanceTypeService.class); 505 UniversityDateService universityDateService = SpringContext.getBean(UniversityDateService.class); 506 SystemInformationService systemInformationService = SpringContext.getBean(SystemInformationService.class); 507 OffsetDefinitionService offsetDefinitionService = SpringContext.getBean(OffsetDefinitionService.class); 508 ParameterService parameterService = SpringContext.getBean(ParameterService.class); 509 510 // Current fiscal year 511 Integer currentFiscalYear = universityDateService.getCurrentFiscalYear(); 512 513 // The processing chart and org comes from the the cash control document if there is one. 514 // If the payment application document is created from scratch though, then we pull it 515 // from the current user. Note that we're not checking here that the user actually belongs 516 // to a billing or processing org, we're assuming that is handled elsewhere. 517 String processingChartCode = null; 518 String processingOrganizationCode = null; 519 if (hasCashControlDocument()) { 520 processingChartCode = getCashControlDocument().getAccountsReceivableDocumentHeader().getProcessingChartOfAccountCode(); 521 processingOrganizationCode = getCashControlDocument().getAccountsReceivableDocumentHeader().getProcessingOrganizationCode(); 522 } 523 else { 524 Person currentUser = GlobalVariables.getUserSession().getPerson(); 525 ChartOrgHolder userOrg = getFsUserService().getPrimaryOrganization(currentUser.getPrincipalId(), ArConstants.AR_NAMESPACE_CODE); 526 processingChartCode = userOrg.getChartOfAccountsCode(); 527 processingOrganizationCode = userOrg.getOrganizationCode(); 528 } 529 530 // Some information comes from the cash control document 531 CashControlDocument cashControlDocument = getCashControlDocument(); 532 533 // Get the System Information 534 SystemInformation unappliedSystemInformation = 535 systemInformationService.getByProcessingChartOrgAndFiscalYear( 536 processingChartCode, processingOrganizationCode, currentFiscalYear); 537 538 // Get the university clearing account 539 unappliedSystemInformation.refreshReferenceObject("universityClearingAccount"); 540 Account universityClearingAccount = unappliedSystemInformation.getUniversityClearingAccount(); 541 542 // Get the university clearing object, object type and sub-object code 543 String unappliedSubAccountNumber = unappliedSystemInformation.getUniversityClearingSubAccountNumber(); 544 String unappliedObjectCode = unappliedSystemInformation.getUniversityClearingObjectCode(); 545 String unappliedObjectTypeCode = unappliedSystemInformation.getUniversityClearingObject().getFinancialObjectTypeCode(); 546 String unappliedSubObjectCode = unappliedSystemInformation.getUniversityClearingSubObjectCode(); 547 548 // Get the object code for the university clearing account. 549 SystemInformation universityClearingAccountSystemInformation = 550 systemInformationService.getByProcessingChartOrgAndFiscalYear( 551 processingChartCode, processingOrganizationCode, currentFiscalYear); 552 String universityClearingAccountObjectCode = universityClearingAccountSystemInformation.getUniversityClearingObjectCode(); 553 554 // Generate glpes for unapplied 555 NonAppliedHolding holding = getNonAppliedHolding(); 556 if(ObjectUtils.isNotNull(holding)) { 557 GeneralLedgerPendingEntry actualCreditUnapplied = new GeneralLedgerPendingEntry(); 558 actualCreditUnapplied.setUniversityFiscalYear(getPostingYear()); 559 actualCreditUnapplied.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 560 actualCreditUnapplied.setChartOfAccountsCode(universityClearingAccount.getChartOfAccountsCode()); 561 actualCreditUnapplied.setAccountNumber(universityClearingAccount.getAccountNumber()); 562 actualCreditUnapplied.setFinancialObjectCode(unappliedObjectCode); 563 actualCreditUnapplied.setFinancialObjectTypeCode(unappliedObjectTypeCode); 564 actualCreditUnapplied.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 565 actualCreditUnapplied.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 566 actualCreditUnapplied.setTransactionLedgerEntryAmount(holding.getFinancialDocumentLineAmount()); 567 if (StringUtils.isBlank(unappliedSubAccountNumber)) { 568 actualCreditUnapplied.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 569 } 570 else { 571 actualCreditUnapplied.setSubAccountNumber(unappliedSubAccountNumber); 572 } 573 if (StringUtils.isBlank(unappliedSubObjectCode)) { 574 actualCreditUnapplied.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 575 } 576 else { 577 actualCreditUnapplied.setFinancialSubObjectCode(unappliedSubObjectCode); 578 } 579 actualCreditUnapplied.setProjectCode(KFSConstants.getDashProjectCode()); 580 actualCreditUnapplied.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 581 actualCreditUnapplied.setTransactionLedgerEntryDescription(getDocumentHeader().getDocumentDescription()); 582 generatedEntries.add(actualCreditUnapplied); 583 sequenceHelper.increment(); 584 585 GeneralLedgerPendingEntry offsetDebitUnapplied = new GeneralLedgerPendingEntry(); 586 offsetDebitUnapplied.setUniversityFiscalYear(actualCreditUnapplied.getUniversityFiscalYear()); 587 offsetDebitUnapplied.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 588 offsetDebitUnapplied.setChartOfAccountsCode(actualCreditUnapplied.getChartOfAccountsCode()); 589 offsetDebitUnapplied.setAccountNumber(actualCreditUnapplied.getAccountNumber()); 590 OffsetDefinition offsetDebitDefinition = 591 offsetDefinitionService.getByPrimaryId( 592 getPostingYear(), universityClearingAccount.getChartOfAccountsCode(), 593 KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION, ArConstants.ACTUALS_BALANCE_TYPE_CODE); 594 offsetDebitDefinition.refreshReferenceObject("financialObject"); 595 offsetDebitUnapplied.setFinancialObjectCode(offsetDebitDefinition.getFinancialObjectCode()); 596 offsetDebitUnapplied.setFinancialObjectTypeCode(offsetDebitDefinition.getFinancialObject().getFinancialObjectTypeCode()); 597 offsetDebitUnapplied.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 598 offsetDebitUnapplied.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 599 offsetDebitUnapplied.setTransactionLedgerEntryAmount(actualCreditUnapplied.getTransactionLedgerEntryAmount()); 600 offsetDebitUnapplied.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 601 offsetDebitUnapplied.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 602 offsetDebitUnapplied.setProjectCode(KFSConstants.getDashProjectCode()); 603 offsetDebitUnapplied.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 604 offsetDebitUnapplied.setTransactionLedgerEntryDescription(getDocumentHeader().getDocumentDescription()); 605 generatedEntries.add(offsetDebitUnapplied); 606 sequenceHelper.increment(); 607 608 GeneralLedgerPendingEntry actualDebitUnapplied = new GeneralLedgerPendingEntry(); 609 actualDebitUnapplied.setUniversityFiscalYear(getPostingYear()); 610 actualDebitUnapplied.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 611 actualDebitUnapplied.setChartOfAccountsCode(universityClearingAccount.getChartOfAccountsCode()); 612 actualDebitUnapplied.setAccountNumber(universityClearingAccount.getAccountNumber()); 613 actualDebitUnapplied.setFinancialObjectCode(unappliedObjectCode); 614 actualDebitUnapplied.setFinancialObjectTypeCode(unappliedObjectTypeCode); 615 actualDebitUnapplied.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 616 actualDebitUnapplied.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 617 actualDebitUnapplied.setTransactionLedgerEntryAmount(holding.getFinancialDocumentLineAmount()); 618 if (StringUtils.isBlank(unappliedSubAccountNumber)) { 619 actualDebitUnapplied.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 620 } 621 else { 622 actualDebitUnapplied.setSubAccountNumber(unappliedSubAccountNumber); 623 } 624 actualDebitUnapplied.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 625 actualDebitUnapplied.setProjectCode(KFSConstants.getDashProjectCode()); 626 actualDebitUnapplied.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 627 actualDebitUnapplied.setTransactionLedgerEntryDescription(getDocumentHeader().getDocumentDescription()); 628 generatedEntries.add(actualDebitUnapplied); 629 sequenceHelper.increment(); 630 631 // Offsets for unapplied entries are just offsets to themselves, same info. 632 // So set the values into the offsets based on the values in the actuals. 633 GeneralLedgerPendingEntry offsetCreditUnapplied = new GeneralLedgerPendingEntry(); 634 offsetCreditUnapplied.setUniversityFiscalYear(actualDebitUnapplied.getUniversityFiscalYear()); 635 offsetCreditUnapplied.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 636 offsetCreditUnapplied.setChartOfAccountsCode(actualDebitUnapplied.getChartOfAccountsCode()); 637 offsetCreditUnapplied.setAccountNumber(actualDebitUnapplied.getAccountNumber()); 638 OffsetDefinition offsetCreditDefinition = 639 offsetDefinitionService.getByPrimaryId( 640 getPostingYear(), universityClearingAccount.getChartOfAccountsCode(), 641 KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION, ArConstants.ACTUALS_BALANCE_TYPE_CODE); 642 offsetCreditDefinition.refreshReferenceObject("financialObject"); 643 offsetCreditUnapplied.setFinancialObjectCode(offsetCreditDefinition.getFinancialObjectCode()); 644 offsetCreditUnapplied.setFinancialObjectTypeCode(offsetCreditDefinition.getFinancialObject().getFinancialObjectTypeCode()); 645 offsetCreditUnapplied.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 646 offsetCreditUnapplied.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 647 offsetCreditUnapplied.setTransactionLedgerEntryAmount(actualDebitUnapplied.getTransactionLedgerEntryAmount()); 648 offsetCreditUnapplied.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 649 offsetCreditUnapplied.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 650 offsetCreditUnapplied.setProjectCode(KFSConstants.getDashProjectCode()); 651 offsetCreditUnapplied.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 652 offsetCreditUnapplied.setTransactionLedgerEntryDescription(getDocumentHeader().getDocumentDescription()); 653 generatedEntries.add(offsetCreditUnapplied); 654 sequenceHelper.increment(); 655 } 656 657 // Generate glpes for non-ar 658 for(NonInvoiced nonInvoiced : getNonInvoiceds()) { 659 // Actual entries 660 GeneralLedgerPendingEntry actualCreditEntry = new GeneralLedgerPendingEntry(); 661 actualCreditEntry.setUniversityFiscalYear(getPostingYear()); 662 actualCreditEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 663 actualCreditEntry.setChartOfAccountsCode(nonInvoiced.getChartOfAccountsCode()); 664 actualCreditEntry.setAccountNumber(nonInvoiced.getAccountNumber()); 665 actualCreditEntry.setFinancialObjectCode(nonInvoiced.getFinancialObjectCode()); 666 nonInvoiced.refreshReferenceObject("financialObject"); 667 actualCreditEntry.setFinancialObjectTypeCode(nonInvoiced.getFinancialObject().getFinancialObjectTypeCode()); 668 actualCreditEntry.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 669 actualCreditEntry.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 670 actualCreditEntry.setTransactionLedgerEntryAmount(nonInvoiced.getFinancialDocumentLineAmount()); 671 if (StringUtils.isBlank(nonInvoiced.getSubAccountNumber())) { 672 actualCreditEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 673 } 674 else { 675 actualCreditEntry.setSubAccountNumber(nonInvoiced.getSubAccountNumber()); 676 } 677 if (StringUtils.isBlank(nonInvoiced.getFinancialSubObjectCode())) { 678 actualCreditEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 679 } 680 else { 681 actualCreditEntry.setFinancialSubObjectCode(nonInvoiced.getFinancialSubObjectCode()); 682 } 683 if (StringUtils.isBlank(nonInvoiced.getProjectCode())) { 684 actualCreditEntry.setProjectCode(KFSConstants.getDashProjectCode()); 685 } 686 else { 687 actualCreditEntry.setProjectCode(nonInvoiced.getProjectCode()); 688 } 689 actualCreditEntry.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 690 actualCreditEntry.setTransactionLedgerEntryDescription(getDocumentHeader().getDocumentDescription()); 691 generatedEntries.add(actualCreditEntry); 692 sequenceHelper.increment(); 693 694 GeneralLedgerPendingEntry actualDebitEntry = new GeneralLedgerPendingEntry(); 695 actualDebitEntry.setUniversityFiscalYear(getPostingYear()); 696 actualDebitEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 697 actualDebitEntry.setChartOfAccountsCode(universityClearingAccount.getChartOfAccountsCode()); 698 actualDebitEntry.setAccountNumber(universityClearingAccount.getAccountNumber()); 699 700 if (hasCashControlDocument()) { 701 actualDebitEntry.setFinancialObjectCode(universityClearingAccountObjectCode); 702 actualDebitEntry.setFinancialObjectTypeCode(nonInvoiced.getFinancialObject().getFinancialObjectTypeCode()); 703 actualDebitEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 704 } 705 else { 706 actualDebitEntry.setFinancialObjectCode(unappliedObjectCode); 707 actualDebitEntry.setFinancialObjectTypeCode(unappliedObjectTypeCode); 708 if (StringUtils.isBlank(unappliedSubObjectCode)) { 709 actualDebitEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 710 } 711 else { 712 actualDebitEntry.setFinancialSubObjectCode(unappliedSubObjectCode); 713 } 714 } 715 actualDebitEntry.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 716 actualDebitEntry.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 717 actualDebitEntry.setTransactionLedgerEntryAmount(nonInvoiced.getFinancialDocumentLineAmount()); 718 if (StringUtils.isBlank(unappliedSubAccountNumber)) { 719 actualDebitEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 720 } 721 else { 722 actualDebitEntry.setSubAccountNumber(unappliedSubAccountNumber); 723 } 724 actualDebitEntry.setProjectCode(KFSConstants.getDashProjectCode()); 725 actualDebitEntry.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 726 actualDebitEntry.setTransactionLedgerEntryDescription(getDocumentHeader().getDocumentDescription()); 727 generatedEntries.add(actualDebitEntry); 728 sequenceHelper.increment(); 729 730 // Offset entries 731 GeneralLedgerPendingEntry offsetDebitEntry = new GeneralLedgerPendingEntry(); 732 offsetDebitEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 733 offsetDebitEntry.setChartOfAccountsCode(nonInvoiced.getChartOfAccountsCode()); 734 offsetDebitEntry.setAccountNumber(nonInvoiced.getAccountNumber()); 735 offsetDebitEntry.setUniversityFiscalYear(getPostingYear()); 736 OffsetDefinition debitOffsetDefinition = 737 offsetDefinitionService.getByPrimaryId( 738 getPostingYear(), nonInvoiced.getChartOfAccountsCode(), 739 KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION, ArConstants.ACTUALS_BALANCE_TYPE_CODE); 740 debitOffsetDefinition.refreshReferenceObject("financialObject"); 741 offsetDebitEntry.setFinancialObjectCode(debitOffsetDefinition.getFinancialObjectCode()); 742 offsetDebitEntry.setFinancialObjectTypeCode(debitOffsetDefinition.getFinancialObject().getFinancialObjectTypeCode()); 743 offsetDebitEntry.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 744 offsetDebitEntry.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 745 offsetDebitEntry.setTransactionLedgerEntryAmount(nonInvoiced.getFinancialDocumentLineAmount()); 746 offsetDebitEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 747 offsetDebitEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 748 offsetDebitEntry.setProjectCode(KFSConstants.getDashProjectCode()); 749 offsetDebitEntry.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 750 offsetDebitEntry.setTransactionLedgerEntryDescription(getDocumentHeader().getDocumentDescription()); 751 generatedEntries.add(offsetDebitEntry); 752 sequenceHelper.increment(); 753 754 GeneralLedgerPendingEntry offsetCreditEntry = new GeneralLedgerPendingEntry(); 755 offsetCreditEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 756 offsetCreditEntry.setUniversityFiscalYear(getPostingYear()); 757 offsetCreditEntry.setChartOfAccountsCode(universityClearingAccount.getChartOfAccountsCode()); 758 offsetCreditEntry.setAccountNumber(universityClearingAccount.getAccountNumber()); 759 Integer fiscalYearForCreditOffsetDefinition = null == cashControlDocument ? currentFiscalYear : cashControlDocument.getUniversityFiscalYear(); 760 OffsetDefinition creditOffsetDefinition = 761 offsetDefinitionService.getByPrimaryId( 762 fiscalYearForCreditOffsetDefinition, processingChartCode, 763 KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION, ArConstants.ACTUALS_BALANCE_TYPE_CODE); 764 creditOffsetDefinition.refreshReferenceObject("financialObject"); 765 offsetCreditEntry.setFinancialObjectCode(creditOffsetDefinition.getFinancialObjectCode()); 766 offsetCreditEntry.setFinancialObjectTypeCode(creditOffsetDefinition.getFinancialObject().getFinancialObjectTypeCode()); 767 offsetCreditEntry.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 768 offsetCreditEntry.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 769 offsetCreditEntry.setTransactionLedgerEntryAmount(nonInvoiced.getFinancialDocumentLineAmount()); 770 offsetCreditEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 771 offsetCreditEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 772 offsetCreditEntry.setProjectCode(KFSConstants.getDashProjectCode()); 773 offsetCreditEntry.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 774 offsetCreditEntry.setTransactionLedgerEntryDescription(getDocumentHeader().getDocumentDescription()); 775 generatedEntries.add(offsetCreditEntry); 776 sequenceHelper.increment(); 777 } 778 779 // Generate GLPEs for applied payments 780 List<InvoicePaidApplied> appliedPayments = getInvoicePaidApplieds(); 781 for(InvoicePaidApplied ipa : appliedPayments) { 782 783 // Skip payments for 0 dollar amount 784 if(KualiDecimal.ZERO.equals(ipa.getInvoiceItemAppliedAmount())) { 785 continue; 786 } 787 788 ipa.refreshNonUpdateableReferences(); 789 Account billingOrganizationAccount = ipa.getInvoiceDetail().getAccount(); 790 ObjectCode invoiceObjectCode = getInvoiceReceivableObjectCode(ipa); 791 ObjectUtils.isNull(invoiceObjectCode); // Refresh 792 ObjectCode accountsReceivableObjectCode = ipa.getAccountsReceivableObjectCode(); 793 ObjectCode unappliedCashObjectCode = ipa.getSystemInformation().getUniversityClearingObject(); 794 795 GeneralLedgerPendingEntry actualDebitEntry = new GeneralLedgerPendingEntry(); 796 actualDebitEntry.setUniversityFiscalYear(getPostingYear()); 797 actualDebitEntry.setChartOfAccountsCode(universityClearingAccount.getChartOfAccountsCode()); 798 actualDebitEntry.setAccountNumber(universityClearingAccount.getAccountNumber()); 799 actualDebitEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 800 actualDebitEntry.setTransactionLedgerEntryAmount(ipa.getInvoiceItemAppliedAmount()); 801 if (hasCashControlDocument()) { 802 actualDebitEntry.setFinancialObjectCode(unappliedCashObjectCode.getFinancialObjectCode()); 803 actualDebitEntry.setFinancialObjectTypeCode(unappliedCashObjectCode.getFinancialObjectTypeCode()); 804 actualDebitEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 805 } 806 else { 807 actualDebitEntry.setFinancialObjectCode(unappliedObjectCode); 808 actualDebitEntry.setFinancialObjectTypeCode(unappliedObjectTypeCode); 809 if (StringUtils.isBlank(unappliedSubObjectCode)) { 810 actualDebitEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 811 } 812 else { 813 actualDebitEntry.setFinancialSubObjectCode(unappliedSubObjectCode); 814 } 815 } 816 if (StringUtils.isBlank(unappliedSubAccountNumber)) { 817 actualDebitEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 818 } 819 else { 820 actualDebitEntry.setSubAccountNumber(unappliedSubAccountNumber); 821 } 822 actualDebitEntry.setProjectCode(KFSConstants.getDashProjectCode()); 823 actualDebitEntry.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 824 actualDebitEntry.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 825 actualDebitEntry.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 826 actualDebitEntry.setTransactionLedgerEntryDescription(getDocumentHeader().getDocumentDescription()); 827 generatedEntries.add(actualDebitEntry); 828 sequenceHelper.increment(); 829 830 GeneralLedgerPendingEntry actualCreditEntry = new GeneralLedgerPendingEntry(); 831 actualCreditEntry.setUniversityFiscalYear(getPostingYear()); 832 actualCreditEntry.setChartOfAccountsCode(universityClearingAccount.getChartOfAccountsCode()); 833 actualCreditEntry.setAccountNumber(universityClearingAccount.getAccountNumber()); 834 actualCreditEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 835 actualCreditEntry.setTransactionLedgerEntryAmount(ipa.getInvoiceItemAppliedAmount()); 836 actualCreditEntry.setFinancialObjectCode(invoiceObjectCode.getFinancialObjectCode()); 837 actualCreditEntry.setFinancialObjectTypeCode(invoiceObjectCode.getFinancialObjectTypeCode()); 838 actualCreditEntry.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 839 actualCreditEntry.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 840 actualCreditEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 841 actualCreditEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 842 actualCreditEntry.setProjectCode(KFSConstants.getDashProjectCode()); 843 glpeService.populateOffsetGeneralLedgerPendingEntry(getPostingYear(), actualDebitEntry, sequenceHelper, actualCreditEntry); 844 actualCreditEntry.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 845 generatedEntries.add(actualCreditEntry); 846 sequenceHelper.increment(); 847 848 GeneralLedgerPendingEntry offsetDebitEntry = new GeneralLedgerPendingEntry(); 849 offsetDebitEntry.setUniversityFiscalYear(getPostingYear()); 850 offsetDebitEntry.setAccountNumber(billingOrganizationAccount.getAccountNumber()); 851 offsetDebitEntry.setChartOfAccountsCode(billingOrganizationAccount.getChartOfAccountsCode()); 852 offsetDebitEntry.setTransactionDebitCreditCode(KFSConstants.GL_CREDIT_CODE); 853 offsetDebitEntry.setTransactionLedgerEntryAmount(ipa.getInvoiceItemAppliedAmount()); 854 offsetDebitEntry.setFinancialObjectCode(invoiceObjectCode.getFinancialObjectCode()); 855 offsetDebitEntry.setFinancialObjectTypeCode(invoiceObjectCode.getFinancialObjectTypeCode()); 856 offsetDebitEntry.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 857 offsetDebitEntry.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 858 if (StringUtils.isBlank(ipa.getInvoiceDetail().getSubAccountNumber())) { 859 offsetDebitEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 860 } 861 else { 862 offsetDebitEntry.setSubAccountNumber(ipa.getInvoiceDetail().getSubAccountNumber()); 863 } 864 if (StringUtils.isBlank(ipa.getInvoiceDetail().getFinancialSubObjectCode())) { 865 offsetDebitEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 866 } 867 else { 868 offsetDebitEntry.setFinancialSubObjectCode(ipa.getInvoiceDetail().getFinancialSubObjectCode()); 869 } 870 if (StringUtils.isBlank(ipa.getInvoiceDetail().getProjectCode())) { 871 offsetDebitEntry.setProjectCode(KFSConstants.getDashProjectCode()); 872 } 873 else { 874 offsetDebitEntry.setProjectCode(ipa.getInvoiceDetail().getProjectCode()); 875 } 876 offsetDebitEntry.setTransactionLedgerEntrySequenceNumber(sequenceHelper.getSequenceCounter()); 877 offsetDebitEntry.setTransactionLedgerEntryDescription(getDocumentHeader().getDocumentDescription()); 878 generatedEntries.add(offsetDebitEntry); 879 sequenceHelper.increment(); 880 881 GeneralLedgerPendingEntry offsetCreditEntry = new GeneralLedgerPendingEntry(); 882 offsetCreditEntry.setUniversityFiscalYear(getPostingYear()); 883 offsetCreditEntry.setAccountNumber(billingOrganizationAccount.getAccountNumber()); 884 offsetCreditEntry.setChartOfAccountsCode(billingOrganizationAccount.getChartOfAccountsCode()); 885 offsetCreditEntry.setTransactionDebitCreditCode(KFSConstants.GL_DEBIT_CODE); 886 offsetCreditEntry.setTransactionLedgerEntryAmount(ipa.getInvoiceItemAppliedAmount()); 887 offsetCreditEntry.setFinancialObjectCode(accountsReceivableObjectCode.getFinancialObjectCode()); 888 offsetCreditEntry.setFinancialObjectTypeCode(accountsReceivableObjectCode.getFinancialObjectTypeCode()); 889 offsetCreditEntry.setFinancialBalanceTypeCode(ArConstants.ACTUALS_BALANCE_TYPE_CODE); 890 offsetCreditEntry.setFinancialDocumentTypeCode(KFSConstants.FinancialDocumentTypeCodes.PAYMENT_APPLICATION); 891 offsetCreditEntry.setSubAccountNumber(KFSConstants.getDashSubAccountNumber()); 892 offsetCreditEntry.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode()); 893 offsetCreditEntry.setProjectCode(KFSConstants.getDashProjectCode()); 894 offsetCreditEntry.refreshNonUpdateableReferences(); 895 glpeService.populateOffsetGeneralLedgerPendingEntry(getPostingYear(), offsetDebitEntry, sequenceHelper, offsetCreditEntry); 896 generatedEntries.add(offsetCreditEntry); 897 sequenceHelper.increment(); 898 } 899 900 // Set the origination code for all entries. 901 for(GeneralLedgerPendingEntry entry : generatedEntries) { 902 entry.setFinancialSystemOriginationCode("01"); 903 } 904 905 return generatedEntries; 906 } 907 908 /** 909 * @see org.kuali.kfs.sys.document.GeneralLedgerPendingEntrySource#generateDocumentGeneralLedgerPendingEntries(org.kuali.kfs.sys.businessobject.GeneralLedgerPendingEntrySequenceHelper) 910 */ 911 public boolean generateDocumentGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySequenceHelper sequenceHelper) { 912 try { 913 List<GeneralLedgerPendingEntry> entries = createPendingEntries(sequenceHelper); 914 for(GeneralLedgerPendingEntry entry : entries) { 915 addPendingEntry(entry); 916 } 917 } catch(Throwable t) { 918 LOG.error("Exception encountered while generating pending entries.",t); 919 return false; 920 } 921 922 return true; 923 } 924 925 public boolean generateGeneralLedgerPendingEntries(GeneralLedgerPendingEntrySourceDetail glpeSourceDetail, GeneralLedgerPendingEntrySequenceHelper sequenceHelper) { 926 return true; 927 } 928 929 public KualiDecimal getGeneralLedgerPendingEntryAmountForDetail(GeneralLedgerPendingEntrySourceDetail glpeSourceDetail) { 930 return null; 931 } 932 933 public List<GeneralLedgerPendingEntrySourceDetail> getGeneralLedgerPendingEntrySourceDetails() { 934 return new ArrayList<GeneralLedgerPendingEntrySourceDetail>(); 935 } 936 937 public boolean isDebit(GeneralLedgerPendingEntrySourceDetail postable) { 938 return false; 939 } 940 941 /** 942 * 943 * This method is used ONLY for handleRouteStatus change and other 944 * postProcessor related tasks (like getWorkflowEngineDocumentIdsToLock()) 945 * and should not otherwise be used. The reason this is its own method 946 * is to make sure that handleRouteStatusChange and 947 * getWorkflowEngineDocumentIdsToLock use the same method to retrieve 948 * what invoices to update. 949 * @return 950 */ 951 protected List<String> getInvoiceNumbersToUpdateOnFinal() { 952 List<String> docIds = new ArrayList<String>(); 953 for(InvoicePaidApplied ipa : getInvoicePaidApplieds()) { 954 docIds.add(ipa.getFinancialDocumentReferenceInvoiceNumber()); 955 } 956 return docIds; 957 } 958 959 @Override 960 public List<Long> getWorkflowEngineDocumentIdsToLock() { 961 List<String> docIdStrings = getInvoiceNumbersToUpdateOnFinal(); 962 if (docIdStrings == null || docIdStrings.isEmpty()) { 963 return null; 964 } 965 List<Long> docIds = new ArrayList<Long>(); 966 for (int i = 0; i < docIdStrings.size(); i++) { // damn I miss ruby sometimes 967 docIds.add(new Long(docIdStrings.get(i))); 968 } 969 return docIds; 970 } 971 972 @Override 973 public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) { 974 super.doRouteStatusChange(statusChangeEvent); 975 976 if(getDocumentHeader().getWorkflowDocument().stateIsFinal()) { 977 DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class); 978 979 // get the now time to stamp invoices with 980 java.sql.Date today = new java.sql.Date(dateTimeService.getCurrentDate().getTime()); 981 982 List<String> invoiceDocNumbers = getInvoiceNumbersToUpdateOnFinal(); 983 for(String invoiceDocumentNumber : invoiceDocNumbers) { 984 CustomerInvoiceDocument invoice = null; 985 986 // attempt to retrieve the invoice doc 987 try { 988 invoice = (CustomerInvoiceDocument) getDocService().getByDocumentHeaderId(invoiceDocumentNumber); 989 } catch(WorkflowException we) { 990 LOG.error("Failed to load the Invoice document due to a WorkflowException.", we); 991 } 992 if (invoice == null) { 993 throw new RuntimeException("DocumentService returned a Null CustomerInvoice Document for Doc# " + invoiceDocumentNumber + "."); 994 } 995 996 // KULAR-384 - close the invoice if its open and the openAmount is zero 997 if (invoice.getOpenAmount().isZero() && invoice.isOpenInvoiceIndicator()) { 998 invoice.setClosedDate(today); 999 invoice.setOpenInvoiceIndicator(false); 1000 getDocService().updateDocument(invoice); 1001 } 1002 } 1003 } 1004 } 1005 1006 @Override 1007 public List buildListOfDeletionAwareLists() { 1008 List deletionAwareLists = super.buildListOfDeletionAwareLists(); 1009 if (invoicePaidApplieds != null) { deletionAwareLists.add(invoicePaidApplieds); } 1010 if (nonInvoiceds != null) { deletionAwareLists.add(nonInvoiceds); } 1011 if (nonInvoicedDistributions != null) { deletionAwareLists.add(nonInvoicedDistributions); } 1012 if (nonAppliedDistributions != null) { deletionAwareLists.add(nonAppliedDistributions); } 1013 return deletionAwareLists; 1014 } 1015 1016 @Override 1017 public void prepareForSave(KualiDocumentEvent event) { 1018 super.prepareForSave(event); 1019 1020 // set primary key for NonAppliedHolding if data entered 1021 if (ObjectUtils.isNotNull(this.nonAppliedHolding)) { 1022 if (ObjectUtils.isNull(this.nonAppliedHolding.getReferenceFinancialDocumentNumber())) { 1023 this.nonAppliedHolding.setReferenceFinancialDocumentNumber(this.documentNumber); 1024 } 1025 } 1026 1027 // generate GLPEs only when routing or blanket approving 1028 if (event instanceof RouteDocumentEvent || event instanceof BlanketApproveDocumentEvent) { 1029 // if this document is not generated thru CashControl, 1030 // create nonApplied and nonInvoiced Distributions 1031 if (!this.hasCashControlDetail()) { 1032 createDistributions(); 1033 } 1034 1035 GeneralLedgerPendingEntryService glpeService = SpringContext.getBean(GeneralLedgerPendingEntryService.class); 1036 if (!glpeService.generateGeneralLedgerPendingEntries(this)) { 1037 logErrors(); 1038 throw new ValidationException("general ledger GLPE generation failed"); 1039 } 1040 } 1041 1042 } 1043 1044 public PaymentApplicationDocumentService getPaymentApplicationDocumentService() { 1045 if(null == paymentApplicationDocumentService) { 1046 paymentApplicationDocumentService = SpringContext.getBean(PaymentApplicationDocumentService.class); 1047 } 1048 return paymentApplicationDocumentService; 1049 } 1050 1051 protected FinancialSystemUserService getFsUserService() { 1052 if (fsUserService == null) { 1053 fsUserService = SpringContext.getBean(FinancialSystemUserService.class); 1054 } 1055 return fsUserService; 1056 } 1057 1058 protected CustomerInvoiceDocumentService getInvoiceDocService() { 1059 if (invoiceDocService == null) { 1060 invoiceDocService = SpringContext.getBean(CustomerInvoiceDocumentService.class); 1061 } 1062 return invoiceDocService; 1063 } 1064 1065 protected DocumentService getDocService() { 1066 if (docService == null) { 1067 docService = SpringContext.getBean(DocumentService.class); 1068 } 1069 return docService; 1070 } 1071 1072 protected NonAppliedHoldingService getNonAppliedHoldingService() { 1073 if (nonAppliedHoldingService == null) { 1074 nonAppliedHoldingService = SpringContext.getBean(NonAppliedHoldingService.class); 1075 } 1076 return nonAppliedHoldingService; 1077 } 1078 1079 protected BusinessObjectService getBoService() { 1080 if (boService == null) { 1081 boService = SpringContext.getBean(BusinessObjectService.class); 1082 } 1083 return boService; 1084 } 1085 1086 public String getHiddenFieldForErrors() { 1087 return hiddenFieldForErrors; 1088 } 1089 1090 public void setHiddenFieldForErrors(String hiddenFieldForErrors) { 1091 this.hiddenFieldForErrors = hiddenFieldForErrors; 1092 } 1093 1094 /** 1095 * 1096 * Retrieves the NonApplied Holdings that are the Controls for this 1097 * PaymentApplication. 1098 * 1099 * Note that this is dangerous to use and should not be relied upon. 1100 * The data is never persisted to the database, so will always be 1101 * null/empty when retrieved fresh. It is only populated while the 1102 * document is live from the website, or while its in flight in workflow, due 1103 * to the fact that it has been serialized. 1104 * 1105 * You should probably not be using this method unless you are sure you know 1106 * what you are doing. 1107 * 1108 * @return 1109 */ 1110 public Collection<NonAppliedHolding> getNonAppliedHoldingsForCustomer() { 1111 return nonAppliedHoldingsForCustomer; 1112 } 1113 1114 /** 1115 * 1116 * Warning, this property is not ever persisted to the database, and is only 1117 * used during workflow processing (since its been serialized) and during 1118 * presentation of the document on the webapp. 1119 * 1120 * You should probably not be using this method unless you are sure you know 1121 * what you are doing. 1122 * 1123 * @param nonApplieds 1124 */ 1125 public void setNonAppliedHoldingsForCustomer(ArrayList<NonAppliedHolding> nonApplieds) { 1126 this.nonAppliedHoldingsForCustomer = nonApplieds; 1127 } 1128 1129 /** 1130 * 1131 * Collects and returns the combined distributions from NonInvoiced/NonAr and Unapplied. 1132 * 1133 * This method is intended to be used only when the document has gone to final, to show what 1134 * control documents were issued what funds. 1135 * 1136 * The return value is a Map<String,KualiDecimal> where the key is the NonAppliedHolding's 1137 * ReferenceFinancialDocumentNumber and the value is the Amount to be applied. 1138 * 1139 * @return 1140 */ 1141 public Map<String,KualiDecimal> getDistributionsFromControlDocuments() { 1142 if (!isFinal()) { 1143 throw new UnsupportedOperationException("This method should only be used once the document has been approved/gone to final."); 1144 } 1145 1146 Map<String,KualiDecimal> distributions = new HashMap<String,KualiDecimal>(); 1147 1148 // short circuit if no non-applied-distributions available 1149 if ((nonAppliedDistributions == null || nonAppliedDistributions.isEmpty()) && 1150 (nonInvoicedDistributions == null || nonInvoicedDistributions.isEmpty())) { 1151 return distributions; 1152 } 1153 1154 // get the list of payapp docnumbers from non-applied-distributions 1155 for (NonAppliedDistribution nonAppliedDistribution : nonAppliedDistributions) { 1156 String refDocNbr = nonAppliedDistribution.getReferenceFinancialDocumentNumber(); 1157 if (distributions.containsKey(refDocNbr)) { 1158 distributions.put(refDocNbr, (distributions.get(refDocNbr).add(nonAppliedDistribution.getFinancialDocumentLineAmount()))); 1159 } 1160 else { 1161 distributions.put(refDocNbr, nonAppliedDistribution.getFinancialDocumentLineAmount()); 1162 } 1163 } 1164 1165 // get the list of payapp docnumbers from non-applied-distributions 1166 for (NonInvoicedDistribution nonInvoicedDistribution : nonInvoicedDistributions) { 1167 String refDocNbr = nonInvoicedDistribution.getReferenceFinancialDocumentNumber(); 1168 if (distributions.containsKey(refDocNbr)) { 1169 distributions.put(refDocNbr, (distributions.get(refDocNbr).add(nonInvoicedDistribution.getFinancialDocumentLineAmount()))); 1170 } 1171 else { 1172 distributions.put(refDocNbr, nonInvoicedDistribution.getFinancialDocumentLineAmount()); 1173 } 1174 } 1175 1176 return distributions; 1177 } 1178 1179 /** 1180 * 1181 * Walks through the nonAppliedHoldings passed in (the control docs) and allocates how the 1182 * funding should be allocated. 1183 * 1184 * This function is intended to be used when the document is still live, ie not for when its 1185 * been finalized. 1186 * 1187 * The return value is a Map<String,KualiDecimal> where the key is the NonAppliedHolding's 1188 * ReferenceFinancialDocumentNumber and the value is the Amount to be applied. 1189 * 1190 */ 1191 public Map<String,KualiDecimal> allocateFundsFromUnappliedControls(List<NonAppliedHolding> nonAppliedHoldings, KualiDecimal amountToBeApplied) { 1192 if (nonAppliedHoldings == null) { 1193 throw new IllegalArgumentException("A null value for the parameter [nonAppliedHoldings] was passed in."); 1194 } 1195 if (amountToBeApplied == null) { 1196 throw new IllegalArgumentException("A null ovalue for the parameter [amountToBeApplied] was passed in."); 1197 } 1198 if (isFinal()) { 1199 throw new UnsupportedOperationException("This method should not be used when the document has been approved/gone to final."); 1200 } 1201 1202 // special-case the situation where the amountToBeApplied is negative, then make all allocations zero 1203 if (amountToBeApplied.isNegative()) { 1204 Map<String,KualiDecimal> allocations = new HashMap<String,KualiDecimal>(); 1205 for (NonAppliedHolding nonAppliedHolding : nonAppliedHoldings) { 1206 allocations.put(nonAppliedHolding.getReferenceFinancialDocumentNumber(), KualiDecimal.ZERO); 1207 } 1208 return allocations; 1209 } 1210 1211 Map<String,KualiDecimal> allocations = new HashMap<String,KualiDecimal>(); 1212 KualiDecimal remainingAmount = new KualiDecimal(amountToBeApplied.toString()); //clone it 1213 1214 // due to the way the control list is generated, this will result in applying 1215 // from the oldest to newest, which is the ordering desired. If this ever changes, 1216 // then the internal logic here should be to apply to the oldest doc first, and then 1217 // move forward in time until you run out of money or docs 1218 for (NonAppliedHolding nonAppliedHolding : nonAppliedHoldings) { 1219 String refDocNumber = nonAppliedHolding.getReferenceFinancialDocumentNumber(); 1220 1221 // this shouldnt ever happen, but lets sanity check it 1222 if (allocations.containsKey(nonAppliedHolding.getReferenceFinancialDocumentNumber())) { 1223 throw new RuntimeException("The same NonAppliedHolding RefDocNumber came up twice, which should never happen."); 1224 } 1225 else { 1226 allocations.put(refDocNumber, KualiDecimal.ZERO); 1227 } 1228 1229 if (remainingAmount.isGreaterThan(KualiDecimal.ZERO)) { 1230 if (nonAppliedHoldings.iterator().hasNext()) { 1231 if (remainingAmount.isLessEqual(nonAppliedHolding.getAvailableUnappliedAmount())) { 1232 allocations.put(refDocNumber, remainingAmount); 1233 remainingAmount = remainingAmount.subtract(remainingAmount); 1234 } 1235 else { 1236 allocations.put(refDocNumber, nonAppliedHolding.getAvailableUnappliedAmount()); 1237 remainingAmount = remainingAmount.subtract(nonAppliedHolding.getAvailableUnappliedAmount()); 1238 } 1239 } 1240 } 1241 } 1242 return allocations; 1243 } 1244 1245 // this method is only used by Unapplied PayApp. 1246 // create nonApplied and nonInvoiced Distributions 1247 public void createDistributions() { 1248 1249 // if there are non nonApplieds, then we have nothing to do 1250 if (nonAppliedHoldingsForCustomer == null || nonAppliedHoldingsForCustomer.isEmpty()) { 1251 return; 1252 } 1253 1254 Collection<InvoicePaidApplied> invoicePaidAppliedsForCurrentDoc = this.getInvoicePaidApplieds(); 1255 Collection<NonInvoiced> nonInvoicedsForCurrentDoc = this.getNonInvoiceds(); 1256 1257 for(NonAppliedHolding nonAppliedHoldings : this.getNonAppliedHoldingsForCustomer()) { 1258 1259 // check if payment has been applied to Invoices 1260 // create Unapplied Distribution for each PaidApplied 1261 KualiDecimal remainingUnappliedForDistribution = nonAppliedHoldings.getAvailableUnappliedAmount(); 1262 for(InvoicePaidApplied invoicePaidAppliedForCurrentDoc : invoicePaidAppliedsForCurrentDoc) { 1263 KualiDecimal paidAppliedDistributionAmount = invoicePaidAppliedForCurrentDoc.getPaidAppiedDistributionAmount(); 1264 KualiDecimal remainingPaidAppliedForDistribution = invoicePaidAppliedForCurrentDoc.getInvoiceItemAppliedAmount().subtract(paidAppliedDistributionAmount); 1265 if (remainingPaidAppliedForDistribution.equals(KualiDecimal.ZERO) || 1266 remainingUnappliedForDistribution.equals(KualiDecimal.ZERO)) { 1267 continue; 1268 } 1269 1270 // set NonAppliedDistributions for the current document 1271 NonAppliedDistribution nonAppliedDistribution = new NonAppliedDistribution(); 1272 nonAppliedDistribution.setDocumentNumber(invoicePaidAppliedForCurrentDoc.getDocumentNumber()); 1273 nonAppliedDistribution.setPaidAppliedItemNumber(invoicePaidAppliedForCurrentDoc.getPaidAppliedItemNumber()); 1274 nonAppliedDistribution.setReferenceFinancialDocumentNumber(nonAppliedHoldings.getReferenceFinancialDocumentNumber()); 1275 if (remainingPaidAppliedForDistribution.isLessEqual(remainingUnappliedForDistribution)) { 1276 nonAppliedDistribution.setFinancialDocumentLineAmount(remainingPaidAppliedForDistribution); 1277 remainingUnappliedForDistribution = remainingUnappliedForDistribution.subtract(remainingPaidAppliedForDistribution); 1278 invoicePaidAppliedForCurrentDoc.setPaidAppiedDistributionAmount(paidAppliedDistributionAmount.add(remainingPaidAppliedForDistribution)); 1279 } 1280 else { 1281 nonAppliedDistribution.setFinancialDocumentLineAmount(remainingUnappliedForDistribution); 1282 invoicePaidAppliedForCurrentDoc.setPaidAppiedDistributionAmount(paidAppliedDistributionAmount.add(remainingUnappliedForDistribution)); 1283 remainingUnappliedForDistribution = KualiDecimal.ZERO; 1284 } 1285 this.nonAppliedDistributions.add(nonAppliedDistribution); 1286 } 1287 1288 // check if payment has been applied to NonAR 1289 // create NonAR distribution for each NonAR Applied row 1290 for(NonInvoiced nonInvoicedForCurrentDoc : nonInvoicedsForCurrentDoc) { 1291 KualiDecimal nonInvoicedDistributionAmount = nonInvoicedForCurrentDoc.getNonInvoicedDistributionAmount(); 1292 KualiDecimal remainingNonInvoicedForDistribution = nonInvoicedForCurrentDoc.getFinancialDocumentLineAmount().subtract(nonInvoicedDistributionAmount); 1293 if (remainingNonInvoicedForDistribution.equals(KualiDecimal.ZERO) || 1294 remainingUnappliedForDistribution.equals(KualiDecimal.ZERO)) { 1295 continue; 1296 } 1297 1298 // set NonAppliedDistributions for the current document 1299 NonInvoicedDistribution nonInvoicedDistribution = new NonInvoicedDistribution(); 1300 nonInvoicedDistribution.setDocumentNumber(nonInvoicedForCurrentDoc.getDocumentNumber()); 1301 nonInvoicedDistribution.setFinancialDocumentLineNumber(nonInvoicedForCurrentDoc.getFinancialDocumentLineNumber()); 1302 nonInvoicedDistribution.setReferenceFinancialDocumentNumber(nonAppliedHoldings.getReferenceFinancialDocumentNumber()); 1303 if (remainingNonInvoicedForDistribution.isLessEqual(remainingUnappliedForDistribution)) { 1304 nonInvoicedDistribution.setFinancialDocumentLineAmount(remainingNonInvoicedForDistribution); 1305 remainingUnappliedForDistribution = remainingUnappliedForDistribution.subtract(remainingNonInvoicedForDistribution); 1306 nonInvoicedForCurrentDoc.setNonInvoicedDistributionAmount(nonInvoicedDistributionAmount.add(remainingNonInvoicedForDistribution)); 1307 } 1308 else { 1309 nonInvoicedDistribution.setFinancialDocumentLineAmount(remainingUnappliedForDistribution); 1310 nonInvoicedForCurrentDoc.setNonInvoicedDistributionAmount(nonInvoicedDistributionAmount.add(remainingUnappliedForDistribution)); 1311 remainingUnappliedForDistribution = KualiDecimal.ZERO; 1312 } 1313 this.nonInvoicedDistributions.add(nonInvoicedDistribution); 1314 } 1315 } 1316 } 1317 1318 /** 1319 * 1320 * @see org.kuali.kfs.sys.document.FinancialSystemTransactionalDocumentBase#answerSplitNodeQuestion(java.lang.String) 1321 */ 1322 @Override 1323 public boolean answerSplitNodeQuestion(String nodeName) throws UnsupportedOperationException { 1324 if (LAUNCHED_FROM_BATCH.equals(nodeName)) { 1325 return launchedFromBatch(); 1326 } 1327 throw new UnsupportedOperationException("answerSplitNode('" + nodeName + "') was called but no handler for nodeName specified."); 1328 } 1329 1330 // determines if the doc was launched by SYSTEM_USER, if so, then it was launched from batch 1331 protected boolean launchedFromBatch() { 1332 boolean result = false; 1333 Person initiator = SpringContext.getBean(PersonService.class).getPersonByPrincipalName(KFSConstants.SYSTEM_USER); 1334 result = initiator.getPrincipalId().equalsIgnoreCase(getDocumentHeader().getWorkflowDocument().getInitiatorPrincipalId()); 1335 return result; 1336 } 1337 1338 /** CUSTOM SEARCH HELPER METHODS **/ 1339 1340 /** 1341 * 1342 * This method is defined to assist in the custom search implementation. 1343 * @return 1344 */ 1345 public String getUnappliedCustomerNumber() { 1346 if(nonAppliedHolding==null) { 1347 return ""; 1348 } 1349 return nonAppliedHolding.getCustomerNumber(); 1350 } 1351 1352 /** 1353 * 1354 * This method is defined to assist in the custom search implementation. 1355 * @return 1356 */ 1357 public String getUnappliedCustomerName() { 1358 if(nonAppliedHolding==null) { 1359 return ""; 1360 } 1361 return nonAppliedHolding.getCustomer().getCustomerName(); 1362 } 1363 1364 /** 1365 * 1366 * This method is defined to assist in the custom search implementation. 1367 * @return 1368 */ 1369 public String getInvoiceAppliedCustomerNumber() { 1370 return getAccountsReceivableDocumentHeader().getCustomerNumber(); 1371 } 1372 1373 /** 1374 * 1375 * This method is defined to assist in the custom search implementation. 1376 * @return 1377 */ 1378 public String getInvoiceAppliedCustomerName() { 1379 return getAccountsReceivableDocumentHeader().getCustomer().getCustomerName(); 1380 } 1381 1382 } 1383