View Javadoc

1   /**
2    * Copyright 2004-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.hr.time.timeblock;
17  
18  import java.math.BigDecimal;
19  import java.sql.Time;
20  import java.sql.Timestamp;
21  import java.util.ArrayList;
22  import java.util.Date;
23  import java.util.List;
24  
25  import javax.persistence.Transient;
26  
27  import org.apache.commons.lang.builder.EqualsBuilder;
28  import org.apache.commons.lang.builder.HashCodeBuilder;
29  import org.joda.time.DateTime;
30  import org.kuali.hr.time.assignment.Assignment;
31  import org.kuali.hr.time.assignment.AssignmentDescriptionKey;
32  import org.kuali.hr.time.clocklog.ClockLog;
33  import org.kuali.hr.time.service.base.TkServiceLocator;
34  import org.kuali.hr.time.util.TkConstants;
35  import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
36  import org.kuali.rice.kim.api.identity.Person;
37  import org.kuali.rice.krad.bo.PersistableBusinessObjectBase;
38  
39  public class TimeBlock extends PersistableBusinessObjectBase implements Comparable {
40  
41      /**
42       *
43       */
44      private static final long serialVersionUID = -4164042707879641855L;
45  
46      private String tkTimeBlockId;
47      private String documentId;
48      private Long jobNumber;
49      private Long workArea;
50      private Long task;
51      private String hrJobId;
52      private String tkWorkAreaId;
53      private String tkTaskId;
54      private String earnCode;
55      private String earnCodeType;
56      private Timestamp beginTimestamp;
57      private Timestamp endTimestamp;
58  
59      @Transient
60      private java.sql.Date beginDate;
61      @Transient
62      private java.sql.Date endDate;
63      @Transient
64      private Time beginTime;
65      @Transient
66      private Time endTime;
67  
68      private Boolean clockLogCreated;
69      private BigDecimal hours = TkConstants.BIG_DECIMAL_SCALED_ZERO;
70      private BigDecimal amount = TkConstants.BIG_DECIMAL_SCALED_ZERO;
71      private String principalId;
72      private String userPrincipalId;
73      private Timestamp timestamp;
74      private String beginTimestampTimezone;
75      private String endTimestampTimezone;
76      private DateTime beginTimeDisplay;
77      private DateTime endTimeDisplay;
78      private String clockLogBeginId;
79      private String clockLogEndId;
80      private String assignmentKey;
81      private String overtimePref;
82      private boolean lunchDeleted;
83      
84      @Transient
85      private Boolean deleteable;
86      
87      @Transient
88      private Boolean overtimeEditable;
89      
90      @Transient
91      private Boolean regEarnCodeEditable;
92  
93  
94      // the two variables below are used to determine if a time block needs to be visually pushed forward / backward
95      @Transient
96      private Boolean pushBackward = false;
97  
98      private TimesheetDocumentHeader timesheetDocumentHeader;
99      private Person user;
100     
101     private List<TimeHourDetail> timeHourDetails = new ArrayList<TimeHourDetail>();
102     private List<TimeBlockHistory> timeBlockHistories = new ArrayList<TimeBlockHistory>();
103 
104     public TimeBlock() {
105     }
106 
107     public String getDocumentId() {
108         return documentId;
109     }
110 
111     public void setDocumentId(String documentId) {
112         this.documentId = documentId;
113     }
114 
115     public Long getJobNumber() {
116         return jobNumber;
117     }
118 
119     public void setJobNumber(Long jobNumber) {
120         this.jobNumber = jobNumber;
121     }
122 
123     public String getEarnCode() {
124         return earnCode;
125     }
126 
127     public void setEarnCode(String earnCode) {
128         this.earnCode = earnCode;
129     }
130 
131     public Timestamp getBeginTimestamp() {
132         return beginTimestamp;
133     }
134 
135     public void setBeginTimestamp(Timestamp beginTimestamp) {
136         this.beginTimestamp = beginTimestamp;
137     }
138 
139     public Timestamp getEndTimestamp() {
140         return endTimestamp;
141     }
142 
143     public void setEndTimestamp(Timestamp endTimestamp) {
144         this.endTimestamp = endTimestamp;
145     }
146 
147     public java.sql.Date getBeginDate() {
148         if (beginDate == null && this.getBeginTimestamp() != null) {
149             setBeginDate(new java.sql.Date(this.getBeginTimestamp().getTime()));
150         }
151         return beginDate;
152     }
153 
154     public void setBeginDate(java.sql.Date beginDate) {
155         this.beginDate = beginDate;
156     }
157 
158     public java.sql.Date getEndDate() {
159         if (endDate == null && this.getEndTimestamp() != null) {
160             setEndDate(new java.sql.Date(this.getEndTimestamp().getTime()));
161         }
162         return endDate;
163     }
164 
165     public void setEndDate(java.sql.Date endDate) {
166         this.endDate = endDate;
167     }
168 
169     public Time getBeginTime() {
170         if (beginTime == null && this.getBeginTimestamp() != null) {
171             setBeginTime(new java.sql.Time(this.getBeginTimestamp().getTime()));
172         }
173         return beginTime;
174     }
175 
176     public void setBeginTime(Time beginTime) {
177         this.beginTime = beginTime;
178     }
179 
180     public Time getEndTime() {
181         if (endTime == null && this.getEndTimestamp() != null) {
182             setEndTime(new java.sql.Time(this.getEndTimestamp().getTime()));
183         }
184         return endTime;
185     }
186 
187     public void setEndTime(Time endTime) {
188         this.endTime = endTime;
189     }
190 
191 
192     public Boolean getClockLogCreated() {
193         return clockLogCreated;
194     }
195 
196     public void setClockLogCreated(Boolean clockLogCreated) {
197         this.clockLogCreated = clockLogCreated;
198     }
199 
200     public BigDecimal getHours() {
201         return hours;
202     }
203 
204     public void setHours(BigDecimal hours) {
205         if (hours != null) {
206             this.hours = hours.setScale(TkConstants.BIG_DECIMAL_SCALE, TkConstants.BIG_DECIMAL_SCALE_ROUNDING);
207         } else {
208             this.hours = hours;
209         }
210     }
211 
212     public BigDecimal getAmount() {
213         return amount;
214     }
215 
216     public void setAmount(BigDecimal amount) {
217         if (amount != null) {
218             this.amount = amount.setScale(TkConstants.BIG_DECIMAL_SCALE, TkConstants.BIG_DECIMAL_SCALE_ROUNDING);
219         } else {
220             this.amount = amount;
221         }
222     }
223 
224     public String getUserPrincipalId() {
225         return userPrincipalId;
226     }
227 
228     public void setUserPrincipalId(String userPrincipalId) {
229         this.userPrincipalId = userPrincipalId;
230     }
231 
232     public Timestamp getTimestamp() {
233         return timestamp;
234     }
235 
236     public void setTimestamp(Timestamp timestamp) {
237         this.timestamp = timestamp;
238     }
239 
240     public String getBeginTimestampTimezone() {
241         return beginTimestampTimezone;
242     }
243 
244     public void setBeginTimestampTimezone(String beginTimestampTimezone) {
245         this.beginTimestampTimezone = beginTimestampTimezone;
246     }
247 
248     public String getEndTimestampTimezone() {
249         return endTimestampTimezone;
250     }
251 
252     public void setEndTimestampTimezone(String endTimestampTimezone) {
253         this.endTimestampTimezone = endTimestampTimezone;
254     }
255 
256     public String toCSVString() {
257         StringBuffer sb = new StringBuffer();
258         sb.append(this.beginTimestampTimezone + ",");
259         sb.append(this.earnCode + ",");
260         sb.append(this.endTimestampTimezone + ",");
261         sb.append(this.userPrincipalId + ",");
262         sb.append(this.amount + ",");
263         sb.append(this.beginTimestamp + ",");
264         sb.append(this.clockLogCreated + ",");
265         sb.append(this.endTimestamp + ",");
266         sb.append(this.hours + ",");
267         sb.append(this.jobNumber + ",");
268         sb.append(this.task + ",");
269         sb.append(this.tkTimeBlockId + ",");
270         sb.append(this.timestamp + ",");
271         sb.append(this.workArea + System.getProperty("line.separator"));
272         return sb.toString();
273     }
274 
275     public String getTkTimeBlockId() {
276         return tkTimeBlockId;
277     }
278 
279     public void setTkTimeBlockId(String tkTimeBlockId) {
280         this.tkTimeBlockId = tkTimeBlockId;
281     }
282 
283     public Long getWorkArea() {
284         return workArea;
285     }
286 
287     public void setWorkArea(Long workArea) {
288         this.workArea = workArea;
289     }
290 
291     public Long getTask() {
292         return task;
293     }
294 
295     public void setTask(Long task) {
296         this.task = task;
297     }
298 
299     public String getHrJobId() {
300         return hrJobId;
301     }
302 
303     public void setHrJobId(String hrJobId) {
304         this.hrJobId = hrJobId;
305     }
306 
307     public String getTkWorkAreaId() {
308         return tkWorkAreaId;
309     }
310 
311     public void setTkWorkAreaId(String tkWorkAreaId) {
312         this.tkWorkAreaId = tkWorkAreaId;
313     }
314 
315     public String getTkTaskId() {
316         return tkTaskId;
317     }
318 
319     public void setTkTaskId(String tkTaskId) {
320         this.tkTaskId = tkTaskId;
321     }
322 
323     public List<TimeHourDetail> getTimeHourDetails() {
324         return timeHourDetails;
325     }
326 
327     public void setTimeHourDetails(List<TimeHourDetail> timeHourDetails) {
328         this.timeHourDetails = timeHourDetails;
329     }
330 
331     public Boolean isPushBackward() {
332         return pushBackward;
333     }
334 
335     public void setPushBackward(Boolean pushBackward) {
336         this.pushBackward = pushBackward;
337     }
338 
339     /**
340      * Use this call for all GUI/Display related rendering of the BEGIN
341      * timestamp of the given time block. Timeblocks require pre-processing
342      * before there will be a non-null return value here.
343      *
344      * @return The Timeblock Begin time to display, with the Users Timezone
345      *         taken into account and applied to this DateTime object.
346      */
347     public DateTime getBeginTimeDisplay() {
348         return beginTimeDisplay;
349     }
350 
351     /**
352      * Helper to call DateTime.toDate().
353      *
354      * @return a java.util.Date representing the getBeginTimeDisplay() DateTime.
355      */
356     public Date getBeginTimeDisplayDate() {
357         return getBeginTimeDisplay().toDate();
358     }
359 
360     /*
361     *   fix timezone issues caused by JScript, for GUI use only,
362     */
363     public String getBeginTimeDisplayDateOnlyString() {
364         return this.getBeginTimeDisplay().toString(TkConstants.DT_BASIC_DATE_FORMAT);
365     }
366 
367     public String getBeginTimeDisplayTimeOnlyString() {
368         return this.getBeginTimeDisplay().toString(TkConstants.DT_BASIC_TIME_FORMAT);
369     }
370 
371     public String getEndTimeDisplayDateOnlyString() {
372         return this.getEndTimeDisplay().toString(TkConstants.DT_BASIC_DATE_FORMAT);
373     }
374 
375     public String getEndTimeDisplayTimeOnlyString() {
376         return this.getEndTimeDisplay().toString(TkConstants.DT_BASIC_TIME_FORMAT);
377     }
378 
379     /**
380      * Set this value with a DateTime that is in the current users Timezone. This
381      * should happen as a pre processing step for display purposes. Do not use these
382      * values for server-side computation.
383      *
384      * @param beginTimeDisplay
385      */
386     public void setBeginTimeDisplay(DateTime beginTimeDisplay) {
387         this.beginTimeDisplay = beginTimeDisplay;
388     }
389 
390     /**
391      * Use this call for all GUI/Display related rendering of the END
392      * timestamp of the given time block. Timeblocks require pre-processing
393      * before there will be a non-null return value here.
394      *
395      * @return The Timeblock end time to display, with the Users Timezone
396      *         taken into account and applied to this DateTime object.
397      */
398     public DateTime getEndTimeDisplay() {
399         return endTimeDisplay;
400     }
401 
402     /**
403      * Helper to call DateTime.toDate().
404      *
405      * @return a java.util.Date representing the getEndTimeDisplay() DateTime.
406      */
407     public Date getEndTimeDisplayDate() {
408         return getEndTimeDisplay().toDate();
409     }
410 
411     /**
412      * Set this value with a DateTime that is in the current users Timezone. This
413      * should happen as a pre processing step for display purposes. Do not use these
414      * values for server-side computation.
415      *
416      * @param endTimeDisplay
417      */
418     public void setEndTimeDisplay(DateTime endTimeDisplay) {
419         this.endTimeDisplay = endTimeDisplay;
420     }
421 
422     public TimesheetDocumentHeader getTimesheetDocumentHeader() {
423         if (timesheetDocumentHeader == null && this.getDocumentId() != null) {
424             setTimesheetDocumentHeader(TkServiceLocator.getTimesheetDocumentHeaderService().getDocumentHeader(this.getDocumentId()));
425         }
426         return timesheetDocumentHeader;
427     }
428 
429     public void setTimesheetDocumentHeader(
430             TimesheetDocumentHeader timesheetDocumentHeader) {
431         this.timesheetDocumentHeader = timesheetDocumentHeader;
432     }
433 
434     public List<TimeBlockHistory> getTimeBlockHistories() {
435         return timeBlockHistories;
436     }
437 
438     public void setTimeBlockHistories(List<TimeBlockHistory> timeBlockHistories) {
439         this.timeBlockHistories = timeBlockHistories;
440     }
441 
442     public String getClockLogBeginId() {
443         return clockLogBeginId;
444     }
445 
446     public void setClockLogBeginId(String clockLogBeginId) {
447         this.clockLogBeginId = clockLogBeginId;
448     }
449 
450     public String getClockLogEndId() {
451         return clockLogEndId;
452     }
453 
454     public void setClockLogEndId(String clockLogEndId) {
455         this.clockLogEndId = clockLogEndId;
456     }
457 
458     public String getAssignmentKey() {
459         if (assignmentKey == null) {
460             AssignmentDescriptionKey adk = new AssignmentDescriptionKey(this.getJobNumber().toString(), this.getWorkArea().toString(), this.getTask().toString());
461             this.setAssignmentKey(adk.toAssignmentKeyString());
462         }
463         return assignmentKey;
464     }
465 
466     public void setAssignmentKey(String assignmentDescription) {
467         this.assignmentKey = assignmentDescription;
468     }
469 
470     public String getAssignmentDescription() {
471         AssignmentDescriptionKey adk = new AssignmentDescriptionKey(this.getJobNumber().toString(), this.getWorkArea().toString(), this.getTask().toString());
472         Assignment anAssignment = TkServiceLocator.getAssignmentService().getAssignment(adk, this.getBeginDate());
473         return anAssignment == null ? this.getAssignmentKey() : anAssignment.getAssignmentDescription();
474     }
475 
476 
477     /**
478      * Word on the street is that Object.clone() is a POS. We only need some
479      * basics for comparison, so we'll implement a simple copy constructor
480      * instead.
481      * <p/>
482      * TODO: Check whether or not it matters if the History is copied, this
483      * operation needs to be as inexpensive as possible.
484      *
485      * @param b The TimeBlock to copy values from when creating this instance.
486      */
487     protected TimeBlock(TimeBlock b) {
488         // TODO : Implement "copy" constructor.
489         this.tkTimeBlockId = b.tkTimeBlockId;
490         this.documentId = b.documentId;
491         this.jobNumber = b.jobNumber;
492         this.workArea = b.workArea;
493         this.task = b.task;
494         this.hrJobId = b.hrJobId;
495         this.tkWorkAreaId = b.tkWorkAreaId;
496         this.tkTaskId = b.tkTaskId;
497         this.earnCode = b.earnCode;
498         this.beginTimestamp = new Timestamp(b.beginTimestamp.getTime());
499         this.endTimestamp = new Timestamp(b.endTimestamp.getTime());
500         this.clockLogCreated = b.clockLogCreated;
501         this.hours = b.hours;
502         this.amount = b.amount;
503         this.userPrincipalId = b.userPrincipalId;
504         this.timestamp = new Timestamp(b.timestamp.getTime());
505         this.beginTimeDisplay = b.beginTimeDisplay;
506         this.endTimeDisplay = b.endTimeDisplay;
507         this.pushBackward = b.pushBackward;
508         this.clockLogBeginId = b.clockLogBeginId;
509         this.clockLogEndId = b.clockLogEndId;
510 
511         // We just set the reference for this object, since splitting the
512         // TimeBlock would be abnormal behavior.
513         this.timesheetDocumentHeader = b.timesheetDocumentHeader;
514 
515         //private List<TimeHourDetail> timeHourDetails = new ArrayList<TimeHourDetail>();
516         for (TimeHourDetail thd : b.timeHourDetails) {
517             this.timeHourDetails.add(thd.copy());
518         }
519 
520         // TODO: For now, not copying TimeBlockHistory - The Object extends this one, which seems odd.
521         //private List<TimeBlockHistory> timeBlockHistories = new ArrayList<TimeBlockHistory>();
522     }
523 
524     /**
525      * @return A new copy of this TimeBlock.
526      */
527     public TimeBlock copy() {
528         return new TimeBlock(this);
529     }
530 
531     public String getEarnCodeType() {
532         return earnCodeType;
533     }
534 
535     public void setEarnCodeType(String earnCodeType) {
536         this.earnCodeType = earnCodeType;
537     }
538 
539     /**
540      * This is for distribute time block page to sort it by begin date/time
541      *
542      * @see java.lang.Comparable#compareTo(java.lang.Object)
543      */
544     public int compareTo(Object o) {
545         return compareTo((TimeBlock) o);
546     }
547 
548     public int compareTo(TimeBlock tb) {
549         return this.getBeginTimestamp().compareTo(tb.getBeginTimestamp());
550     }
551 
552     public Boolean getEditable() {
553         return TkServiceLocator.getTimeBlockService().isTimeBlockEditable(this);
554     }
555 
556     public String getPrincipalId() {
557         return principalId;
558     }
559 
560     public void setPrincipalId(String principalId) {
561         this.principalId = principalId;
562     }
563 
564     public String getOvertimePref() {
565         return overtimePref;
566     }
567 
568     public void setOvertimePref(String overtimePref) {
569         this.overtimePref = overtimePref;
570     }
571 
572     /* apply grace period rule to times of time block
573      * These strings are for GUI of Actual time inquiry
574     */
575     public String getActualBeginTimeString() {
576         if (this.getClockLogBeginId() != null) {
577             if (isOvernightTimeClockLog(clockLogEndId)) {
578                 return new DateTime(beginTimestamp).toString(TkConstants.DT_FULL_DATE_TIME_FORMAT);
579             } else {
580                 ClockLog cl = TkServiceLocator.getClockLogService().getClockLog(this.getClockLogBeginId());
581                 if (cl != null) {
582                     return new DateTime(cl.getTimestamp()).toString(TkConstants.DT_FULL_DATE_TIME_FORMAT);
583                 }
584             }
585 
586         }
587         return "";
588     }
589 
590     public String getActualEndTimeString() {
591         if (this.getClockLogEndId() != null) {
592             if (isOvernightTimeClockLog(clockLogEndId)) {
593                 return new DateTime(endTimestamp).toString(TkConstants.DT_FULL_DATE_TIME_FORMAT);
594             } else {
595                 ClockLog cl = TkServiceLocator.getClockLogService().getClockLog(this.getClockLogEndId());
596                 if (cl != null) {
597                     return new DateTime(cl.getTimestamp()).toString(TkConstants.DT_FULL_DATE_TIME_FORMAT);
598                 }
599             }
600 
601         }
602         return "";
603     }
604 
605     private Boolean isOvernightTimeClockLog(String clockLogId) {
606         // https://jira.kuali.org/browse/KPME-1179
607         Integer overnightTimeBlocks = TkServiceLocator.getTimeBlockService().getOvernightTimeBlocks(clockLogEndId).size();
608         if (overnightTimeBlocks >= 2) {
609             return true;
610         }
611 
612         return false;
613     }
614 
615 	public Boolean getDeleteable() {
616 		return TkServiceLocator.getPermissionsService().canDeleteTimeBlock(this);
617 	}
618 
619 	public Boolean getOvertimeEditable() {
620 		return TkServiceLocator.getPermissionsService().canEditOvertimeEarnCode(this);
621 	}
622 	
623 	public Boolean getRegEarnCodeEditable() {
624 		return TkServiceLocator.getPermissionsService().canEditRegEarnCode(this);
625 	}
626 
627     public Boolean getTimeBlockEditable(){
628         return TkServiceLocator.getPermissionsService().canEditTimeBlock(this);
629     }
630 
631     public boolean isLunchDeleted() {
632         return lunchDeleted;
633     }
634 
635     public void setLunchDeleted(boolean lunchDeleted) {
636         this.lunchDeleted = lunchDeleted;
637     }
638 
639 	public Person getUser() {
640 		return user;
641 	}
642 
643 	public void setUser(Person user) {
644 		this.user = user;
645 	}
646 	
647 	@Override
648 	public boolean equals(Object obj) {
649 		if (obj == null) { 
650 			return false;
651 		}
652 		if (obj == this) { 
653 			return true;
654 		}
655 		if (obj.getClass() != getClass()) {
656 			return false;
657 		}
658 		TimeBlock timeBlock = (TimeBlock) obj;
659 		return new EqualsBuilder()
660 			.append(jobNumber, timeBlock.jobNumber)
661 			.append(workArea, timeBlock.workArea)
662 			.append(task, timeBlock.task)
663 			.append(earnCode, timeBlock.earnCode)
664 			.append(beginTimestamp, timeBlock.beginTimestamp)
665 			.append(endTimestamp, timeBlock.endTimestamp)
666 			.append(hours, timeBlock.hours)
667 			.append(timeHourDetails, timeBlock.timeHourDetails)
668 			.isEquals();
669 	}
670 
671     @Override
672     public int hashCode() {
673     	return new HashCodeBuilder(17, 31)
674     		.append(jobNumber)
675     		.append(workArea)
676     		.append(task)
677     		.append(earnCode)
678     		.append(beginTimestamp)
679     		.append(endTimestamp)
680     		.append(hours)
681     		.append(timeHourDetails)
682     		.toHashCode();
683     }
684     
685 }