Zeiterfassung: Bei Zeitanzeige auch Varianten mit Datum und Dauer berücksichtigen
[kivitendo-erp.git] / SL / DB / TimeRecording.pm
1 # This file has been auto-generated only because it didn't exist.
2 # Feel free to modify it at will; it will not be overwritten automatically.
3
4 package SL::DB::TimeRecording;
5
6 use strict;
7
8 use SL::Locale::String qw(t8);
9
10 use SL::DB::Helper::AttrDuration;
11 use SL::DB::Helper::AttrHTML;
12
13 use SL::DB::MetaSetup::TimeRecording;
14 use SL::DB::Manager::TimeRecording;
15
16 __PACKAGE__->meta->initialize;
17
18 __PACKAGE__->attr_duration_minutes(qw(duration));
19
20 __PACKAGE__->attr_html('description');
21
22 __PACKAGE__->before_save('_before_save_check_valid');
23
24 sub _before_save_check_valid {
25   my ($self) = @_;
26
27   my @errors = $self->validate;
28   return (scalar @errors == 0);
29 }
30
31 sub validate {
32   my ($self) = @_;
33
34   my @errors;
35
36   push @errors, t8('Customer must not be empty.')                              if !$self->customer_id;
37   push @errors, t8('Staff member must not be empty.')                          if !$self->staff_member_id;
38   push @errors, t8('Employee must not be empty.')                              if !$self->employee_id;
39   push @errors, t8('Description must not be empty.')                           if !$self->description;
40   push @errors, t8('Start time must be earlier than end time.')                if $self->is_time_in_wrong_order;
41
42   my $conflict = $self->is_time_overlapping;
43   push @errors, t8('Entry overlaps with "#1".', $conflict->displayable_times)  if $conflict;
44
45   return @errors;
46 }
47
48 sub is_time_overlapping {
49   my ($self) = @_;
50
51   # Do not allow overlapping time periods.
52   # Start time can be equal to another end time
53   # (an end time can be equal to another start time)
54
55   # We cannot check if no staff member is given.
56   return if !$self->staff_member_id;
57
58   # If no start time and no end time are given, there is no overlapping.
59   return if !($self->start_time || $self->end_time);
60
61   my $conflicting;
62
63   # Start time or end time can be undefined.
64   if (!$self->start_time) {
65     $conflicting = SL::DB::Manager::TimeRecording->get_all(where  => [ and => [ '!id'           => $self->id,
66                                                                                 staff_member_id => $self->staff_member_id,
67                                                                                 start_time      => {lt => $self->end_time},
68                                                                                 end_time        => {ge => $self->end_time} ] ],
69                                                            sort_by => 'start_time DESC',
70                                                            limit   => 1);
71   } elsif (!$self->end_time) {
72     $conflicting = SL::DB::Manager::TimeRecording->get_all(where  => [ and => [ '!id'           => $self->id,
73                                                                                 staff_member_id => $self->staff_member_id,
74                                                                                 or              => [ and => [start_time => {le => $self->start_time},
75                                                                                                              end_time   => {gt => $self->start_time} ],
76                                                                                                      start_time => $self->start_time,
77                                                                                 ],
78                                                                        ],
79                                                            ],
80                                                            sort_by => 'start_time DESC',
81                                                            limit   => 1);
82   } else {
83     $conflicting = SL::DB::Manager::TimeRecording->get_all(where  => [ and => [ '!id'           => $self->id,
84                                                                                 staff_member_id => $self->staff_member_id,
85                                                                                 or              => [ and => [ start_time => {lt => $self->end_time},
86                                                                                                               end_time   => {gt => $self->start_time} ] ,
87                                                                                                      or  => [ start_time => $self->start_time,
88                                                                                                               end_time   => $self->end_time, ],
89                                                                                 ]
90                                                                        ]
91                                                            ],
92                                                            sort_by => 'start_time DESC',
93                                                            limit   => 1);
94   }
95
96   return $conflicting->[0] if @$conflicting;
97   return;
98 }
99
100 sub is_time_in_wrong_order {
101   my ($self) = @_;
102
103   if ($self->start_time && $self->end_time
104       && $self->start_time >= $self->end_time) {
105     return 1;
106   }
107
108   return;
109 }
110
111 sub is_duration_used {
112   return !$_[0]->start_time;
113 }
114
115 sub displayable_times {
116   my ($self) = @_;
117
118   my $text;
119
120   if ($self->is_duration_used) {
121     $text = $self->date_as_date . ': ' . ($self->duration_as_duration_string || '--:--');
122
123   } else {
124     # placeholder
125     my $ph =  $::locale->format_date_object(DateTime->new(year => 1111, month => 11, day => 11, hour => 11, minute => 11), precision => 'minute');
126     $ph    =~ s{1}{-}g;
127     $text  =  ($self->start_time_as_timestamp||$ph) . ' - ' . ($self->end_time_as_timestamp||$ph);
128   }
129
130   return $text;
131 }
132
133 1;