001    /**
002     * Copyright 2004-2013 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.hr.lm.balancetransfer.service;
017    
018    import java.math.BigDecimal;
019    import java.util.ArrayList;
020    import java.util.List;
021    import java.util.Map;
022    
023    import org.apache.commons.collections.CollectionUtils;
024    import org.apache.commons.lang3.StringUtils;
025    import org.kuali.hr.lm.LMConstants;
026    import org.kuali.hr.lm.accrual.AccrualCategory;
027    import org.kuali.hr.lm.balancetransfer.BalanceTransfer;
028    import org.kuali.hr.lm.leaveblock.LeaveBlock;
029    import org.kuali.hr.time.HrBusinessObject;
030    import org.kuali.hr.time.service.base.TkServiceLocator;
031    import org.kuali.hr.time.util.HrBusinessObjectMaintainableImpl;
032    import org.kuali.hr.time.util.TKContext;
033    import org.kuali.hr.time.util.TKUtils;
034    import org.kuali.rice.kew.api.document.DocumentStatus;
035    import org.kuali.rice.kew.api.exception.WorkflowException;
036    import org.kuali.rice.kns.document.MaintenanceDocument;
037    import org.kuali.rice.krad.bo.DocumentHeader;
038    import org.kuali.rice.krad.service.DocumentService;
039    import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
040    import org.kuali.rice.krad.util.ObjectUtils;
041    
042    @SuppressWarnings("deprecation")
043    public class BalanceTransferMaintainableImpl extends
044                    HrBusinessObjectMaintainableImpl {
045    
046            private static final long serialVersionUID = -789218061798169466L;
047    
048            @Override
049            public void saveBusinessObject() {
050                    // TODO Auto-generated method stub
051                    super.saveBusinessObject();
052            }
053            
054            @Override
055            public HrBusinessObject getObjectById(String id) {
056                    return TkServiceLocator.getBalanceTransferService().getBalanceTransferById(id);
057            }
058    
059    
060            @Override
061        public void doRouteStatusChange(DocumentHeader documentHeader) {
062            //ProcessDocReport pdr = new ProcessDocReport(true, "");
063            String documentId = documentHeader.getDocumentNumber();
064            BalanceTransfer balanceTransfer = (BalanceTransfer)this.getDataObject();
065            DocumentService documentService = KRADServiceLocatorWeb.getDocumentService();
066    
067            DocumentStatus newDocumentStatus = documentHeader.getWorkflowDocument().getStatus();
068            String routedByPrincipalId = documentHeader.getWorkflowDocument().getRoutedByPrincipalId();
069            if (DocumentStatus.ENROUTE.equals(newDocumentStatus)
070                    && CollectionUtils.isEmpty(balanceTransfer.getLeaveBlocks())) {
071                    // this is a balance transfer on a system scheduled time off leave block
072                    if(StringUtils.isNotEmpty(balanceTransfer.getSstoId())) {
073                            try {
074                            MaintenanceDocument md = (MaintenanceDocument)KRADServiceLocatorWeb.getDocumentService().getByDocumentHeaderId(documentId);
075                            balanceTransfer = TkServiceLocator.getBalanceTransferService().transferSsto(balanceTransfer);
076                            md.getNewMaintainableObject().setDataObject(balanceTransfer);
077                            documentService.saveDocument(md);
078                        }
079                        catch (WorkflowException e) {
080                            LOG.error("caught exception while handling doRouteStatusChange -> documentService.getByDocumentHeaderId(" + documentHeader.getDocumentNumber() + "). ", e);
081                            throw new RuntimeException("caught exception while handling doRouteStatusChange -> documentService.getByDocumentHeaderId(" + documentHeader.getDocumentNumber() + "). ", e);
082                        }   
083                    } else {
084                    //when transfer document is routed, initiate the balance transfer - creating the leave blocks
085                        try {
086                            MaintenanceDocument md = (MaintenanceDocument)KRADServiceLocatorWeb.getDocumentService().getByDocumentHeaderId(documentId);
087            
088                            balanceTransfer = TkServiceLocator.getBalanceTransferService().transfer(balanceTransfer);
089                            md.getNewMaintainableObject().setDataObject(balanceTransfer);
090                            documentService.saveDocument(md);
091                        }
092                        catch (WorkflowException e) {
093                            LOG.error("caught exception while handling doRouteStatusChange -> documentService.getByDocumentHeaderId(" + documentHeader.getDocumentNumber() + "). ", e);
094                            throw new RuntimeException("caught exception while handling doRouteStatusChange -> documentService.getByDocumentHeaderId(" + documentHeader.getDocumentNumber() + "). ", e);
095                        }
096                    }
097            } else if (DocumentStatus.DISAPPROVED.equals(newDocumentStatus)) {
098                    /**
099                     * TODO: Remove disapproval action
100                     */
101                    // this is a balance transfer on a system scheduled time off leave block
102    
103                if(StringUtils.isNotEmpty(balanceTransfer.getSstoId())) {
104                            // put two accrual service generated leave blocks back, one accrued, one usage
105                            List<LeaveBlock> lbList = buildSstoLeaveBlockList(balanceTransfer);                       
106                            TkServiceLocator.getLeaveBlockService().saveLeaveBlocks(lbList);
107                    }
108                //When transfer document is disapproved, set all leave block's request statuses to disapproved.
109                for(LeaveBlock lb : balanceTransfer.getLeaveBlocks()) {
110                    if(ObjectUtils.isNotNull(lb)) {
111                        lb.setRequestStatus(LMConstants.REQUEST_STATUS.DISAPPROVED);
112                        TkServiceLocator.getLeaveBlockService().deleteLeaveBlock(lb.getLmLeaveBlockId(), routedByPrincipalId);
113                    }
114                }
115                //update status of document and associated leave blocks.
116            } else if (DocumentStatus.FINAL.equals(newDocumentStatus)) {
117                //When transfer document moves to final, set all leave block's request statuses to approved.
118                for(LeaveBlock lb : balanceTransfer.getLeaveBlocks()) {
119                    if(ObjectUtils.isNotNull(lb)) {
120                            //TODO: What happens when an approver edits the fields in the transfer doc before approving?
121                        lb.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED);
122                        TkServiceLocator.getLeaveBlockService().updateLeaveBlock(lb, routedByPrincipalId);
123                    }
124                }
125                List<LeaveBlock> leaveBlocks = TkServiceLocator.getLeaveBlockService().getLeaveBlocksForDate(balanceTransfer.getPrincipalId(), balanceTransfer.getEffectiveDate());
126                LeaveBlock carryOverBlock = null;
127                for(LeaveBlock lb : leaveBlocks) {
128                    if(StringUtils.equals(lb.getAccrualCategory(),balanceTransfer.getFromAccrualCategory())
129                                    && StringUtils.equals(lb.getDescription(),"Max carry over adjustment")) {
130                            carryOverBlock = lb;
131                    }
132                }
133                if(carryOverBlock != null) {
134                    BigDecimal adjustment = new BigDecimal(0);
135                    if(balanceTransfer.getTransferAmount() != null)
136                            adjustment = adjustment.add(balanceTransfer.getTransferAmount().abs());
137                    if(balanceTransfer.getForfeitedAmount() != null)
138                            adjustment = adjustment.add(balanceTransfer.getForfeitedAmount().abs());
139                    BigDecimal adjustedLeaveAmount = carryOverBlock.getLeaveAmount().abs().subtract(adjustment);
140                    carryOverBlock.setLeaveAmount(adjustedLeaveAmount.negate());
141                            TkServiceLocator.getLeaveBlockService().updateLeaveBlock(carryOverBlock, routedByPrincipalId);
142                }
143            } else if (DocumentStatus.CANCELED.equals(newDocumentStatus)) {
144                //When transfer document is canceled, set all leave block's request statuses to deferred
145    
146                for(LeaveBlock lb : balanceTransfer.getLeaveBlocks()) {
147                    if(ObjectUtils.isNotNull(lb)) {
148                        lb.setRequestStatus(LMConstants.REQUEST_STATUS.DEFERRED);
149                        TkServiceLocator.getLeaveBlockService().updateLeaveBlock(lb, routedByPrincipalId);
150                    }
151                }
152            }
153        }
154    
155            private List<LeaveBlock> buildSstoLeaveBlockList(BalanceTransfer bt) {
156                    String leaveDocId = CollectionUtils.isNotEmpty(bt.getLeaveBlocks())? bt.getLeaveBlocks().get(0).getDocumentId() : "";
157                    List<LeaveBlock> lbList = new ArrayList<LeaveBlock>();
158                    AccrualCategory fromAC = TkServiceLocator.getAccrualCategoryService().getAccrualCategory(bt.getFromAccrualCategory(), bt.getEffectiveDate());
159                    
160                    LeaveBlock accruedLeaveBlock = new LeaveBlock();
161                    accruedLeaveBlock.setAccrualCategory(bt.getFromAccrualCategory());
162                    accruedLeaveBlock.setLeaveDate(bt.getEffectiveDate());
163                    accruedLeaveBlock.setPrincipalId(bt.getPrincipalId());
164                    accruedLeaveBlock.setEarnCode(fromAC.getEarnCode());
165                    accruedLeaveBlock.setDateAndTime(TKUtils.getCurrentTimestamp());
166                    accruedLeaveBlock.setAccrualGenerated(true);
167                    accruedLeaveBlock.setBlockId(0L);
168                    accruedLeaveBlock.setScheduleTimeOffId(bt.getSstoId());
169                    accruedLeaveBlock.setLeaveAmount(bt.getTransferAmount());
170                    accruedLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.ACCRUAL_SERVICE);
171                    accruedLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED);
172                    accruedLeaveBlock.setDocumentId(leaveDocId);
173                    accruedLeaveBlock.setPrincipalIdModified(TKContext.getPrincipalId());
174                    lbList.add(accruedLeaveBlock);
175                    
176                    LeaveBlock usageLeaveBlock = new LeaveBlock();
177                    usageLeaveBlock.setAccrualCategory(bt.getFromAccrualCategory());
178                    usageLeaveBlock.setLeaveDate(bt.getEffectiveDate());
179                    usageLeaveBlock.setPrincipalId(bt.getPrincipalId());
180                    usageLeaveBlock.setEarnCode(fromAC.getEarnCode());
181                    usageLeaveBlock.setDateAndTime(TKUtils.getCurrentTimestamp());
182                    usageLeaveBlock.setAccrualGenerated(true);
183                    usageLeaveBlock.setBlockId(0L);
184                    usageLeaveBlock.setScheduleTimeOffId(bt.getSstoId());
185                    usageLeaveBlock.setLeaveAmount(bt.getTransferAmount().negate());
186                    usageLeaveBlock.setLeaveBlockType(LMConstants.LEAVE_BLOCK_TYPE.ACCRUAL_SERVICE);
187                    usageLeaveBlock.setRequestStatus(LMConstants.REQUEST_STATUS.APPROVED);
188                    usageLeaveBlock.setDocumentId(leaveDocId);
189                    usageLeaveBlock.setPrincipalIdModified(TKContext.getPrincipalId());
190                    lbList.add(usageLeaveBlock);
191                    
192                    return lbList;
193            }
194    }