001/* 002 * Copyright 2008 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 */ 016package org.kuali.ole.pdp.service.impl; 017 018import java.sql.Timestamp; 019import java.text.MessageFormat; 020import java.text.ParseException; 021import java.util.ArrayList; 022import java.util.Calendar; 023import java.util.List; 024 025import org.apache.commons.lang.StringUtils; 026import org.kuali.ole.coa.businessobject.Account; 027import org.kuali.ole.coa.businessobject.ObjectCode; 028import org.kuali.ole.coa.businessobject.ProjectCode; 029import org.kuali.ole.coa.businessobject.SubAccount; 030import org.kuali.ole.coa.businessobject.SubObjectCode; 031import org.kuali.ole.coa.service.AccountService; 032import org.kuali.ole.coa.service.ObjectCodeService; 033import org.kuali.ole.coa.service.SubAccountService; 034import org.kuali.ole.coa.service.SubObjectCodeService; 035import org.kuali.ole.pdp.PdpConstants; 036import org.kuali.ole.pdp.PdpKeyConstants; 037import org.kuali.ole.pdp.PdpParameterConstants; 038import org.kuali.ole.pdp.PdpPropertyConstants; 039import org.kuali.ole.pdp.businessobject.AccountingChangeCode; 040import org.kuali.ole.pdp.businessobject.CustomerProfile; 041import org.kuali.ole.pdp.businessobject.PayeeType; 042import org.kuali.ole.pdp.businessobject.PaymentAccountDetail; 043import org.kuali.ole.pdp.businessobject.PaymentAccountHistory; 044import org.kuali.ole.pdp.businessobject.PaymentDetail; 045import org.kuali.ole.pdp.businessobject.PaymentFileLoad; 046import org.kuali.ole.pdp.businessobject.PaymentGroup; 047import org.kuali.ole.pdp.businessobject.PaymentStatus; 048import org.kuali.ole.pdp.dataaccess.PaymentFileLoadDao; 049import org.kuali.ole.pdp.service.CustomerProfileService; 050import org.kuali.ole.pdp.service.PaymentFileValidationService; 051import org.kuali.ole.sys.OLEConstants; 052import org.kuali.ole.sys.businessobject.Bank; 053import org.kuali.ole.sys.businessobject.OriginationCode; 054import org.kuali.ole.sys.service.BankService; 055import org.kuali.ole.sys.service.OriginationCodeService; 056import org.kuali.ole.sys.service.impl.OleParameterConstants; 057import org.kuali.rice.core.api.config.property.ConfigurationService; 058import org.kuali.rice.core.api.datetime.DateTimeService; 059import org.kuali.rice.core.api.util.type.KualiDecimal; 060import org.kuali.rice.coreservice.framework.parameter.ParameterService; 061import org.kuali.rice.kew.api.doctype.DocumentTypeService; 062import org.kuali.rice.krad.bo.KualiCodeBase; 063import org.kuali.rice.krad.service.BusinessObjectService; 064import org.kuali.rice.krad.util.MessageMap; 065import org.springframework.transaction.annotation.Transactional; 066 067/** 068 * @see org.kuali.ole.pdp.batch.service.PaymentFileValidationService 069 */ 070@Transactional 071public class PaymentFileValidationServiceImpl implements PaymentFileValidationService { 072 protected CustomerProfileService customerProfileService; 073 protected PaymentFileLoadDao paymentFileLoadDao; 074 protected ParameterService parameterService; 075 protected ConfigurationService kualiConfigurationService; 076 protected DateTimeService dateTimeService; 077 protected AccountService accountService; 078 protected SubAccountService subAccountService; 079 protected ObjectCodeService objectCodeService; 080 protected SubObjectCodeService subObjectCodeService; 081 protected BankService bankService; 082 protected OriginationCodeService originationCodeService; 083 protected DocumentTypeService documentTypeService; 084 protected BusinessObjectService businessObjectService; 085 086 /** 087 * @see org.kuali.ole.pdp.batch.service.PaymentFileValidationService#doHardEdits(org.kuali.ole.pdp.businessobject.PaymentFile, 088 * org.kuali.rice.krad.util.MessageMap) 089 */ 090 @Override 091 public void doHardEdits(PaymentFileLoad paymentFile, MessageMap errorMap) { 092 processHeaderValidation(paymentFile, errorMap); 093 094 if (errorMap.hasNoErrors()) { 095 processGroupValidation(paymentFile, errorMap); 096 } 097 098 if (errorMap.hasNoErrors()) { 099 processTrailerValidation(paymentFile, errorMap); 100 } 101 } 102 103 /** 104 * Validates payment file header fields <li>Checks customer exists in customer profile table and is active</li> 105 * 106 * @param paymentFile payment file object 107 * @param errorMap map in which errors will be added to 108 */ 109 protected void processHeaderValidation(PaymentFileLoad paymentFile, MessageMap errorMap) { 110 CustomerProfile customer = customerProfileService.get(paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit()); 111 if (customer == null) { 112 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_INVALID_CUSTOMER, paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit()); 113 } 114 else { 115 if (!customer.isActive()) { 116 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_INACTIVE_CUSTOMER, paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit()); 117 } 118 else { 119 paymentFile.setCustomer(customer); 120 } 121 } 122 } 123 124 /** 125 * Validates payment file trailer fields <li>Reconciles actual to expected payment count and totals</li> <li>Verifies the batch 126 * is not a duplicate</li> 127 * 128 * @param paymentFile payment file object 129 * @param errorMap map in which errors will be added to 130 */ 131 protected void processTrailerValidation(PaymentFileLoad paymentFile, MessageMap errorMap) { 132 // compare trailer payment count to actual count loaded 133 if (paymentFile.getActualPaymentCount() != paymentFile.getPaymentCount()) { 134 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_PAYMENT_COUNT_MISMATCH, Integer.toString(paymentFile.getPaymentCount()), Integer.toString(paymentFile.getActualPaymentCount())); 135 } 136 137 // compare trailer total amount with actual total amount 138 if (paymentFile.getCalculatedPaymentTotalAmount().compareTo(paymentFile.getPaymentTotalAmount()) != 0) { 139 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_PAYMENT_TOTAL_MISMATCH, paymentFile.getPaymentTotalAmount().toString(), paymentFile.getCalculatedPaymentTotalAmount().toString()); 140 } 141 142 // Check to see if this is a duplicate batch 143 Timestamp now = new Timestamp(paymentFile.getCreationDate().getTime()); 144 145 if (paymentFileLoadDao.isDuplicateBatch(paymentFile.getCustomer(), paymentFile.getPaymentCount(), paymentFile.getPaymentTotalAmount().bigDecimalValue(), now)) { 146 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_DUPLICATE_BATCH); 147 } 148 } 149 150 /** 151 * Validates payment file groups <li>Checks number of note lines needed is not above the configured maximum allowed</li> <li> 152 * Verifies group total is not negative</li> <li>Verifies detail accounting total equals net payment amount</li> 153 * 154 * @param paymentFile payment file object 155 * @param errorMap map in which errors will be added to 156 */ 157 protected void processGroupValidation(PaymentFileLoad paymentFile, MessageMap errorMap) { 158 int groupCount = 0; 159 for (PaymentGroup paymentGroup : paymentFile.getPaymentGroups()) { 160 groupCount++; 161 162 int noteLineCount = 0; 163 int detailCount = 0; 164 165 // verify payee id and owner code if customer requires them to be filled in 166 if (paymentFile.getCustomer().getPayeeIdRequired() && StringUtils.isBlank(paymentGroup.getPayeeId())) { 167 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_PAYEE_ID_REQUIRED, Integer.toString(groupCount)); 168 } 169 170 if (paymentFile.getCustomer().getOwnershipCodeRequired() && StringUtils.isBlank(paymentGroup.getPayeeOwnerCd())) { 171 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_PAYEE_OWNER_CODE, Integer.toString(groupCount)); 172 } 173 174 // validate payee id type 175 if (StringUtils.isNotBlank(paymentGroup.getPayeeIdTypeCd())) { 176 PayeeType payeeType = businessObjectService.findBySinglePrimaryKey(PayeeType.class, paymentGroup.getPayeeIdTypeCd()); 177 if (payeeType == null) { 178 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_INVALID_PAYEE_ID_TYPE, Integer.toString(groupCount), paymentGroup.getPayeeIdTypeCd()); 179 } 180 } 181 182 // validate bank 183 String bankCode = paymentGroup.getBankCode(); 184 if (StringUtils.isNotBlank(bankCode)) { 185 Bank bank = bankService.getByPrimaryId(bankCode); 186 if (bank == null) { 187 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_INVALID_BANK_CODE, Integer.toString(groupCount), bankCode); 188 } 189 else if (!bank.isActive()) { 190 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_INACTIVE_BANK_CODE, Integer.toString(groupCount), bankCode); 191 } 192 } 193 194 KualiDecimal groupTotal = KualiDecimal.ZERO; 195 for (PaymentDetail paymentDetail : paymentGroup.getPaymentDetails()) { 196 detailCount++; 197 198 noteLineCount++; // Add a line to print the invoice number 199 noteLineCount = noteLineCount + paymentDetail.getNotes().size(); 200 201 if ((paymentDetail.getNetPaymentAmount() == null) && (!paymentDetail.isDetailAmountProvided())) { 202 paymentDetail.setNetPaymentAmount(paymentDetail.getAccountTotal()); 203 } 204 else if ((paymentDetail.getNetPaymentAmount() == null) && (paymentDetail.isDetailAmountProvided())) { 205 paymentDetail.setNetPaymentAmount(paymentDetail.getCalculatedPaymentAmount()); 206 } 207 208 // compare net to accounting segments 209 if (paymentDetail.getAccountTotal().compareTo(paymentDetail.getNetPaymentAmount()) != 0) { 210 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_DETAIL_TOTAL_MISMATCH, Integer.toString(groupCount), Integer.toString(detailCount), paymentDetail.getAccountTotal().toString(), paymentDetail.getNetPaymentAmount().toString()); 211 } 212 213 // validate origin code if given 214 if (StringUtils.isNotBlank(paymentDetail.getFinancialSystemOriginCode())) { 215 OriginationCode originationCode = originationCodeService.getByPrimaryKey(paymentDetail.getFinancialSystemOriginCode()); 216 if (originationCode == null) { 217 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_INVALID_ORIGIN_CODE, Integer.toString(groupCount), Integer.toString(detailCount), paymentDetail.getFinancialSystemOriginCode()); 218 } 219 } 220 221 // validate doc type if given 222 if (StringUtils.isNotBlank(paymentDetail.getFinancialDocumentTypeCode())) { 223 if ( !documentTypeService.isActiveByName(paymentDetail.getFinancialDocumentTypeCode()) ) { 224 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_INVALID_DOC_TYPE, Integer.toString(groupCount), Integer.toString(detailCount), paymentDetail.getFinancialDocumentTypeCode()); 225 } 226 } 227 228 groupTotal = groupTotal.add(paymentDetail.getNetPaymentAmount()); 229 } 230 231 // verify total for group is not negative 232 if (groupTotal.doubleValue() < 0) { 233 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_NEGATIVE_GROUP_TOTAL, Integer.toString(groupCount)); 234 } 235 236 // check that the number of detail items and note lines will fit on a check stub 237 if (noteLineCount > getMaxNoteLines()) { 238 errorMap.putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.ERROR_PAYMENT_LOAD_MAX_NOTE_LINES, Integer.toString(groupCount), Integer.toString(noteLineCount), Integer.toString(getMaxNoteLines())); 239 } 240 } 241 } 242 243 /** 244 * @see org.kuali.ole.pdp.service.PaymentFileValidationService#doSoftEdits(org.kuali.ole.pdp.businessobject.PaymentFile) 245 */ 246 @Override 247 public List<String> doSoftEdits(PaymentFileLoad paymentFile) { 248 List<String> warnings = new ArrayList<String>(); 249 250 CustomerProfile customer = customerProfileService.get(paymentFile.getChart(), paymentFile.getUnit(), paymentFile.getSubUnit()); 251 252 // check payment amount does not exceed the configured threshold amount of this customer 253 if (paymentFile.getPaymentTotalAmount().compareTo(customer.getFileThresholdAmount()) > 0) { 254 addWarningMessage(warnings, PdpKeyConstants.MESSAGE_PAYMENT_LOAD_FILE_THRESHOLD, paymentFile.getPaymentTotalAmount().toString(), customer.getFileThresholdAmount().toString()); 255 paymentFile.setFileThreshold(true); 256 } 257 258 processGroupSoftEdits(paymentFile, customer, warnings); 259 260 return warnings; 261 } 262 263 /** 264 * Set defaults for group fields and do tax checks. 265 * 266 * @param paymentFile payment file object 267 * @param customer payment customer 268 * @param warnings <code>List</code> list of accumulated warning messages 269 */ 270 public void processGroupSoftEdits(PaymentFileLoad paymentFile, CustomerProfile customer, List<String> warnings) { 271 PaymentStatus openStatus = businessObjectService.findBySinglePrimaryKey(PaymentStatus.class, PdpConstants.PaymentStatusCodes.OPEN); 272 273 for (PaymentGroup paymentGroup : paymentFile.getPaymentGroups()) { 274 paymentGroup.setBatchId(paymentFile.getBatchId()); 275 paymentGroup.setPaymentStatusCode(openStatus.getCode()); 276 paymentGroup.setPaymentStatus(openStatus); 277 paymentGroup.setPayeeName(paymentGroup.getPayeeName().toUpperCase()); 278 279 // Set defaults for missing information 280 defaultGroupIndicators(paymentGroup); 281 282 // Tax Group Requirements for automatic Holding 283 checkForTaxEmailRequired(paymentFile, paymentGroup, customer); 284 285 // do edits on detail lines 286 for (PaymentDetail paymentDetail : paymentGroup.getPaymentDetails()) { 287 paymentDetail.setPaymentGroupId(paymentGroup.getId()); 288 289 processDetailSoftEdits(paymentFile, customer, paymentDetail, warnings); 290 } 291 292 } 293 } 294 295 /** 296 * Set default fields on detail line and check amount against customer threshold. 297 * 298 * @param paymentFile payment file object 299 * @param customer payment customer 300 * @param paymentDetail <code>PaymentDetail</code> object to process 301 * @param warnings <code>List</code> list of accumulated warning messages 302 */ 303 protected void processDetailSoftEdits(PaymentFileLoad paymentFile, CustomerProfile customer, PaymentDetail paymentDetail, List<String> warnings) { 304 updateDetailAmounts(paymentDetail); 305 306 // Check net payment amount 307 KualiDecimal testAmount = paymentDetail.getNetPaymentAmount(); 308 if (testAmount.compareTo(customer.getPaymentThresholdAmount()) > 0) { 309 addWarningMessage(warnings, PdpKeyConstants.MESSAGE_PAYMENT_LOAD_DETAIL_THRESHOLD, testAmount.toString(), customer.getPaymentThresholdAmount().toString()); 310 paymentFile.setDetailThreshold(true); 311 paymentFile.getThresholdPaymentDetails().add(paymentDetail); 312 } 313 314 // set invoice date if it doesn't exist 315 if (paymentDetail.getInvoiceDate() == null) { 316 paymentDetail.setInvoiceDate(dateTimeService.getCurrentSqlDate()); 317 } 318 319 if (paymentDetail.getPrimaryCancelledPayment() == null) { 320 paymentDetail.setPrimaryCancelledPayment(Boolean.FALSE); 321 } 322 323 // do accounting edits 324 for (PaymentAccountDetail paymentAccountDetail : paymentDetail.getAccountDetail()) { 325 paymentAccountDetail.setPaymentDetailId(paymentDetail.getId()); 326 327 processAccountSoftEdits(paymentFile, customer, paymentAccountDetail, warnings); 328 } 329 } 330 331 /** 332 * Set default fields on account line and perform account field existence checks 333 * 334 * @param paymentFile payment file object 335 * @param customer payment customer 336 * @param paymentAccountDetail <code>PaymentAccountDetail</code> object to process 337 * @param warnings <code>List</code> list of accumulated warning messages 338 */ 339 protected void processAccountSoftEdits(PaymentFileLoad paymentFile, CustomerProfile customer, PaymentAccountDetail paymentAccountDetail, List<String> warnings) { 340 List<PaymentAccountHistory> changeRecords = paymentAccountDetail.getAccountHistory(); 341 342 // uppercase chart 343 paymentAccountDetail.setFinChartCode(paymentAccountDetail.getFinChartCode().toUpperCase()); 344 345 // only do accounting edits if required by customer 346 if (customer.getAccountingEditRequired()) { 347 // check account number 348 Account account = accountService.getByPrimaryId(paymentAccountDetail.getFinChartCode(), paymentAccountDetail.getAccountNbr()); 349 if (account == null) { 350 addWarningMessage(warnings, PdpKeyConstants.MESSAGE_PAYMENT_LOAD_INVALID_ACCOUNT, paymentAccountDetail.getFinChartCode(), paymentAccountDetail.getAccountNbr()); 351 352 KualiCodeBase objChangeCd = businessObjectService.findBySinglePrimaryKey(AccountingChangeCode.class, PdpConstants.AccountChangeCodes.INVALID_ACCOUNT); 353 replaceAccountingString(objChangeCd, changeRecords, customer, paymentAccountDetail); 354 } 355 else { 356 // check sub account code 357 if (StringUtils.isNotBlank(paymentAccountDetail.getSubAccountNbr())) { 358 SubAccount subAccount = subAccountService.getByPrimaryId(paymentAccountDetail.getFinChartCode(), paymentAccountDetail.getAccountNbr(), paymentAccountDetail.getSubAccountNbr()); 359 if (subAccount == null) { 360 addWarningMessage(warnings, PdpKeyConstants.MESSAGE_PAYMENT_LOAD_INVALID_SUB_ACCOUNT, paymentAccountDetail.getFinChartCode(), paymentAccountDetail.getAccountNbr(), paymentAccountDetail.getSubAccountNbr()); 361 362 KualiCodeBase objChangeCd = businessObjectService.findBySinglePrimaryKey(AccountingChangeCode.class, PdpConstants.AccountChangeCodes.INVALID_SUB_ACCOUNT); 363 changeRecords.add(newAccountHistory(PdpPropertyConstants.SUB_ACCOUNT_DB_COLUMN_NAME, OLEConstants.getDashSubAccountNumber(), paymentAccountDetail.getSubAccountNbr(), objChangeCd)); 364 365 paymentAccountDetail.setSubAccountNbr(OLEConstants.getDashSubAccountNumber()); 366 } 367 } 368 369 // check object code 370 ObjectCode objectCode = objectCodeService.getByPrimaryIdForCurrentYear(paymentAccountDetail.getFinChartCode(), paymentAccountDetail.getFinObjectCode()); 371 if (objectCode == null) { 372 addWarningMessage(warnings, PdpKeyConstants.MESSAGE_PAYMENT_LOAD_INVALID_OBJECT, paymentAccountDetail.getFinChartCode(), paymentAccountDetail.getFinObjectCode()); 373 374 KualiCodeBase objChangeCd = businessObjectService.findBySinglePrimaryKey(AccountingChangeCode.class, PdpConstants.AccountChangeCodes.INVALID_OBJECT); 375 replaceAccountingString(objChangeCd, changeRecords, customer, paymentAccountDetail); 376 } 377 378 // check sub object code 379 else if (StringUtils.isNotBlank(paymentAccountDetail.getFinSubObjectCode())) { 380 SubObjectCode subObjectCode = subObjectCodeService.getByPrimaryIdForCurrentYear(paymentAccountDetail.getFinChartCode(), paymentAccountDetail.getAccountNbr(), paymentAccountDetail.getFinObjectCode(), paymentAccountDetail.getFinSubObjectCode()); 381 if (subObjectCode == null) { 382 addWarningMessage(warnings, PdpKeyConstants.MESSAGE_PAYMENT_LOAD_INVALID_SUB_OBJECT, paymentAccountDetail.getFinChartCode(), paymentAccountDetail.getAccountNbr(), paymentAccountDetail.getFinObjectCode(), paymentAccountDetail.getFinSubObjectCode()); 383 384 KualiCodeBase objChangeCd = businessObjectService.findBySinglePrimaryKey(AccountingChangeCode.class, PdpConstants.AccountChangeCodes.INVALID_SUB_OBJECT); 385 changeRecords.add(newAccountHistory(PdpPropertyConstants.SUB_OBJECT_DB_COLUMN_NAME, OLEConstants.getDashFinancialSubObjectCode(), paymentAccountDetail.getFinSubObjectCode(), objChangeCd)); 386 387 paymentAccountDetail.setFinSubObjectCode(OLEConstants.getDashFinancialSubObjectCode()); 388 } 389 } 390 } 391 392 // check project code 393 if (StringUtils.isNotBlank(paymentAccountDetail.getProjectCode())) { 394 ProjectCode projectCode = businessObjectService.findBySinglePrimaryKey(ProjectCode.class, paymentAccountDetail.getProjectCode()); 395 if (projectCode == null) { 396 addWarningMessage(warnings, PdpKeyConstants.MESSAGE_PAYMENT_LOAD_INVALID_PROJECT, paymentAccountDetail.getProjectCode()); 397 398 KualiCodeBase objChangeCd = businessObjectService.findBySinglePrimaryKey(AccountingChangeCode.class, PdpConstants.AccountChangeCodes.INVALID_PROJECT); 399 changeRecords.add(newAccountHistory(PdpPropertyConstants.PROJECT_DB_COLUMN_NAME, OLEConstants.getDashProjectCode(), paymentAccountDetail.getProjectCode(), objChangeCd)); 400 paymentAccountDetail.setProjectCode(OLEConstants.getDashProjectCode()); 401 } 402 } 403 } 404 405 // change nulls into ---'s for the fields that need it 406 if (StringUtils.isBlank(paymentAccountDetail.getFinSubObjectCode())) { 407 paymentAccountDetail.setFinSubObjectCode(OLEConstants.getDashFinancialSubObjectCode()); 408 } 409 410 if (StringUtils.isBlank(paymentAccountDetail.getSubAccountNbr())) { 411 paymentAccountDetail.setSubAccountNbr(OLEConstants.getDashSubAccountNumber()); 412 } 413 414 if (StringUtils.isBlank(paymentAccountDetail.getProjectCode())) { 415 paymentAccountDetail.setProjectCode(OLEConstants.getDashProjectCode()); 416 } 417 418 } 419 420 /** 421 * Replaces the entire accounting string with defaults from the customer profile. 422 * 423 * @param objChangeCd code indicating reason for change 424 * @param changeRecords <code>List</code> of <code>PaymentAccountHistory</code> records 425 * @param customer profile of payment customer 426 * @param paymentAccountDetail account detail record 427 */ 428 protected void replaceAccountingString(KualiCodeBase objChangeCd, List<PaymentAccountHistory> changeRecords, CustomerProfile customer, PaymentAccountDetail paymentAccountDetail) { 429 changeRecords.add(newAccountHistory(PdpPropertyConstants.CHART_DB_COLUMN_NAME, customer.getDefaultChartCode(), paymentAccountDetail.getFinChartCode(), objChangeCd)); 430 changeRecords.add(newAccountHistory(PdpPropertyConstants.ACCOUNT_DB_COLUMN_NAME, customer.getDefaultAccountNumber(), paymentAccountDetail.getAccountNbr(), objChangeCd)); 431 changeRecords.add(newAccountHistory(PdpPropertyConstants.SUB_ACCOUNT_DB_COLUMN_NAME, customer.getDefaultSubAccountNumber(), paymentAccountDetail.getSubAccountNbr(), objChangeCd)); 432 changeRecords.add(newAccountHistory(PdpPropertyConstants.OBJECT_DB_COLUMN_NAME, customer.getDefaultObjectCode(), paymentAccountDetail.getFinObjectCode(), objChangeCd)); 433 changeRecords.add(newAccountHistory(PdpPropertyConstants.SUB_OBJECT_DB_COLUMN_NAME, customer.getDefaultSubObjectCode(), paymentAccountDetail.getFinSubObjectCode(), objChangeCd)); 434 435 paymentAccountDetail.setFinChartCode(customer.getDefaultChartCode()); 436 paymentAccountDetail.setAccountNbr(customer.getDefaultAccountNumber()); 437 if (StringUtils.isNotBlank(customer.getDefaultSubAccountNumber())) { 438 paymentAccountDetail.setSubAccountNbr(customer.getDefaultSubAccountNumber()); 439 } 440 else { 441 paymentAccountDetail.setSubAccountNbr(OLEConstants.getDashSubAccountNumber()); 442 } 443 paymentAccountDetail.setFinObjectCode(customer.getDefaultObjectCode()); 444 if (StringUtils.isNotBlank(customer.getDefaultSubAccountNumber())) { 445 paymentAccountDetail.setFinSubObjectCode(customer.getDefaultSubObjectCode()); 446 } 447 else { 448 paymentAccountDetail.setFinSubObjectCode(OLEConstants.getDashFinancialSubObjectCode()); 449 } 450 } 451 452 /** 453 * Helper method to construct a new payment account history record 454 * 455 * @param attName name of field that has changed 456 * @param newValue new value for the field 457 * @param oldValue field value that was changed 458 * @param changeCode code indicating reason for change 459 * @return <code>PaymentAccountHistory</code> 460 */ 461 protected PaymentAccountHistory newAccountHistory(String attName, String newValue, String oldValue, KualiCodeBase changeCode) { 462 PaymentAccountHistory paymentAccountHistory = new PaymentAccountHistory(); 463 464 paymentAccountHistory.setAcctAttributeName(attName); 465 paymentAccountHistory.setAcctAttributeNewValue(newValue); 466 paymentAccountHistory.setAcctAttributeOrigValue(oldValue); 467 paymentAccountHistory.setAcctChangeDate(dateTimeService.getCurrentTimestamp()); 468 paymentAccountHistory.setAccountingChange((AccountingChangeCode) changeCode); 469 470 return paymentAccountHistory; 471 } 472 473 /** 474 * Sets null amount fields to 0 475 * 476 * @param paymentDetail <code>PaymentDetail</code> to update 477 */ 478 protected void updateDetailAmounts(PaymentDetail paymentDetail) { 479 KualiDecimal zero = KualiDecimal.ZERO; 480 481 if (paymentDetail.getInvTotDiscountAmount() == null) { 482 paymentDetail.setInvTotDiscountAmount(zero); 483 } 484 485 if (paymentDetail.getInvTotShipAmount() == null) { 486 paymentDetail.setInvTotShipAmount(zero); 487 } 488 489 if (paymentDetail.getInvTotOtherDebitAmount() == null) { 490 paymentDetail.setInvTotOtherDebitAmount(zero); 491 } 492 493 if (paymentDetail.getInvTotOtherCreditAmount() == null) { 494 paymentDetail.setInvTotOtherCreditAmount(zero); 495 } 496 497 // update the total payment amount with the amount from the accounts if null 498 if (paymentDetail.getNetPaymentAmount() == null) { 499 paymentDetail.setNetPaymentAmount(paymentDetail.getAccountTotal()); 500 } 501 502 if (paymentDetail.getOrigInvoiceAmount() == null) { 503 KualiDecimal amt = paymentDetail.getNetPaymentAmount(); 504 amt = amt.add(paymentDetail.getInvTotDiscountAmount()); 505 amt = amt.subtract(paymentDetail.getInvTotShipAmount()); 506 amt = amt.subtract(paymentDetail.getInvTotOtherDebitAmount()); 507 amt = amt.add(paymentDetail.getInvTotOtherCreditAmount()); 508 paymentDetail.setOrigInvoiceAmount(amt); 509 } 510 } 511 512 /** 513 * Sets null indicators to false 514 * 515 * @param paymentGroup <code>PaymentGroup</code> to update 516 */ 517 protected void defaultGroupIndicators(PaymentGroup paymentGroup) { 518 // combineGroups column does not accept null values, so it will never be null 519 /* 520 * if (paymentGroup.getCombineGroups() == null) { paymentGroup.setCombineGroups(Boolean.TRUE); } 521 */ 522 523 if (paymentGroup.getCampusAddress() == null) { 524 paymentGroup.setCampusAddress(Boolean.FALSE); 525 } 526 527 if (paymentGroup.getPymtAttachment() == null) { 528 paymentGroup.setPymtAttachment(Boolean.FALSE); 529 } 530 531 if (paymentGroup.getPymtSpecialHandling() == null) { 532 paymentGroup.setPymtSpecialHandling(Boolean.FALSE); 533 } 534 535 if (paymentGroup.getProcessImmediate() == null) { 536 paymentGroup.setProcessImmediate(Boolean.FALSE); 537 } 538 539 if (paymentGroup.getEmployeeIndicator() == null) { 540 paymentGroup.setEmployeeIndicator(Boolean.FALSE); 541 } 542 543 if (paymentGroup.getNraPayment() == null) { 544 paymentGroup.setNraPayment(Boolean.FALSE); 545 } 546 547 if (paymentGroup.getTaxablePayment() == null) { 548 paymentGroup.setTaxablePayment(Boolean.FALSE); 549 } 550 } 551 552 /** 553 * Checks whether payment status should be set to held and a tax email sent indicating so 554 * 555 * @param paymentFile payment file object 556 * @param paymentGroup <code>PaymentGroup</code> being checked 557 * @param customer payment customer 558 */ 559 protected void checkForTaxEmailRequired(PaymentFileLoad paymentFile, PaymentGroup paymentGroup, CustomerProfile customer) { 560 PaymentStatus heldForNRAEmployee = businessObjectService.findBySinglePrimaryKey(PaymentStatus.class, PdpConstants.PaymentStatusCodes.HELD_TAX_NRA_EMPL_CD); 561 PaymentStatus heldForEmployee = businessObjectService.findBySinglePrimaryKey(PaymentStatus.class, PdpConstants.PaymentStatusCodes.HELD_TAX_EMPLOYEE_CD); 562 PaymentStatus heldForNRA = businessObjectService.findBySinglePrimaryKey(PaymentStatus.class, PdpConstants.PaymentStatusCodes.HELD_TAX_NRA_CD); 563 564 if (customer.getNraReview() && customer.getEmployeeCheck() && paymentGroup.getEmployeeIndicator().booleanValue() && paymentGroup.getNraPayment().booleanValue()) { 565 paymentGroup.setPaymentStatus(heldForNRAEmployee); 566 paymentFile.setTaxEmailRequired(true); 567 } 568 569 else if (customer.getEmployeeCheck() && paymentGroup.getEmployeeIndicator().booleanValue()) { 570 paymentGroup.setPaymentStatus(heldForEmployee); 571 paymentFile.setTaxEmailRequired(true); 572 } 573 574 else if (customer.getNraReview() && paymentGroup.getNraPayment().booleanValue()) { 575 paymentGroup.setPaymentStatus(heldForNRA); 576 paymentFile.setTaxEmailRequired(true); 577 } 578 } 579 580 /** 581 * Checks the payment date is not more than 30 days past or 30 days coming 582 * 583 * @param paymentGroup <code>PaymentGroup</code> being checked 584 * @param warnings <code>List</code> list of accumulated warning messages 585 */ 586 protected void checkGroupPaymentDate(PaymentGroup paymentGroup, List<String> warnings) { 587 Timestamp now = dateTimeService.getCurrentTimestamp(); 588 589 Calendar nowPlus30 = Calendar.getInstance(); 590 nowPlus30.setTime(now); 591 nowPlus30.add(Calendar.DATE, 30); 592 593 Calendar nowMinus30 = Calendar.getInstance(); 594 nowMinus30.setTime(now); 595 nowMinus30.add(Calendar.DATE, -30); 596 597 if (paymentGroup.getPaymentDate() != null) { 598 Calendar payDate = Calendar.getInstance(); 599 payDate.setTime(paymentGroup.getPaymentDate()); 600 601 if (payDate.before(nowMinus30)) { 602 addWarningMessage(warnings, PdpKeyConstants.MESSAGE_PAYMENT_LOAD_PAYDATE_OVER_30_DAYS_PAST, dateTimeService.toDateString(paymentGroup.getPaymentDate())); 603 } 604 605 if (payDate.after(nowPlus30)) { 606 addWarningMessage(warnings, PdpKeyConstants.MESSAGE_PAYMENT_LOAD_PAYDATE_OVER_30_DAYS_OUT, dateTimeService.toDateString(paymentGroup.getPaymentDate())); 607 } 608 } 609 else { 610 try { 611 paymentGroup.setPaymentDate(dateTimeService.convertToSqlDate(now)); 612 } 613 catch (ParseException e) { 614 throw new RuntimeException("Unable to parse current timestamp into sql date " + e.getMessage()); 615 } 616 } 617 } 618 619 /** 620 * @return system parameter value giving the maximum number of notes allowed. 621 */ 622 protected int getMaxNoteLines() { 623 String maxLines = parameterService.getParameterValueAsString(OleParameterConstants.PRE_DISBURSEMENT_ALL.class, PdpParameterConstants.MAX_NOTE_LINES); 624 if (StringUtils.isBlank(maxLines)) { 625 throw new RuntimeException("System parameter for max note lines is blank"); 626 } 627 628 return Integer.parseInt(maxLines); 629 } 630 631 /** 632 * Helper method for subsituting message parameters and adding the message to the warning list. 633 * 634 * @param warnings <code>List</code> of messages to add to 635 * @param messageKey resource key for message 636 * @param arguments message substitute parameters 637 */ 638 protected void addWarningMessage(List<String> warnings, String messageKey, String... arguments) { 639 String message = kualiConfigurationService.getPropertyValueAsString(messageKey); 640 warnings.add(MessageFormat.format(message, (Object[]) arguments)); 641 } 642 643 /** 644 * Sets the customerProfileService attribute value. 645 * 646 * @param customerProfileService The customerProfileService to set. 647 */ 648 public void setCustomerProfileService(CustomerProfileService customerProfileService) { 649 this.customerProfileService = customerProfileService; 650 } 651 652 /** 653 * Sets the paymentFileLoadDao attribute value. 654 * 655 * @param paymentFileLoadDao The paymentFileLoadDao to set. 656 */ 657 public void setPaymentFileLoadDao(PaymentFileLoadDao paymentFileLoadDao) { 658 this.paymentFileLoadDao = paymentFileLoadDao; 659 } 660 661 /** 662 * Sets the parameterService attribute value. 663 * 664 * @param parameterService The parameterService to set. 665 */ 666 public void setParameterService(ParameterService parameterService) { 667 this.parameterService = parameterService; 668 } 669 670 /** 671 * Sets the dateTimeService attribute value. 672 * 673 * @param dateTimeService The dateTimeService to set. 674 */ 675 public void setDateTimeService(DateTimeService dateTimeService) { 676 this.dateTimeService = dateTimeService; 677 } 678 679 /** 680 * Sets the accountService attribute value. 681 * 682 * @param accountService The accountService to set. 683 */ 684 public void setAccountService(AccountService accountService) { 685 this.accountService = accountService; 686 } 687 688 /** 689 * Sets the subAccountService attribute value. 690 * 691 * @param subAccountService The subAccountService to set. 692 */ 693 public void setSubAccountService(SubAccountService subAccountService) { 694 this.subAccountService = subAccountService; 695 } 696 697 /** 698 * Sets the objectCodeService attribute value. 699 * 700 * @param objectCodeService The objectCodeService to set. 701 */ 702 public void setObjectCodeService(ObjectCodeService objectCodeService) { 703 this.objectCodeService = objectCodeService; 704 } 705 706 /** 707 * Sets the subObjectCodeService attribute value. 708 * 709 * @param subObjectCodeService The subObjectCodeService to set. 710 */ 711 public void setSubObjectCodeService(SubObjectCodeService subObjectCodeService) { 712 this.subObjectCodeService = subObjectCodeService; 713 } 714 715 /** 716 * Sets the kualiConfigurationService attribute value. 717 * 718 * @param kualiConfigurationService The kualiConfigurationService to set. 719 */ 720 public void setConfigurationService(ConfigurationService kualiConfigurationService) { 721 this.kualiConfigurationService = kualiConfigurationService; 722 } 723 724 /** 725 * Sets the bankService attribute value. 726 * 727 * @param bankService The bankService to set. 728 */ 729 public void setBankService(BankService bankService) { 730 this.bankService = bankService; 731 } 732 733 /** 734 * Sets the originationCodeService attribute value. 735 * 736 * @param originationCodeService The originationCodeService to set. 737 */ 738 public void setOriginationCodeService(OriginationCodeService originationCodeService) { 739 this.originationCodeService = originationCodeService; 740 } 741 742 /** 743 * Gets the businessObjectService attribute. 744 * 745 * @return Returns the businessObjectService. 746 */ 747 protected BusinessObjectService getBusinessObjectService() { 748 return businessObjectService; 749 } 750 751 /** 752 * Sets the businessObjectService attribute value. 753 * 754 * @param businessObjectService The businessObjectService to set. 755 */ 756 public void setBusinessObjectService(BusinessObjectService businessObjectService) { 757 this.businessObjectService = businessObjectService; 758 } 759 760 public void setDocumentTypeService(DocumentTypeService documentTypeService) { 761 this.documentTypeService = documentTypeService; 762 } 763 764}