001/*
002 * Copyright 2007 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/*
017 * Created on Aug 12, 2004
018 */
019package org.kuali.ole.pdp.service.impl;
020
021import java.sql.Timestamp;
022import java.util.Date;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import org.kuali.ole.pdp.PdpConstants;
028import org.kuali.ole.pdp.PdpKeyConstants;
029import org.kuali.ole.pdp.PdpPropertyConstants;
030import org.kuali.ole.pdp.businessobject.AchAccountNumber;
031import org.kuali.ole.pdp.businessobject.PaymentChangeCode;
032import org.kuali.ole.pdp.businessobject.PaymentDetail;
033import org.kuali.ole.pdp.businessobject.PaymentGroup;
034import org.kuali.ole.pdp.businessobject.PaymentGroupHistory;
035import org.kuali.ole.pdp.businessobject.PaymentNoteText;
036import org.kuali.ole.pdp.businessobject.PaymentStatus;
037import org.kuali.ole.pdp.dataaccess.PaymentDetailDao;
038import org.kuali.ole.pdp.dataaccess.PaymentGroupDao;
039import org.kuali.ole.pdp.service.PaymentGroupService;
040import org.kuali.ole.pdp.service.PaymentMaintenanceService;
041import org.kuali.ole.pdp.service.PdpAuthorizationService;
042import org.kuali.ole.pdp.service.PdpEmailService;
043import org.kuali.ole.pdp.service.PendingTransactionService;
044import org.kuali.ole.sys.OLEConstants;
045import org.kuali.ole.sys.service.BankService;
046import org.kuali.rice.core.api.util.type.KualiInteger;
047import org.kuali.rice.coreservice.framework.parameter.ParameterService;
048import org.kuali.rice.kim.api.identity.Person;
049import org.kuali.rice.krad.bo.KualiCode;
050import org.kuali.rice.krad.service.BusinessObjectService;
051import org.kuali.rice.krad.service.MailService;
052import org.kuali.rice.krad.util.GlobalVariables;
053import org.kuali.rice.krad.util.ObjectUtils;
054import org.springframework.transaction.annotation.Transactional;
055
056/**
057 * @see org.kuali.ole.pdp.service.PaymentMaintenanceService
058 */
059@Transactional
060public class PaymentMaintenanceServiceImpl implements PaymentMaintenanceService {
061    private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PaymentMaintenanceServiceImpl.class);
062
063    private PaymentGroupDao paymentGroupDao;
064    private PaymentDetailDao paymentDetailDao;
065    private PendingTransactionService glPendingTransactionService;
066    private MailService mailService;
067    private ParameterService parameterService;
068    private BankService bankService;
069    private BusinessObjectService businessObjectService;
070    private PaymentGroupService paymentGroupService;
071    private PdpEmailService emailService;
072    private PdpAuthorizationService pdpAuthorizationService;
073
074    /**
075     * This method changes status for a payment group.
076     *
077     * @param paymentGroup the payment group
078     * @param newPaymentStatus the new payment status
079     * @param changeStatus the changed payment status
080     * @param note a note for payment status change
081     * @param user the user that changed the status
082     */
083    protected void changeStatus(PaymentGroup paymentGroup, String newPaymentStatus, String changeStatus, String note, Person user) {
084        if (LOG.isDebugEnabled()) {
085            LOG.debug("changeStatus() enter method with new status of " + newPaymentStatus);
086        }
087
088        PaymentGroupHistory paymentGroupHistory = new PaymentGroupHistory();
089        KualiCode cd = businessObjectService.findBySinglePrimaryKey(PaymentChangeCode.class, changeStatus);
090        paymentGroupHistory.setPaymentChange((PaymentChangeCode) cd);
091        paymentGroupHistory.setOrigPaymentStatus(paymentGroup.getPaymentStatus());
092        paymentGroupHistory.setChangeUser(user);
093        paymentGroupHistory.setChangeNoteText(note);
094        paymentGroupHistory.setPaymentGroup(paymentGroup);
095        paymentGroupHistory.setChangeTime(new Timestamp(new Date().getTime()));
096
097        this.businessObjectService.save(paymentGroupHistory);
098
099        KualiCode code = businessObjectService.findBySinglePrimaryKey(PaymentStatus.class, newPaymentStatus);
100        paymentGroup.setPaymentStatus((PaymentStatus) code);
101        this.businessObjectService.save(paymentGroup);
102        LOG.debug("changeStatus() Status has been changed; exit method.");
103    }
104
105    /**
106     * This method changes the state of a paymentGroup.
107     *
108     * @param paymentGroup the payment group to change the state for
109     * @param newPaymentStatus the new payment status
110     * @param changeStatus the status that is changed
111     * @param note the note entered by the user
112     * @param user the user that changed the
113     * @param paymentGroupHistory
114     */
115    protected void changeStatus(PaymentGroup paymentGroup, String newPaymentStatus, String changeStatus, String note, Person user, PaymentGroupHistory paymentGroupHistory) {
116        if (LOG.isDebugEnabled()) {
117            LOG.debug("changeStatus() enter method with new status of " + newPaymentStatus);
118        }
119
120        KualiCode cd = businessObjectService.findBySinglePrimaryKey(PaymentChangeCode.class, changeStatus);
121        paymentGroupHistory.setPaymentChange((PaymentChangeCode) cd);
122        paymentGroupHistory.setOrigPaymentStatus(paymentGroup.getPaymentStatus());
123        paymentGroupHistory.setChangeUser(user);
124        paymentGroupHistory.setChangeNoteText(note);
125        paymentGroupHistory.setPaymentGroup(paymentGroup);
126        paymentGroupHistory.setChangeTime(new Timestamp(new Date().getTime()));
127
128        this.businessObjectService.save(paymentGroupHistory);
129
130        KualiCode code = businessObjectService.findBySinglePrimaryKey(PaymentStatus.class, newPaymentStatus);
131        if (paymentGroup.getPaymentStatus() != ((PaymentStatus) code)) {
132            paymentGroup.setPaymentStatus((PaymentStatus) code);
133        }
134        this.businessObjectService.save(paymentGroup);
135
136        LOG.debug("changeStatus() Status has been changed; exit method.");
137    }
138
139    /**
140     * @see org.kuali.ole.pdp.document.service.PaymentMaintenanceService#cancelPendingPayment(java.lang.Integer, java.lang.Integer,
141     *      java.lang.String, org.kuali.rice.kim.api.identity.Person)
142     */
143    @Override
144    public boolean cancelPendingPayment(Integer paymentGroupId, Integer paymentDetailId, String note, Person user) {
145        // All actions must be performed on entire group not individual detail record
146        if (LOG.isDebugEnabled()) {
147            LOG.debug("cancelPendingPayment() Enter method to cancel pending payment with group id = " + paymentGroupId);
148            LOG.debug("cancelPendingPayment() payment detail id being cancelled = " + paymentDetailId);
149        }
150
151        PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId);
152        if (paymentGroup == null) {
153            LOG.debug("cancelPendingPayment() Pending payment not found; throw exception.");
154            GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_NOT_FOUND);
155            return false;
156        }
157
158        String paymentStatus = paymentGroup.getPaymentStatus().getCode();
159
160        if (!(PdpConstants.PaymentStatusCodes.CANCEL_PAYMENT.equals(paymentStatus))) {
161            if (LOG.isDebugEnabled()) {
162                LOG.debug("cancelPendingPayment() Payment status is " + paymentStatus + "; continue with cancel.");
163            }
164
165            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))) {
166                if (!pdpAuthorizationService.hasRemovePaymentTaxHoldPermission(user.getPrincipalId())) {
167                    LOG.warn("cancelPendingPayment() Payment status is " + paymentStatus + "; user does not have rights to cancel. This should not happen unless user is URL spoofing.");
168                    throw new RuntimeException("cancelPendingPayment() Payment status is " + paymentStatus + "; user does not have rights to cancel. This should not happen unless user is URL spoofing.");
169                }
170
171                changeStatus(paymentGroup, PdpConstants.PaymentStatusCodes.CANCEL_PAYMENT, PdpConstants.PaymentChangeCodes.CANCEL_PAYMENT_CHNG_CD, note, user);
172
173                // set primary cancel indicator for EPIC to use
174                Map primaryKeys = new HashMap();
175                primaryKeys.put(PdpPropertyConstants.PaymentDetail.PAYMENT_ID, paymentDetailId);
176
177                PaymentDetail pd = (PaymentDetail) this.businessObjectService.findByPrimaryKey(PaymentDetail.class, primaryKeys);
178                if (pd != null) {
179                    pd.setPrimaryCancelledPayment(Boolean.TRUE);
180                }
181                this.businessObjectService.save(pd);
182                this.emailService.sendCancelEmail(paymentGroup, note, user);
183
184                LOG.debug("cancelPendingPayment() Pending payment cancelled and mail was sent; exit method.");
185            }
186            else if (PdpConstants.PaymentStatusCodes.OPEN.equals(paymentStatus) || PdpConstants.PaymentStatusCodes.HELD_CD.equals(paymentStatus)) {
187                if (!pdpAuthorizationService.hasCancelPaymentPermission(user.getPrincipalId())) {
188                    LOG.warn("cancelPendingPayment() Payment status is " + paymentStatus + "; user does not have rights to cancel. This should not happen unless user is URL spoofing.");
189                    throw new RuntimeException("cancelPendingPayment() Payment status is " + paymentStatus + "; user does not have rights to cancel. This should not happen unless user is URL spoofing.");
190                }
191
192                changeStatus(paymentGroup, PdpConstants.PaymentStatusCodes.CANCEL_PAYMENT, PdpConstants.PaymentChangeCodes.CANCEL_PAYMENT_CHNG_CD, note, user);
193
194                // set primary cancel indicator for EPIC to use
195                Map primaryKeys = new HashMap();
196                primaryKeys.put(PdpPropertyConstants.PaymentDetail.PAYMENT_ID, paymentDetailId);
197
198                PaymentDetail pd = (PaymentDetail) this.businessObjectService.findByPrimaryKey(PaymentDetail.class, primaryKeys);
199                if (pd != null) {
200                    pd.setPrimaryCancelledPayment(Boolean.TRUE);
201                    PaymentNoteText payNoteText = new PaymentNoteText();
202                    payNoteText.setCustomerNoteLineNbr(new KualiInteger(pd.getNotes().size() + 1));
203                    payNoteText.setCustomerNoteText(note);
204                    pd.addNote(payNoteText);
205                }
206
207                this.businessObjectService.save(pd);
208
209                LOG.debug("cancelPendingPayment() Pending payment cancelled; exit method.");
210            }
211            else {
212                if (LOG.isDebugEnabled()) {
213                    LOG.debug("cancelPendingPayment() Payment status is " + paymentStatus + "; cannot cancel payment in this status");
214                }
215
216                GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_INVALID_STATUS_TO_CANCEL);
217                return false;
218            }
219        }
220        else {
221            LOG.debug("cancelPendingPayment() Pending payment group has already been cancelled; exit method.");
222        }
223        return true;
224    }
225
226    /**
227     * @see org.kuali.ole.pdp.document.service.PaymentMaintenanceService#holdPendingPayment(java.lang.Integer, java.lang.String,
228     *      org.kuali.rice.kim.api.identity.Person)
229     */
230    @Override
231    public boolean holdPendingPayment(Integer paymentGroupId, String note, Person user) {
232        // All actions must be performed on entire group not individual detail record
233        if (LOG.isDebugEnabled()) {
234            LOG.debug("holdPendingPayment() Enter method to hold pending payment with id = " + paymentGroupId);
235        }
236
237        if (!pdpAuthorizationService.hasHoldPaymentPermission(user.getPrincipalId())) {
238            LOG.warn("holdPendingPayment() User " + user.getPrincipalId() + " does not have rights to hold payments. This should not happen unless user is URL spoofing.");
239            throw new RuntimeException("holdPendingPayment() User " + user.getPrincipalId() + " does not have rights to hold payments. This should not happen unless user is URL spoofing.");
240        }
241
242        PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId);
243        if (paymentGroup == null) {
244            LOG.debug("holdPendingPayment() Pending payment not found; throw exception.");
245            GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_NOT_FOUND);
246            return false;
247        }
248
249        String paymentStatus = paymentGroup.getPaymentStatus().getCode();
250
251        if (!(PdpConstants.PaymentStatusCodes.HELD_CD.equals(paymentStatus))) {
252            if (PdpConstants.PaymentStatusCodes.OPEN.equals(paymentStatus)) {
253                if (LOG.isDebugEnabled()) {
254                    LOG.debug("holdPendingPayment() Payment status is " + paymentStatus + "; continue with hold.");
255                }
256
257                changeStatus(paymentGroup, PdpConstants.PaymentStatusCodes.HELD_CD, PdpConstants.PaymentChangeCodes.HOLD_CHNG_CD, note, user);
258
259                LOG.debug("holdPendingPayment() Pending payment was put on hold; exit method.");
260            }
261            else {
262                if (LOG.isDebugEnabled()) {
263                    LOG.debug("holdPendingPayment() Payment status is " + paymentStatus + "; cannot hold payment in this status");
264                }
265
266                GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_INVALID_STATUS_TO_HOLD);
267                return false;
268            }
269        }
270        else {
271            LOG.debug("holdPendingPayment() Pending payment group has already been held; exit method.");
272        }
273        return true;
274
275    }
276
277    /**
278     * @see org.kuali.ole.pdp.document.service.PaymentMaintenanceService#removeHoldPendingPayment(java.lang.Integer,
279     *      java.lang.String, org.kuali.rice.kim.api.identity.Person)
280     */
281    @Override
282    public boolean removeHoldPendingPayment(Integer paymentGroupId, String note, Person user) {
283        // All actions must be performed on entire group not individual detail record
284        if (LOG.isDebugEnabled()) {
285            LOG.debug("removeHoldPendingPayment() Enter method to hold pending payment with id = " + paymentGroupId);
286        }
287        PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId);
288        if (paymentGroup == null) {
289            LOG.debug("removeHoldPendingPayment() Payment not found; throw exception.");
290
291            GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_NOT_FOUND);
292            return false;
293        }
294
295        String paymentStatus = paymentGroup.getPaymentStatus().getCode();
296
297        if (!(PdpConstants.PaymentStatusCodes.OPEN.equals(paymentStatus))) {
298            if (LOG.isDebugEnabled()) {
299                LOG.debug("removeHoldPendingPayment() Payment status is " + paymentStatus + "; continue with hold removal.");
300            }
301
302            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))) {
303                if (!pdpAuthorizationService.hasRemovePaymentTaxHoldPermission(user.getPrincipalId())) {
304                    LOG.warn("removeHoldPendingPayment() User " + user.getPrincipalId() + " does not have rights to remove tax holds. This should not happen unless user is URL spoofing.");
305                    throw new RuntimeException("removeHoldPendingPayment() User " + user.getPrincipalId() + " does not have rights to remove tax holds. This should not happen unless user is URL spoofing.");
306                }
307
308                changeStatus(paymentGroup, PdpConstants.PaymentStatusCodes.OPEN, PdpConstants.PaymentChangeCodes.REMOVE_HOLD_CHNG_CD, note, user);
309                LOG.debug("removeHoldPendingPayment() Pending payment was taken off hold; exit method.");
310            }
311            else if (PdpConstants.PaymentStatusCodes.HELD_CD.equals(paymentStatus)) {
312                if (!pdpAuthorizationService.hasHoldPaymentPermission(user.getPrincipalId())) {
313                    LOG.warn("removeHoldPendingPayment() User " + user.getPrincipalId() + " does not have rights to hold payments. This should not happen unless user is URL spoofing.");
314                    throw new RuntimeException("removeHoldPendingPayment() User " + user.getPrincipalId() + " does not have rights to hold payments. This should not happen unless user is URL spoofing.");
315                }
316
317                changeStatus(paymentGroup, PdpConstants.PaymentStatusCodes.OPEN, PdpConstants.PaymentChangeCodes.REMOVE_HOLD_CHNG_CD, note, user);
318
319                LOG.debug("removeHoldPendingPayment() Pending payment was taken off hold; exit method.");
320            }
321            else {
322                if (LOG.isDebugEnabled()) {
323                    LOG.debug("removeHoldPendingPayment() Payment status is " + paymentStatus + "; cannot remove hold on payment in this status");
324                }
325
326                GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_PAYMENT_INVALID_STATUS_TO_REMOVE_HOLD);
327                return false;
328            }
329        }
330        else {
331            LOG.debug("removeHoldPendingPayment() Pending payment group has already been un-held; exit method.");
332        }
333        return true;
334    }
335
336    /**
337     * @see org.kuali.ole.pdp.document.service.PaymentMaintenanceService#changeImmediateFlag(java.lang.Integer, java.lang.String,
338     *      org.kuali.rice.kim.api.identity.Person)
339     */
340    @Override
341    public void changeImmediateFlag(Integer paymentGroupId, String note, Person user) {
342        // All actions must be performed on entire group not individual detail record
343        if (LOG.isDebugEnabled()) {
344            LOG.debug("changeImmediateFlag() Enter method to hold pending payment with id = " + paymentGroupId);
345        }
346
347        if (!pdpAuthorizationService.hasSetAsImmediatePayPermission(user.getPrincipalId())) {
348            LOG.warn("changeImmediateFlag() User " + user.getPrincipalId() + " does not have rights to set payments as immediate. This should not happen unless user is URL spoofing.");
349            throw new RuntimeException("changeImmediateFlag() User " + user.getPrincipalId() + " does not have rights to payments as immediate. This should not happen unless user is URL spoofing.");
350        }
351
352        PaymentGroupHistory paymentGroupHistory = new PaymentGroupHistory();
353        PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId);
354
355        paymentGroupHistory.setOrigProcessImmediate(paymentGroup.getProcessImmediate());
356
357        if (paymentGroup.getProcessImmediate().equals(Boolean.TRUE)) {
358            paymentGroup.setProcessImmediate(Boolean.FALSE);
359        }
360        else {
361            paymentGroup.setProcessImmediate(Boolean.TRUE);
362        }
363
364        changeStatus(paymentGroup, paymentGroup.getPaymentStatus().getCode(), PdpConstants.PaymentChangeCodes.CHANGE_IMMEDIATE_CHNG_CD, note, user, paymentGroupHistory);
365
366        LOG.debug("changeImmediateFlag() exit method.");
367    }
368
369    /**
370     * @see org.kuali.ole.pdp.document.service.PaymentMaintenanceService#cancelDisbursement(java.lang.Integer, java.lang.Integer,
371     *      java.lang.String, org.kuali.rice.kim.api.identity.Person)
372     */
373    @Override
374    public boolean cancelDisbursement(Integer paymentGroupId, Integer paymentDetailId, String note, Person user) {
375        // All actions must be performed on entire group not individual detail record
376        if (LOG.isDebugEnabled()) {
377            LOG.debug("cancelDisbursement() Enter method to cancel disbursement with id = " + paymentGroupId);
378        }
379
380        if (!pdpAuthorizationService.hasCancelPaymentPermission(user.getPrincipalId())) {
381            LOG.warn("cancelDisbursement() User " + user.getPrincipalId() + " does not have rights to cancel payments. This should not happen unless user is URL spoofing.");
382            throw new RuntimeException("cancelDisbursement() User " + user.getPrincipalId() + " does not have rights to cancel payments. This should not happen unless user is URL spoofing.");
383        }
384
385        PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId);
386
387        if (paymentGroup == null) {
388            LOG.debug("cancelDisbursement() Disbursement not found; throw exception.");
389            GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_NOT_FOUND);
390            return false;
391        }
392
393        // get the target PaymentGroup info
394        PaymentDetail targetPd = getPaymentDetail(paymentDetailId);
395        KualiInteger targetGroupId = targetPd.getPaymentGroupId();
396        PaymentGroup targetPg = getPaymentGroup(targetGroupId);
397        String targetDvTypeCode = targetPg.getDisbursementTypeCode();
398        String targetDvBankCode = targetPg.getBankCode();
399
400        String paymentStatus = paymentGroup.getPaymentStatus().getCode();
401
402        if (!(PdpConstants.PaymentStatusCodes.CANCEL_DISBURSEMENT.equals(paymentStatus))) {
403            if (((PdpConstants.PaymentStatusCodes.EXTRACTED.equals(paymentStatus)) && (ObjectUtils.isNotNull(paymentGroup.getDisbursementDate()))) || (PdpConstants.PaymentStatusCodes.PENDING_ACH.equals(paymentStatus))) {
404                if (LOG.isDebugEnabled()) {
405                    LOG.debug("cancelDisbursement() Payment status is " + paymentStatus + "; continue with cancel.");
406                }
407
408                List<PaymentGroup> allDisbursementPaymentGroups = this.paymentGroupService.getByDisbursementNumber(paymentGroup.getDisbursementNbr().intValue());
409
410                for (PaymentGroup element : allDisbursementPaymentGroups) {
411
412                    // should be the same DV type and the same bank
413                    if (!(element.getDisbursementTypeCode().equalsIgnoreCase(targetDvTypeCode) && element.getBankCode().equalsIgnoreCase(targetDvBankCode))) {
414                        continue;
415                    }
416
417                    PaymentGroupHistory pgh = new PaymentGroupHistory();
418
419                    if (!element.getPaymentDetails().get(0).isDisbursementActionAllowed()) {
420                        LOG.warn("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing.");
421                        throw new RuntimeException("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing.");
422                    }
423
424                    if ((ObjectUtils.isNotNull(element.getDisbursementType())) && (element.getDisbursementType().getCode().equals(PdpConstants.DisbursementTypeCodes.CHECK))) {
425                        pgh.setPmtCancelExtractStat(Boolean.FALSE);
426                    }
427
428                    changeStatus(element, PdpConstants.PaymentStatusCodes.CANCEL_DISBURSEMENT, PdpConstants.PaymentChangeCodes.CANCEL_DISBURSEMENT, note, user, pgh);
429
430                    glPendingTransactionService.generateCancellationGeneralLedgerPendingEntry(element);
431
432                    // set primary cancel indicator for EPIC to use
433                    // these payment details will be canceled when running processPdpCancelAndPaidJOb
434                    Map<String, KualiInteger> primaryKeys = new HashMap<String, KualiInteger>();
435                    primaryKeys.put(PdpPropertyConstants.PaymentDetail.PAYMENT_DETAIL_PAYMENT_GROUP_ID, element.getId());
436
437                    PaymentDetail pd = this.businessObjectService.findByPrimaryKey(PaymentDetail.class, primaryKeys);
438                    if (pd != null) {
439                        pd.setPrimaryCancelledPayment(Boolean.TRUE);
440                    }
441
442                    this.businessObjectService.save(pd);
443                }
444
445                LOG.debug("cancelDisbursement() Disbursement cancelled; exit method.");
446            }
447            else {
448                if (LOG.isDebugEnabled()) {
449                    LOG.debug("cancelDisbursement() Payment status is " + paymentStatus + " and disbursement date is " + paymentGroup.getDisbursementDate() + "; cannot cancel payment in this status");
450                }
451
452                GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_INVALID_TO_CANCEL);
453                return false;
454            }
455        }
456        else {
457            LOG.debug("cancelDisbursement() Disbursement has already been cancelled; exit method.");
458        }
459        return true;
460    }
461
462    /**
463     * @see org.kuali.ole.pdp.document.service.PaymentMaintenanceService#reissueDisbursement(java.lang.Integer,
464     *      java.lang.String, org.kuali.rice.kim.api.identity.Person)
465     */
466    @Override
467    public boolean reissueDisbursement(Integer paymentGroupId, String note, Person user) {
468        // All actions must be performed on entire group not individual detail record
469        if (LOG.isDebugEnabled()) {
470            LOG.debug("reissueDisbursement() Enter method to reissue disbursement with id = " + paymentGroupId);
471        }
472
473
474        PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId);
475        if (paymentGroup == null) {
476            LOG.debug("reissueDisbursement() Disbursement not found; throw exception.");
477            GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_NOT_FOUND);
478            return false;
479        }
480
481        String paymentStatus = paymentGroup.getPaymentStatus().getCode();
482
483        if (!(PdpConstants.PaymentStatusCodes.OPEN.equals(paymentStatus))) {
484            if (((PdpConstants.PaymentStatusCodes.CANCEL_DISBURSEMENT.equals(paymentStatus)) && (ObjectUtils.isNotNull(paymentGroup.getDisbursementDate())))) {
485                if (LOG.isDebugEnabled()) {
486                    LOG.debug("reissueDisbursement() Payment status is " + paymentStatus + "; continue with reissue.");
487                }
488
489                List<PaymentGroup> allDisbursementPaymentGroups = this.paymentGroupService.getByDisbursementNumber(paymentGroup.getDisbursementNbr().intValue());
490
491                for (PaymentGroup pg : allDisbursementPaymentGroups) {
492                    PaymentGroupHistory pgh = new PaymentGroupHistory();
493
494                    if (!pg.getPaymentDetails().get(0).isDisbursementActionAllowed()) {
495                        LOG.warn("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing.");
496                        throw new RuntimeException("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing.");
497                    }
498
499
500                    pgh.setOrigProcessImmediate(pg.getProcessImmediate());
501                    pgh.setOrigPmtSpecHandling(pg.getPymtSpecialHandling());
502                    pgh.setBank(pg.getBank());
503                    pgh.setOrigPaymentDate(pg.getPaymentDate());
504                    //put a check for null since disbursement date was not set in testMode / dev
505                    if (ObjectUtils.isNotNull(pg.getDisbursementDate())) {
506                        pgh.setOrigDisburseDate(new Timestamp(pg.getDisbursementDate().getTime()));
507                    }
508                    pgh.setOrigAchBankRouteNbr(pg.getAchBankRoutingNbr());
509                    pgh.setOrigDisburseNbr(pg.getDisbursementNbr());
510                    pgh.setOrigAdviceEmail(pg.getAdviceEmailAddress());
511                    pgh.setDisbursementType(pg.getDisbursementType());
512                    pgh.setProcess(pg.getProcess());
513
514                   // glPendingTransactionService.generateReissueGeneralLedgerPendingEntry(pg);
515
516                    if (LOG.isDebugEnabled()) {
517                        LOG.debug("cancelReissueDisbursement() Status is '" + paymentStatus + "; delete row from AchAccountNumber table.");
518                    }
519
520                    AchAccountNumber achAccountNumber = pg.getAchAccountNumber();
521
522                    if (ObjectUtils.isNotNull(achAccountNumber)) {
523                        this.businessObjectService.delete(achAccountNumber);
524                        pg.setAchAccountNumber(null);
525                    }
526
527                    // if bank functionality is not enabled or the group bank is inactive clear bank code
528                    if (!bankService.isBankSpecificationEnabled() || !pg.getBank().isActive()) {
529                        pg.setBank(null);
530                    }
531
532                    pg.setDisbursementDate((java.sql.Date) null);
533                    pg.setAchBankRoutingNbr(null);
534                    pg.setAchAccountType(null);
535                    pg.setPhysCampusProcessCd(null);
536                    pg.setDisbursementNbr((KualiInteger) null);
537                    pg.setAdviceEmailAddress(null);
538                    pg.setDisbursementType(null);
539                    pg.setProcess(null);
540                    pg.setProcessImmediate(false);
541                    changeStatus(pg, PdpConstants.PaymentStatusCodes.OPEN, PdpConstants.PaymentChangeCodes.REISSUE_DISBURSEMENT, note, user, pgh);
542                }
543
544                LOG.debug("reissueDisbursement() Disbursement reissued; exit method.");
545            }
546            else {
547                if (LOG.isDebugEnabled()) {
548                    LOG.debug("cancelReissueDisbursement() Payment status is " + paymentStatus + " and disbursement date is " + paymentGroup.getDisbursementDate() + "; cannot cancel payment");
549                }
550
551                GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_INVALID_TO_CANCEL_AND_REISSUE);
552                return false;
553            }
554        }
555        else {
556            LOG.debug("cancelReissueDisbursement() Disbursement already cancelled and reissued; exit method.");
557        }
558        return true;
559    }
560
561    /**
562     * @see org.kuali.ole.pdp.document.service.PaymentMaintenanceService#cancelReissueDisbursement(java.lang.Integer,
563     *      java.lang.String, org.kuali.rice.kim.api.identity.Person)
564     */
565    @Override
566    public boolean cancelReissueDisbursement(Integer paymentGroupId, String note, Person user) {
567        // All actions must be performed on entire group not individual detail record
568        if (LOG.isDebugEnabled()) {
569            LOG.debug("cancelReissueDisbursement() Enter method to cancel disbursement with id = " + paymentGroupId);
570        }
571
572        if (!pdpAuthorizationService.hasCancelPaymentPermission(user.getPrincipalId())) {
573            LOG.warn("cancelReissueDisbursement() User " + user.getPrincipalId() + " does not have rights to cancel payments. This should not happen unless user is URL spoofing.");
574            throw new RuntimeException("cancelReissueDisbursement() User " + user.getPrincipalId() + " does not have rights to cancel payments. This should not happen unless user is URL spoofing.");
575        }
576
577        PaymentGroup paymentGroup = this.paymentGroupService.get(paymentGroupId);
578        if (paymentGroup == null) {
579            LOG.debug("cancelReissueDisbursement() Disbursement not found; throw exception.");
580            GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_NOT_FOUND);
581            return false;
582        }
583
584        String paymentStatus = paymentGroup.getPaymentStatus().getCode();
585
586        if (!(PdpConstants.PaymentStatusCodes.OPEN.equals(paymentStatus))) {
587            if (((PdpConstants.PaymentStatusCodes.EXTRACTED.equals(paymentStatus)) && (ObjectUtils.isNotNull(paymentGroup.getDisbursementDate()))) || (PdpConstants.PaymentStatusCodes.PENDING_ACH.equals(paymentStatus))) {
588                if (LOG.isDebugEnabled()) {
589                    LOG.debug("cancelReissueDisbursement() Payment status is " + paymentStatus + "; continue with cancel.");
590                }
591
592                List<PaymentGroup> allDisbursementPaymentGroups = this.paymentGroupService.getByDisbursementNumber(paymentGroup.getDisbursementNbr().intValue());
593
594                for (PaymentGroup pg : allDisbursementPaymentGroups) {
595                    PaymentGroupHistory pgh = new PaymentGroupHistory();
596
597                    if (!pg.getPaymentDetails().get(0).isDisbursementActionAllowed()) {
598                        LOG.warn("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing.");
599                        throw new RuntimeException("cancelDisbursement() Payment does not allow disbursement action. This should not happen unless user is URL spoofing.");
600                    }
601
602                    if ((ObjectUtils.isNotNull(pg.getDisbursementType())) && (pg.getDisbursementType().getCode().equals(PdpConstants.DisbursementTypeCodes.CHECK))) {
603                        pgh.setPmtCancelExtractStat(Boolean.FALSE);
604                    }
605
606                    pgh.setOrigProcessImmediate(pg.getProcessImmediate());
607                    pgh.setOrigPmtSpecHandling(pg.getPymtSpecialHandling());
608                    pgh.setBank(pg.getBank());
609                    pgh.setOrigPaymentDate(pg.getPaymentDate());
610                    //put a check for null since disbursement date was not set in testMode / dev
611                    if (ObjectUtils.isNotNull(pg.getDisbursementDate())) {
612                        pgh.setOrigDisburseDate(new Timestamp(pg.getDisbursementDate().getTime()));
613                    }
614                    pgh.setOrigAchBankRouteNbr(pg.getAchBankRoutingNbr());
615                    pgh.setOrigDisburseNbr(pg.getDisbursementNbr());
616                    pgh.setOrigAdviceEmail(pg.getAdviceEmailAddress());
617                    pgh.setDisbursementType(pg.getDisbursementType());
618                    pgh.setProcess(pg.getProcess());
619
620                    glPendingTransactionService.generateReissueGeneralLedgerPendingEntry(pg);
621
622                    if (LOG.isDebugEnabled()) {
623                        LOG.debug("cancelReissueDisbursement() Status is '" + paymentStatus + "; delete row from AchAccountNumber table.");
624                    }
625
626                    AchAccountNumber achAccountNumber = pg.getAchAccountNumber();
627
628                    if (ObjectUtils.isNotNull(achAccountNumber)) {
629                        this.businessObjectService.delete(achAccountNumber);
630                        pg.setAchAccountNumber(null);
631                    }
632
633                    // if bank functionality is not enabled or the group bank is inactive clear bank code
634                    if (!bankService.isBankSpecificationEnabled() || !pg.getBank().isActive()) {
635                        pg.setBank(null);
636                    }
637
638                    pg.setDisbursementDate((java.sql.Date) null);
639                    pg.setAchBankRoutingNbr(null);
640                    pg.setAchAccountType(null);
641                    pg.setPhysCampusProcessCd(null);
642                    pg.setDisbursementNbr((KualiInteger) null);
643                    pg.setAdviceEmailAddress(null);
644                    pg.setDisbursementType(null);
645                    pg.setProcess(null);
646                    pg.setProcessImmediate(false);
647
648                    changeStatus(pg, PdpConstants.PaymentStatusCodes.OPEN, PdpConstants.PaymentChangeCodes.CANCEL_REISSUE_DISBURSEMENT, note, user, pgh);
649                }
650
651                LOG.debug("cancelReissueDisbursement() Disbursement cancelled and reissued; exit method.");
652            }
653            else {
654                if (LOG.isDebugEnabled()) {
655                    LOG.debug("cancelReissueDisbursement() Payment status is " + paymentStatus + " and disbursement date is " + paymentGroup.getDisbursementDate() + "; cannot cancel payment");
656                }
657
658                GlobalVariables.getMessageMap().putError(OLEConstants.GLOBAL_ERRORS, PdpKeyConstants.PaymentDetail.ErrorMessages.ERROR_DISBURSEMENT_INVALID_TO_CANCEL_AND_REISSUE);
659                return false;
660            }
661        }
662        else {
663            LOG.debug("cancelReissueDisbursement() Disbursement already cancelled and reissued; exit method.");
664        }
665        return true;
666    }
667
668    /**
669     * Gets DisbursementVoucher by the primary key
670     *
671     * @param paymentDetailId
672     * @return
673     */
674    protected PaymentDetail getPaymentDetail(Integer paymentDetailId) {
675        Map<String, Integer> primaryKeys = new HashMap<String, Integer>();
676        primaryKeys.put(PdpPropertyConstants.PaymentDetail.PAYMENT_ID, paymentDetailId);
677
678        return this.businessObjectService.findByPrimaryKey(PaymentDetail.class, primaryKeys);
679    }
680
681    /**
682     * Gets PaymentGroup by the primary key
683     *
684     * @param paymentDetailId
685     * @return
686     */
687    protected PaymentGroup getPaymentGroup(KualiInteger paymentGroupId) {
688        Map<String, KualiInteger> primaryKeys = new HashMap<String, KualiInteger>();
689        primaryKeys.put(PdpPropertyConstants.PaymentGroup.PAYMENT_GROUP_ID, paymentGroupId);
690
691        return this.businessObjectService.findByPrimaryKey(PaymentGroup.class, primaryKeys);
692    }
693
694    /**
695     * inject
696     *
697     * @param dao
698     */
699    public void setPaymentGroupDao(PaymentGroupDao dao) {
700        paymentGroupDao = dao;
701    }
702
703    /**
704     * inject
705     *
706     * @param dao
707     */
708    public void setPaymentDetailDao(PaymentDetailDao dao) {
709        paymentDetailDao = dao;
710    }
711
712    /**
713     * inject
714     *
715     * @param service
716     */
717    public void setGlPendingTransactionService(PendingTransactionService service) {
718        glPendingTransactionService = service;
719    }
720
721    /**
722     * inject
723     *
724     * @param service
725     */
726    public void setMailService(MailService mailService) {
727        this.mailService = mailService;
728    }
729
730    public void setParameterService(ParameterService parameterService) {
731        this.parameterService = parameterService;
732    }
733
734    /**
735     * Sets the bankService attribute value.
736     *
737     * @param bankService The bankService to set.
738     */
739    public void setBankService(BankService bankService) {
740        this.bankService = bankService;
741    }
742
743    /**
744     * Sets the business object service
745     *
746     * @param businessObjectService
747     */
748    public void setBusinessObjectService(BusinessObjectService businessObjectService) {
749        this.businessObjectService = businessObjectService;
750    }
751
752    /**
753     * Sets the payment group service
754     *
755     * @param paymentGroupService
756     */
757    public void setPaymentGroupService(PaymentGroupService paymentGroupService) {
758        this.paymentGroupService = paymentGroupService;
759    }
760
761    public void setEmailService(PdpEmailService emailService) {
762        this.emailService = emailService;
763    }
764
765    public void setPdpAuthorizationService(PdpAuthorizationService pdpAuthorizationService) {
766        this.pdpAuthorizationService = pdpAuthorizationService;
767    }
768}