/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Created on Aug 12, 2004 */ package org.kuali.kfs.pdp.service.impl; import java.sql.Timestamp; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.kuali.kfs.pdp.PdpConstants; import org.kuali.kfs.pdp.PdpKeyConstants; import org.kuali.kfs.pdp.PdpPropertyConstants; import org.kuali.kfs.pdp.businessobject.AchAccountNumber; import org.kuali.kfs.pdp.businessobject.PaymentChangeCode; import org.kuali.kfs.pdp.businessobject.PaymentDetail; import org.kuali.kfs.pdp.businessobject.PaymentGroup; import org.kuali.kfs.pdp.businessobject.PaymentGroupHistory; import org.kuali.kfs.pdp.businessobject.PaymentNoteText; import org.kuali.kfs.pdp.businessobject.PaymentStatus; import org.kuali.kfs.pdp.dataaccess.PaymentDetailDao; import org.kuali.kfs.pdp.dataaccess.PaymentGroupDao; import org.kuali.kfs.pdp.service.PaymentGroupService; import org.kuali.kfs.pdp.service.PaymentMaintenanceService; import org.kuali.kfs.pdp.service.PdpAuthorizationService; import org.kuali.kfs.pdp.service.PdpEmailService; import org.kuali.kfs.pdp.service.PendingTransactionService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.service.BankService; import org.kuali.rice.core.api.util.type.KualiInteger; import org.kuali.rice.coreservice.framework.parameter.ParameterService; import org.kuali.rice.kim.api.identity.Person; import org.kuali.rice.krad.bo.KualiCode; import org.kuali.rice.krad.service.BusinessObjectService; import org.kuali.rice.krad.service.MailService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.ObjectUtils; import org.springframework.transaction.annotation.Transactional; /** * @see org.kuali.kfs.pdp.service.PaymentMaintenanceService */ @Transactional public class PaymentMaintenanceServiceImpl implements PaymentMaintenanceService { private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentMaintenanceServiceImpl.class); private PaymentGroupDao paymentGroupDao; private PaymentDetailDao paymentDetailDao; private PendingTransactionService glPendingTransactionService; private MailService mailService; private ParameterService parameterService; private BankService bankService; private BusinessObjectService businessObjectService; private PaymentGroupService paymentGroupService; private PdpEmailService emailService; private PdpAuthorizationService pdpAuthorizationService; /** * This method changes status for a payment group. * * @param paymentGroup the payment group * @param newPaymentStatus the new payment status * @param changeStatus the changed payment status * @param note a note for payment status change * @param user the user that changed the status */ protected void changeStatus(PaymentGroup paymentGroup, String newPaymentStatus, String changeStatus, String note, Person user) { if (LOG.isDebugEnabled()) { LOG.debug("changeStatus() enter method with new status of " + newPaymentStatus); } PaymentGroupHistory paymentGroupHistory = new PaymentGroupHistory(); KualiCode cd = businessObjectService.findBySinglePrimaryKey(PaymentChangeCode.class, changeStatus); paymentGroupHistory.setPaymentChange((PaymentChangeCode) cd); paymentGroupHistory.setOrigPaymentStatus(paymentGroup.getPaymentStatus()); paymentGroupHistory.setChangeUser(user); paymentGroupHistory.setChangeNoteText(note); paymentGroupHistory.setPaymentGroup(paymentGroup); paymentGroupHistory.setChangeTime(new Timestamp(new Date().getTime())); this.businessObjectService.save(paymentGroupHistory); KualiCode code = businessObjectService.findBySinglePrimaryKey(PaymentStatus.class, newPaymentStatus); paymentGroup.setPaymentStatus((PaymentStatus) code); this.businessObjectService.save(paymentGroup); LOG.debug("changeStatus() Status has been changed; exit method."); } /** * This method changes the state of a paymentGroup. * * @param paymentGroup the payment group to change the state for * @param newPaymentStatus the new payment status * @param changeStatus the status that is changed * @param note the note entered by the user * @param user the user that changed the * @param paymentGroupHistory */ protected void changeStatus(PaymentGroup paymentGroup, String newPaymentStatus, String changeStatus, String note, Person user, PaymentGroupHistory paymentGroupHistory) { if (LOG.isDebugEnabled()) { LOG.debug("changeStatus() enter method with new status of " + newPaymentStatus); } KualiCode cd = businessObjectService.findBySinglePrimaryKey(PaymentChangeCode.class, changeStatus); paymentGroupHistory.setPaymentChange((PaymentChangeCode) cd); paymentGroupHistory.setOrigPaymentStatus(paymentGroup.getPaymentStatus()); paymentGroupHistory.setChangeUser(user); paymentGroupHistory.setChangeNoteText(note); paymentGroupHistory.setPaymentGroup(paymentGroup); paymentGroupHistory.setChangeTime(new Timestamp(new Date().getTime())); this.businessObjectService.save(paymentGroupHistory); KualiCode code = businessObjectService.findBySinglePrimaryKey(PaymentStatus.class, newPaymentStatus); if (paymentGroup.getPaymentStatus() != ((PaymentStatus) code)) { paymentGroup.setPaymentStatus((PaymentStatus) code); } this.businessObjectService.save(paymentGroup); LOG.debug("changeStatus() Status has been changed; exit method."); } /** * @see org.kuali.kfs.pdp.document.service.PaymentMaintenanceService#cancelPendingPayment(java.lang.Integer, java.lang.Integer, * java.lang.String, org.kuali.rice.kim.api.identity.Person) */ @Override public boolean cancelPendingPayment(Integer paymentGroupId, Integer paymentDetailId, String note, Person user) { // All actions must be performed on entire group not individual detail record if (LOG.isDebugEnabled()) { LOG.debug("cancelPendingPayment() Enter method to cancel pending payment with group id = " + paymentGroupId); LOG.debug("cancelPendingPayment() payment detail id being cancelled = " + paymentDetailId); } PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId); if (paymentGroup == null) { LOG.debug("cancelPendingPayment() Pending payment not found; throw exception."); GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_NOT_FOUND); return false; } String paymentStatus = paymentGroup.getPaymentStatus().getCode(); if (!(PdpConstants.PaymentStatusCodes.CANCEL_PAYMENT.equals(paymentStatus))) { if (LOG.isDebugEnabled()) { LOG.debug("cancelPendingPayment() Payment status is " + paymentStatus + "; continue with cancel."); } if ((PdpConstants.PaymentStatusCodes.HELD_TAX_EMPLOYEE_CD.equals(paymentStatus)) || (PdpConstants.PaymentStatusCodes.HELD_TAX_NRA_CD.equals(paymentStatus)) || (PdpConstants.PaymentStatusCodes.HELD_TAX_NRA_EMPL_CD.equals(paymentStatus))) { if (!pdpAuthorizationService.hasRemovePaymentTaxHoldPermission(user.getPrincipalId())) { LOG.warn("cancelPendingPayment() Payment status is " + paymentStatus + "; user does not have rights to cancel. This should not happen unless user is URL spoofing."); throw new RuntimeException("cancelPendingPayment() Payment status is " + paymentStatus + "; user does not have rights to cancel. This should not happen unless user is URL spoofing."); } changeStatus(paymentGroup, PdpConstants.PaymentStatusCodes.CANCEL_PAYMENT, PdpConstants.PaymentChangeCodes.CANCEL_PAYMENT_CHNG_CD, note, user); // set primary cancel indicator for EPIC to use Map primaryKeys = new HashMap(); primaryKeys.put(PdpPropertyConstants.PaymentDetail.PAYMENT_ID, paymentDetailId); PaymentDetail pd = this.businessObjectService.findByPrimaryKey(PaymentDetail.class, primaryKeys); if (pd != null) { pd.setPrimaryCancelledPayment(Boolean.TRUE); } this.businessObjectService.save(pd); this.emailService.sendCancelEmail(paymentGroup, note, user); LOG.debug("cancelPendingPayment() Pending payment cancelled and mail was sent; exit method."); } else if (PdpConstants.PaymentStatusCodes.OPEN.equals(paymentStatus) || PdpConstants.PaymentStatusCodes.HELD_CD.equals(paymentStatus)) { if (!pdpAuthorizationService.hasCancelPaymentPermission(user.getPrincipalId())) { LOG.warn("cancelPendingPayment() Payment status is " + paymentStatus + "; user does not have rights to cancel. This should not happen unless user is URL spoofing."); throw new RuntimeException("cancelPendingPayment() Payment status is " + paymentStatus + "; user does not have rights to cancel. This should not happen unless user is URL spoofing."); } changeStatus(paymentGroup, PdpConstants.PaymentStatusCodes.CANCEL_PAYMENT, PdpConstants.PaymentChangeCodes.CANCEL_PAYMENT_CHNG_CD, note, user); // set primary cancel indicator for EPIC to use Map primaryKeys = new HashMap(); primaryKeys.put(PdpPropertyConstants.PaymentDetail.PAYMENT_ID, paymentDetailId); PaymentDetail pd = this.businessObjectService.findByPrimaryKey(PaymentDetail.class, primaryKeys); if (pd != null) { pd.setPrimaryCancelledPayment(Boolean.TRUE); PaymentNoteText payNoteText = new PaymentNoteText(); payNoteText.setCustomerNoteLineNbr(new KualiInteger(pd.getNotes().size() + 1)); payNoteText.setCustomerNoteText(note); pd.addNote(payNoteText); } this.businessObjectService.save(pd); LOG.debug("cancelPendingPayment() Pending payment cancelled; exit method."); } else { if (LOG.isDebugEnabled()) { LOG.debug("cancelPendingPayment() Payment status is " + paymentStatus + "; cannot cancel payment in this status"); } GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_INVALID_STATUS_TO_CANCEL); return false; } } else { LOG.debug("cancelPendingPayment() Pending payment group has already been cancelled; exit method."); } return true; } /** * @see org.kuali.kfs.pdp.document.service.PaymentMaintenanceService#holdPendingPayment(java.lang.Integer, java.lang.String, * org.kuali.rice.kim.api.identity.Person) */ @Override public boolean holdPendingPayment(Integer paymentGroupId, String note, Person user) { // All actions must be performed on entire group not individual detail record if (LOG.isDebugEnabled()) { LOG.debug("holdPendingPayment() Enter method to hold pending payment with id = " + paymentGroupId); } if (!pdpAuthorizationService.hasHoldPaymentPermission(user.getPrincipalId())) { LOG.warn("holdPendingPayment() User " + user.getPrincipalId() + " does not have rights to hold payments. This should not happen unless user is URL spoofing."); throw new RuntimeException("holdPendingPayment() User " + user.getPrincipalId() + " does not have rights to hold payments. This should not happen unless user is URL spoofing."); } PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId); if (paymentGroup == null) { LOG.debug("holdPendingPayment() Pending payment not found; throw exception."); GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_NOT_FOUND); return false; } String paymentStatus = paymentGroup.getPaymentStatus().getCode(); if (!(PdpConstants.PaymentStatusCodes.HELD_CD.equals(paymentStatus))) { if (PdpConstants.PaymentStatusCodes.OPEN.equals(paymentStatus)) { if (LOG.isDebugEnabled()) { LOG.debug("holdPendingPayment() Payment status is " + paymentStatus + "; continue with hold."); } changeStatus(paymentGroup, PdpConstants.PaymentStatusCodes.HELD_CD, PdpConstants.PaymentChangeCodes.HOLD_CHNG_CD, note, user); LOG.debug("holdPendingPayment() Pending payment was put on hold; exit method."); } else { if (LOG.isDebugEnabled()) { LOG.debug("holdPendingPayment() Payment status is " + paymentStatus + "; cannot hold payment in this status"); } GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_INVALID_STATUS_TO_HOLD); return false; } } else { LOG.debug("holdPendingPayment() Pending payment group has already been held; exit method."); } return true; } /** * @see org.kuali.kfs.pdp.document.service.PaymentMaintenanceService#removeHoldPendingPayment(java.lang.Integer, * java.lang.String, org.kuali.rice.kim.api.identity.Person) */ @Override public boolean removeHoldPendingPayment(Integer paymentGroupId, String note, Person user) { // All actions must be performed on entire group not individual detail record if (LOG.isDebugEnabled()) { LOG.debug("removeHoldPendingPayment() Enter method to hold pending payment with id = " + paymentGroupId); } PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId); if (paymentGroup == null) { LOG.debug("removeHoldPendingPayment() Payment not found; throw exception."); GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_NOT_FOUND); return false; } String paymentStatus = paymentGroup.getPaymentStatus().getCode(); if (!(PdpConstants.PaymentStatusCodes.OPEN.equals(paymentStatus))) { if (LOG.isDebugEnabled()) { LOG.debug("removeHoldPendingPayment() Payment status is " + paymentStatus + "; continue with hold removal."); } if ((PdpConstants.PaymentStatusCodes.HELD_TAX_EMPLOYEE_CD.equals(paymentStatus)) || (PdpConstants.PaymentStatusCodes.HELD_TAX_NRA_CD.equals(paymentStatus)) || (PdpConstants.PaymentStatusCodes.HELD_TAX_NRA_EMPL_CD.equals(paymentStatus))) { if (!pdpAuthorizationService.hasRemovePaymentTaxHoldPermission(user.getPrincipalId())) { LOG.warn("removeHoldPendingPayment() User " + user.getPrincipalId() + " does not have rights to remove tax holds. This should not happen unless user is URL spoofing."); throw new RuntimeException("removeHoldPendingPayment() User " + user.getPrincipalId() + " does not have rights to remove tax holds. This should not happen unless user is URL spoofing."); } changeStatus(paymentGroup, PdpConstants.PaymentStatusCodes.OPEN, PdpConstants.PaymentChangeCodes.REMOVE_HOLD_CHNG_CD, note, user); LOG.debug("removeHoldPendingPayment() Pending payment was taken off hold; exit method."); } else if (PdpConstants.PaymentStatusCodes.HELD_CD.equals(paymentStatus)) { if (!pdpAuthorizationService.hasHoldPaymentPermission(user.getPrincipalId())) { LOG.warn("removeHoldPendingPayment() User " + user.getPrincipalId() + " does not have rights to hold payments. This should not happen unless user is URL spoofing."); throw new RuntimeException("removeHoldPendingPayment() User " + user.getPrincipalId() + " does not have rights to hold payments. This should not happen unless user is URL spoofing."); } changeStatus(paymentGroup, PdpConstants.PaymentStatusCodes.OPEN, PdpConstants.PaymentChangeCodes.REMOVE_HOLD_CHNG_CD, note, user); LOG.debug("removeHoldPendingPayment() Pending payment was taken off hold; exit method."); } else { if (LOG.isDebugEnabled()) { LOG.debug("removeHoldPendingPayment() Payment status is " + paymentStatus + "; cannot remove hold on payment in this status"); } GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_INVALID_STATUS_TO_REMOVE_HOLD); return false; } } else { LOG.debug("removeHoldPendingPayment() Pending payment group has already been un-held; exit method."); } return true; } /** * @see org.kuali.kfs.pdp.document.service.PaymentMaintenanceService#changeImmediateFlag(java.lang.Integer, java.lang.String, * org.kuali.rice.kim.api.identity.Person) */ @Override public void changeImmediateFlag(Integer paymentGroupId, String note, Person user) { // All actions must be performed on entire group not individual detail record if (LOG.isDebugEnabled()) { LOG.debug("changeImmediateFlag() Enter method to hold pending payment with id = " + paymentGroupId); } if (!pdpAuthorizationService.hasSetAsImmediatePayPermission(user.getPrincipalId())) { LOG.warn("changeImmediateFlag() User " + user.getPrincipalId() + " does not have rights to set payments as immediate. This should not happen unless user is URL spoofing."); throw new RuntimeException("changeImmediateFlag() User " + user.getPrincipalId() + " does not have rights to payments as immediate. This should not happen unless user is URL spoofing."); } PaymentGroupHistory paymentGroupHistory = new PaymentGroupHistory(); PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId); paymentGroupHistory.setOrigProcessImmediate(paymentGroup.getProcessImmediate()); if (paymentGroup.getProcessImmediate().equals(Boolean.TRUE)) { paymentGroup.setProcessImmediate(Boolean.FALSE); } else { paymentGroup.setProcessImmediate(Boolean.TRUE); } changeStatus(paymentGroup, paymentGroup.getPaymentStatus().getCode(), PdpConstants.PaymentChangeCodes.CHANGE_IMMEDIATE_CHNG_CD, note, user, paymentGroupHistory); LOG.debug("changeImmediateFlag() exit method."); } /** * @see org.kuali.kfs.pdp.document.service.PaymentMaintenanceService#cancelDisbursement(java.lang.Integer, java.lang.Integer, * java.lang.String, org.kuali.rice.kim.api.identity.Person) */ @Override public boolean cancelDisbursement(Integer paymentGroupId, Integer paymentDetailId, String note, Person user) { // All actions must be performed on entire group not individual detail record if (LOG.isDebugEnabled()) { LOG.debug("cancelDisbursement() Enter method to cancel disbursement with id = " + paymentGroupId); } if (!pdpAuthorizationService.hasCancelPaymentPermission(user.getPrincipalId())) { LOG.warn("cancelDisbursement() User " + user.getPrincipalId() + " does not have rights to cancel payments. This should not happen unless user is URL spoofing."); throw new RuntimeException("cancelDisbursement() User " + user.getPrincipalId() + " does not have rights to cancel payments. This should not happen unless user is URL spoofing."); } PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId); if (paymentGroup == null) { LOG.debug("cancelDisbursement() Disbursement not found; throw exception."); GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_NOT_FOUND); return false; } String paymentStatus = paymentGroup.getPaymentStatus().getCode(); if (!(PdpConstants.PaymentStatusCodes.CANCEL_DISBURSEMENT.equals(paymentStatus))) { if (((PdpConstants.PaymentStatusCodes.EXTRACTED.equals(paymentStatus)) && (ObjectUtils.isNotNull(paymentGroup.getDisbursementDate()))) || (PdpConstants.PaymentStatusCodes.PENDING_ACH.equals(paymentStatus))) { if (LOG.isDebugEnabled()) { LOG.debug("cancelDisbursement() Payment status is " + paymentStatus + "; continue with cancel."); } List<PaymentGroup> allDisbursementPaymentGroups = this.paymentGroupService.getByDisbursementNumber(paymentGroup.getDisbursementNbr().intValue()); for (PaymentGroup element : allDisbursementPaymentGroups) { PaymentGroupHistory pgh = new PaymentGroupHistory(); if (!element.getPaymentDetails().get(0).isDisbursementActionAllowed()) { LOG.warn("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing."); throw new RuntimeException("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing."); } if ((ObjectUtils.isNotNull(element.getDisbursementType())) && (element.getDisbursementType().getCode().equals(PdpConstants.DisbursementTypeCodes.CHECK))) { pgh.setPmtCancelExtractStat(Boolean.FALSE); } changeStatus(element, PdpConstants.PaymentStatusCodes.CANCEL_DISBURSEMENT, PdpConstants.PaymentChangeCodes.CANCEL_DISBURSEMENT, note, user, pgh); glPendingTransactionService.generateCancellationGeneralLedgerPendingEntry(element); // set primary cancel indicator for EPIC to use // these payment details will be canceled when running processPdpCancelAndPaidJOb Map<String, KualiInteger> primaryKeys = new HashMap<String, KualiInteger>(); // KFSCNTRB-1705: use PAYMENT_DETAIL_PAYMENT_GROUP_ID instead of PAYMENT_ID since now we're starting to have Payment Group ID // values assigned in PDP whose values just happen to not have identical values in the Payment Detail ID field. primaryKeys.put(PdpPropertyConstants.PaymentDetail.PAYMENT_DETAIL_PAYMENT_GROUP_ID, element.getId()); // cancel all payment details for payment group List<PaymentDetail> pds = (List<PaymentDetail>) this.businessObjectService.findMatching(PaymentDetail.class, primaryKeys); if (pds != null && !pds.isEmpty()) { for(PaymentDetail pd : pds) { pd.setPrimaryCancelledPayment(Boolean.TRUE); this.businessObjectService.save(pd); } } } LOG.debug("cancelDisbursement() Disbursement cancelled; exit method."); } else { if (LOG.isDebugEnabled()) { LOG.debug("cancelDisbursement() Payment status is " + paymentStatus + " and disbursement date is " + paymentGroup.getDisbursementDate() + "; cannot cancel payment in this status"); } GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_INVALID_TO_CANCEL); return false; } } else { LOG.debug("cancelDisbursement() Disbursement has already been cancelled; exit method."); } return true; } /** * @see org.kuali.kfs.pdp.document.service.PaymentMaintenanceService#reissueDisbursement(java.lang.Integer, * java.lang.String, org.kuali.rice.kim.api.identity.Person) */ @Override public boolean reissueDisbursement(Integer paymentGroupId, String note, Person user) { // All actions must be performed on entire group not individual detail record if (LOG.isDebugEnabled()) { LOG.debug("reissueDisbursement() Enter method to reissue disbursement with id = " + paymentGroupId); } PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId); if (paymentGroup == null) { LOG.debug("reissueDisbursement() Disbursement not found; throw exception."); GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_NOT_FOUND); return false; } String paymentStatus = paymentGroup.getPaymentStatus().getCode(); if (!(PdpConstants.PaymentStatusCodes.OPEN.equals(paymentStatus))) { if (((PdpConstants.PaymentStatusCodes.CANCEL_DISBURSEMENT.equals(paymentStatus)) && (ObjectUtils.isNotNull(paymentGroup.getDisbursementDate())))) { if (LOG.isDebugEnabled()) { LOG.debug("reissueDisbursement() Payment status is " + paymentStatus + "; continue with reissue."); } List<PaymentGroup> allDisbursementPaymentGroups = this.paymentGroupService.getByDisbursementNumber(paymentGroup.getDisbursementNbr().intValue()); for (PaymentGroup pg : allDisbursementPaymentGroups) { PaymentGroupHistory pgh = new PaymentGroupHistory(); if (!pg.getPaymentDetails().get(0).isDisbursementActionAllowed()) { LOG.warn("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing."); throw new RuntimeException("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing."); } pgh.setOrigProcessImmediate(pg.getProcessImmediate()); pgh.setOrigPmtSpecHandling(pg.getPymtSpecialHandling()); pgh.setBank(pg.getBank()); pgh.setOrigPaymentDate(pg.getPaymentDate()); //put a check for null since disbursement date was not set in testMode / dev if (ObjectUtils.isNotNull(pg.getDisbursementDate())) { pgh.setOrigDisburseDate(new Timestamp(pg.getDisbursementDate().getTime())); } pgh.setOrigAchBankRouteNbr(pg.getAchBankRoutingNbr()); pgh.setOrigDisburseNbr(pg.getDisbursementNbr()); pgh.setOrigAdviceEmail(pg.getAdviceEmailAddress()); pgh.setDisbursementType(pg.getDisbursementType()); pgh.setProcess(pg.getProcess()); // glPendingTransactionService.generateReissueGeneralLedgerPendingEntry(pg); if (LOG.isDebugEnabled()) { LOG.debug("cancelReissueDisbursement() Status is '" + paymentStatus + "; delete row from AchAccountNumber table."); } AchAccountNumber achAccountNumber = pg.getAchAccountNumber(); if (ObjectUtils.isNotNull(achAccountNumber)) { this.businessObjectService.delete(achAccountNumber); pg.setAchAccountNumber(null); } // if bank functionality is not enabled or the group bank is inactive clear bank code if (!bankService.isBankSpecificationEnabled() || !pg.getBank().isActive()) { pg.setBank(null); } pg.setDisbursementDate((java.sql.Date) null); pg.setAchBankRoutingNbr(null); pg.setAchAccountType(null); pg.setPhysCampusProcessCd(null); pg.setDisbursementNbr((KualiInteger) null); pg.setAdviceEmailAddress(null); pg.setDisbursementType(null); pg.setProcess(null); pg.setProcessImmediate(false); changeStatus(pg, PdpConstants.PaymentStatusCodes.OPEN, PdpConstants.PaymentChangeCodes.REISSUE_DISBURSEMENT, note, user, pgh); } LOG.debug("reissueDisbursement() Disbursement reissued; exit method."); } else { if (LOG.isDebugEnabled()) { LOG.debug("cancelReissueDisbursement() Payment status is " + paymentStatus + " and disbursement date is " + paymentGroup.getDisbursementDate() + "; cannot cancel payment"); } GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_INVALID_TO_CANCEL_AND_REISSUE); return false; } } else { LOG.debug("cancelReissueDisbursement() Disbursement already cancelled and reissued; exit method."); } return true; } /** * @see org.kuali.kfs.pdp.document.service.PaymentMaintenanceService#cancelReissueDisbursement(java.lang.Integer, * java.lang.String, org.kuali.rice.kim.api.identity.Person) */ @Override public boolean cancelReissueDisbursement(Integer paymentGroupId, String note, Person user) { // All actions must be performed on entire group not individual detail record if (LOG.isDebugEnabled()) { LOG.debug("cancelReissueDisbursement() Enter method to cancel disbursement with id = " + paymentGroupId); } if (!pdpAuthorizationService.hasCancelPaymentPermission(user.getPrincipalId())) { LOG.warn("cancelReissueDisbursement() User " + user.getPrincipalId() + " does not have rights to cancel payments. This should not happen unless user is URL spoofing."); throw new RuntimeException("cancelReissueDisbursement() User " + user.getPrincipalId() + " does not have rights to cancel payments. This should not happen unless user is URL spoofing."); } PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId); if (paymentGroup == null) { LOG.debug("cancelReissueDisbursement() Disbursement not found; throw exception."); GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_NOT_FOUND); return false; } String paymentStatus = paymentGroup.getPaymentStatus().getCode(); if (!(PdpConstants.PaymentStatusCodes.OPEN.equals(paymentStatus))) { if (((PdpConstants.PaymentStatusCodes.EXTRACTED.equals(paymentStatus)) && (ObjectUtils.isNotNull(paymentGroup.getDisbursementDate()))) || (PdpConstants.PaymentStatusCodes.PENDING_ACH.equals(paymentStatus))) { if (LOG.isDebugEnabled()) { LOG.debug("cancelReissueDisbursement() Payment status is " + paymentStatus + "; continue with cancel."); } List<PaymentGroup> allDisbursementPaymentGroups = this.paymentGroupService.getByDisbursementNumber(paymentGroup.getDisbursementNbr().intValue()); for (PaymentGroup pg : allDisbursementPaymentGroups) { PaymentGroupHistory pgh = new PaymentGroupHistory(); if (!pg.getPaymentDetails().get(0).isDisbursementActionAllowed()) { LOG.warn("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing."); throw new RuntimeException("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing."); } if ((ObjectUtils.isNotNull(pg.getDisbursementType())) && (pg.getDisbursementType().getCode().equals(PdpConstants.DisbursementTypeCodes.CHECK))) { pgh.setPmtCancelExtractStat(Boolean.FALSE); } pgh.setOrigProcessImmediate(pg.getProcessImmediate()); pgh.setOrigPmtSpecHandling(pg.getPymtSpecialHandling()); pgh.setBank(pg.getBank()); pgh.setOrigPaymentDate(pg.getPaymentDate()); //put a check for null since disbursement date was not set in testMode / dev if (ObjectUtils.isNotNull(pg.getDisbursementDate())) { pgh.setOrigDisburseDate(new Timestamp(pg.getDisbursementDate().getTime())); } pgh.setOrigAchBankRouteNbr(pg.getAchBankRoutingNbr()); pgh.setOrigDisburseNbr(pg.getDisbursementNbr()); pgh.setOrigAdviceEmail(pg.getAdviceEmailAddress()); pgh.setDisbursementType(pg.getDisbursementType()); pgh.setProcess(pg.getProcess()); glPendingTransactionService.generateReissueGeneralLedgerPendingEntry(pg); if (LOG.isDebugEnabled()) { LOG.debug("cancelReissueDisbursement() Status is '" + paymentStatus + "; delete row from AchAccountNumber table."); } AchAccountNumber achAccountNumber = pg.getAchAccountNumber(); if (ObjectUtils.isNotNull(achAccountNumber)) { this.businessObjectService.delete(achAccountNumber); pg.setAchAccountNumber(null); } // if bank functionality is not enabled or the group bank is inactive clear bank code if (!bankService.isBankSpecificationEnabled() || !pg.getBank().isActive()) { pg.setBank(null); } pg.setDisbursementDate((java.sql.Date) null); pg.setAchBankRoutingNbr(null); pg.setAchAccountType(null); pg.setPhysCampusProcessCd(null); pg.setDisbursementNbr((KualiInteger) null); pg.setAdviceEmailAddress(null); pg.setDisbursementType(null); pg.setProcess(null); pg.setProcessImmediate(false); changeStatus(pg, PdpConstants.PaymentStatusCodes.OPEN, PdpConstants.PaymentChangeCodes.CANCEL_REISSUE_DISBURSEMENT, note, user, pgh); } LOG.debug("cancelReissueDisbursement() Disbursement cancelled and reissued; exit method."); } else { if (LOG.isDebugEnabled()) { LOG.debug("cancelReissueDisbursement() Payment status is " + paymentStatus + " and disbursement date is " + paymentGroup.getDisbursementDate() + "; cannot cancel payment"); } GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_INVALID_TO_CANCEL_AND_REISSUE); return false; } } else { LOG.debug("cancelReissueDisbursement() Disbursement already cancelled and reissued; exit method."); } return true; } /** * inject * * @param dao */ public void setPaymentGroupDao(PaymentGroupDao dao) { paymentGroupDao = dao; } /** * inject * * @param dao */ public void setPaymentDetailDao(PaymentDetailDao dao) { paymentDetailDao = dao; } /** * inject * * @param service */ public void setGlPendingTransactionService(PendingTransactionService service) { glPendingTransactionService = service; } /** * inject * * @param service */ public void setMailService(MailService mailService) { this.mailService = mailService; } public void setParameterService(ParameterService parameterService) { this.parameterService = parameterService; } /** * Sets the bankService attribute value. * * @param bankService The bankService to set. */ public void setBankService(BankService bankService) { this.bankService = bankService; } /** * Sets the business object service * * @param businessObjectService */ public void setBusinessObjectService(BusinessObjectService businessObjectService) { this.businessObjectService = businessObjectService; } /** * Sets the payment group service * * @param paymentGroupService */ public void setPaymentGroupService(PaymentGroupService paymentGroupService) { this.paymentGroupService = paymentGroupService; } public void setEmailService(PdpEmailService emailService) { this.emailService = emailService; } public void setPdpAuthorizationService(PdpAuthorizationService pdpAuthorizationService) { this.pdpAuthorizationService = pdpAuthorizationService; } }