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