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.time.clocklog.service;
017    
018    import java.math.BigDecimal;
019    import java.sql.Timestamp;
020    import java.util.ArrayList;
021    import java.util.HashSet;
022    import java.util.List;
023    import java.util.Set;
024    
025    import org.apache.commons.collections.CollectionUtils;
026    import org.apache.commons.lang.StringUtils;
027    import org.kuali.hr.time.assignment.Assignment;
028    import org.kuali.hr.time.calendar.CalendarEntries;
029    import org.kuali.hr.time.clocklog.ClockLog;
030    import org.kuali.hr.time.clocklog.dao.ClockLogDao;
031    import org.kuali.hr.time.service.base.TkServiceLocator;
032    import org.kuali.hr.time.timeblock.TimeBlock;
033    import org.kuali.hr.time.timesheet.TimesheetDocument;
034    import org.kuali.hr.time.util.TKContext;
035    import org.kuali.hr.time.util.TkConstants;
036    import org.kuali.rice.krad.service.KRADServiceLocator;
037    import org.kuali.rice.krad.util.KRADConstants;
038    
039    public class ClockLogServiceImpl implements ClockLogService {
040    
041        private ClockLogDao clockLogDao;
042    
043        public ClockLogServiceImpl() {
044        }
045    
046        public void saveClockLog(ClockLog clockLog) {
047            clockLogDao.saveOrUpdate(clockLog);
048        }
049    
050        @Override
051        public ClockLog processClockLog(Timestamp clockTimeStamp, Assignment assignment,CalendarEntries pe, String ip, java.sql.Date asOfDate, TimesheetDocument td, String clockAction, String principalId) {
052            return processClockLog(clockTimeStamp, assignment, pe, ip, asOfDate, td, clockAction, principalId, TKContext.getPrincipalId());
053        }
054    
055        @Override
056        public ClockLog processClockLog(Timestamp clockTimeStamp, Assignment assignment,CalendarEntries pe, String ip, java.sql.Date asOfDate, TimesheetDocument td, String clockAction, String principalId, String userPrincipalId) {
057            // process rules
058            Timestamp roundedClockTimestamp = TkServiceLocator.getGracePeriodService().processGracePeriodRule(clockTimeStamp, new java.sql.Date(pe.getBeginPeriodDateTime().getTime()));
059    
060            ClockLog clockLog = buildClockLog(roundedClockTimestamp, new Timestamp(System.currentTimeMillis()), assignment, td, clockAction, ip, userPrincipalId);
061            TkServiceLocator.getClockLocationRuleService().processClockLocationRule(clockLog, asOfDate);
062    
063            // If the clock action is clock out or lunch out, create a time block besides the clock log
064            if (StringUtils.equals(clockAction, TkConstants.CLOCK_OUT) || StringUtils.equals(clockAction, TkConstants.LUNCH_OUT)) {
065                processTimeBlock(clockLog, assignment, pe, td, clockAction, principalId, userPrincipalId);
066            } else {
067                //Save current clock log to get id for timeblock building
068                KRADServiceLocator.getBusinessObjectService().save(clockLog);
069            }
070    
071            return clockLog;
072        }
073    
074        private void processTimeBlock(ClockLog clockLog, Assignment assignment, CalendarEntries pe, TimesheetDocument td, String clockAction, String principalId, String userPrincipalId) {
075            ClockLog lastLog = null;
076            Timestamp lastClockTimestamp = null;
077            String beginClockLogId = null;
078            String endClockLogId = null;
079    
080            if (StringUtils.equals(clockAction, TkConstants.LUNCH_OUT)) {
081                lastLog = TkServiceLocator.getClockLogService().getLastClockLog(principalId, TkConstants.CLOCK_IN);
082            } else if (StringUtils.equals(clockAction, TkConstants.CLOCK_OUT)) {
083                lastLog = TkServiceLocator.getClockLogService().getLastClockLog(principalId);
084            }
085            if (lastLog != null) {
086                lastClockTimestamp = lastLog.getClockTimestamp();
087                beginClockLogId = lastLog.getTkClockLogId();
088            }
089            //Save current clock log to get id for timeblock building
090            KRADServiceLocator.getBusinessObjectService().save(clockLog);
091            endClockLogId = clockLog.getTkClockLogId();
092    
093            long beginTime = lastClockTimestamp.getTime();
094            Timestamp beginTimestamp = new Timestamp(beginTime);
095            Timestamp endTimestamp = clockLog.getClockTimestamp();
096    
097            // New Time Blocks, pointer reference
098            List<TimeBlock> newTimeBlocks = td.getTimeBlocks();
099            List<TimeBlock> referenceTimeBlocks = new ArrayList<TimeBlock>(td.getTimeBlocks().size());
100            for (TimeBlock tb : td.getTimeBlocks()) {
101                referenceTimeBlocks.add(tb.copy());
102            }
103    
104            // Add TimeBlocks after we store our reference object!
105            List<TimeBlock> aList = TkServiceLocator.getTimeBlockService().buildTimeBlocks(assignment, assignment.getJob().getPayTypeObj().getRegEarnCode(), td, beginTimestamp, endTimestamp, BigDecimal.ZERO, BigDecimal.ZERO, true, false, userPrincipalId);
106            for (TimeBlock tb : aList) {
107                tb.setClockLogBeginId(beginClockLogId);
108                tb.setClockLogEndId(endClockLogId);
109            }
110            newTimeBlocks.addAll(aList);
111    
112            //reset time block
113            TkServiceLocator.getTimesheetService().resetTimeBlock(newTimeBlocks);
114    
115            //apply any rules for this action
116            TkServiceLocator.getTkRuleControllerService().applyRules(TkConstants.ACTIONS.CLOCK_OUT, newTimeBlocks, pe, td, principalId);
117    
118            //call persist method that only saves added/deleted/changed timeblocks
119            TkServiceLocator.getTimeBlockService().saveTimeBlocks(referenceTimeBlocks, newTimeBlocks, userPrincipalId);
120        }
121    
122        @Override
123        public ClockLog buildClockLog(Timestamp clockTimestamp, Timestamp originalTimestamp, Assignment assignment, TimesheetDocument timesheetDocument, String clockAction, String ip) {
124            return buildClockLog(clockTimestamp, originalTimestamp, assignment, timesheetDocument, clockAction, ip, TKContext.getPrincipalId());
125        }
126    
127        @Override
128        public ClockLog buildClockLog(Timestamp clockTimestamp, Timestamp originalTimestamp, Assignment assignment, TimesheetDocument timesheetDocument, String clockAction, String ip, String userPrincipalId) {
129            String principalId = timesheetDocument.getPrincipalId();
130    
131            ClockLog clockLog = new ClockLog();
132            clockLog.setPrincipalId(principalId);
133            //        AssignmentDescriptionKey assignmentDesc = TkServiceLocator.getAssignmentService().getAssignmentDescriptionKey(selectedAssign);
134            //        Assignment assignment = TkServiceLocator.getAssignmentService().getAssignment(timesheetDocument, selectedAssign);
135            clockLog.setJob(timesheetDocument.getJob(assignment.getJobNumber()));
136            clockLog.setJobNumber(assignment.getJobNumber());
137            clockLog.setWorkArea(assignment.getWorkArea());
138            clockLog.setTask(assignment.getTask());
139            clockLog.setClockTimestampTimezone(TkServiceLocator.getTimezoneService().getUserTimezoneWithFallback().getID());
140            clockLog.setClockTimestamp(clockTimestamp);
141            clockLog.setClockAction(clockAction);
142            clockLog.setIpAddress(ip);
143            clockLog.setUserPrincipalId(userPrincipalId);
144            // timestamp should be the original time without Grace Period rule applied
145            clockLog.setTimestamp(originalTimestamp);
146    
147            return clockLog;
148        }
149    
150        public void setClockLogDao(ClockLogDao clockLogDao) {
151            this.clockLogDao = clockLogDao;
152        }
153    
154        public ClockLog getLastClockLog(String principalId) {
155            return clockLogDao.getLastClockLog(principalId);
156        }
157    
158        public ClockLog getLastClockLog(String principalId, String clockAction) {
159            return clockLogDao.getLastClockLog(principalId, clockAction);
160        }
161    
162        public ClockLog getLastClockLog(String principalId, String jobNumber, String workArea, String task, CalendarEntries calendarEntry) {
163            return clockLogDao.getLastClockLog(principalId, jobNumber, workArea, task, calendarEntry);
164        }
165    
166        @Override
167        public ClockLog getClockLog(String tkClockLogId) {
168            return clockLogDao.getClockLog(tkClockLogId);
169        }
170    
171        public List<String> getUnapprovedIPWarning(List<TimeBlock> timeBlocks) {
172                     List<String> warningMessages = new ArrayList<String>();
173                     if (CollectionUtils.isNotEmpty(timeBlocks)) {
174                         Set<String> aSet = new HashSet<String>();
175                         for(TimeBlock tb : timeBlocks) {
176                             if(tb.getClockLogCreated()) {
177                                     if(StringUtils.isNotEmpty(tb.getClockLogBeginId())){
178                                             ClockLog cl = TkServiceLocator.getClockLogService().getClockLog(tb.getClockLogBeginId());
179                                             if(cl.getUnapprovedIP()) {
180                                                     aSet.add(buildUnapprovedIPWarning(cl));
181                                             }
182                                     }
183                                     if(StringUtils.isNotEmpty(tb.getClockLogEndId())){
184                                             ClockLog cl = TkServiceLocator.getClockLogService().getClockLog(tb.getClockLogEndId());
185                                             if(cl.getUnapprovedIP()) {
186                                                     aSet.add(buildUnapprovedIPWarning(cl));
187                                             }
188                                     }              
189                             }
190                         }
191                         warningMessages.addAll(aSet);
192                    }
193                    
194                    return warningMessages;
195        }
196    
197            public String buildUnapprovedIPWarning(ClockLog cl) {
198                    String warning = "Warning: Action '" + TkConstants.CLOCK_ACTION_STRINGS.get(cl.getClockAction()) + "' taken at " 
199                            + cl.getClockTimestamp() + " was from an unapproved IP address - " + cl.getIpAddress();
200                    return warning;
201            }
202    
203    }