AttrDuration-Helfer
[kivitendo-erp.git] / SL / DB / Helper / AttrDuration.pm
1 package SL::DB::Helper::AttrDuration;
2
3 use strict;
4
5 use parent qw(Exporter);
6 our @EXPORT = qw(attr_duration);
7
8 use Carp;
9
10 sub attr_duration {
11   my ($package, @attributes) = @_;
12
13   _make($package, $_) for @attributes;
14 }
15
16 sub _make {
17   my ($package, $attribute) = @_;
18
19   no strict 'refs';
20
21   *{ $package . '::' . $attribute . '_as_hours' } = sub {
22     my ($self, $value) = @_;
23
24     $self->$attribute(int($value) + ($self->$attribute - int($self->$attribute))) if @_ > 1;
25     return int($self->$attribute // 0);
26   };
27
28   *{ $package . '::' . $attribute . '_as_minutes' } = sub {
29     my ($self, $value) = @_;
30
31     $self->$attribute(int($self->$attribute) * 1.0 + ($value // 0) / 60.0) if @_ > 1;
32     return int(($self->$attribute // 0) * 60.0 + 0.5) % 60;
33   };
34
35   *{ $package . '::' . $attribute . '_as_duration_string' } = sub {
36     my ($self, $value) = @_;
37
38     $self->$attribute(defined($value) ? $::form->parse_amount(\%::myconfig, $value) * 1 : undef) if @_ > 1;
39     return defined($self->$attribute) ? $::form->format_amount(\%::myconfig, $self->$attribute // 0, 2) : undef;
40   };
41
42   *{ $package . '::' . $attribute . '_as_man_days' } = sub {
43     my ($self, $value) = @_;
44
45     if (@_ > 1) {
46       return undef if !defined $value;
47       $self->$attribute($value);
48     }
49     $value = $self->$attribute // 0;
50     return $value >= 8.0 ? $value / 8.0 : $value;
51   };
52
53   *{ $package . '::' . $attribute . '_as_man_days_unit' } = sub {
54     my ($self, $unit) = @_;
55
56     if (@_ > 1) {
57       return undef if !defined $unit;
58       croak "Unknown unit '${unit}'"                    if $unit !~ m/^(?:h|hour|man_day)$/;
59       $self->$attribute(($self->$attribute // 0) * 8.0) if $unit eq 'man_day';
60     }
61
62     return ($self->$attribute // 0) >= 8.0 ? 'man_day' : 'h'
63   };
64
65   *{ $package . '::' . $attribute . '_as_man_days_string' } = sub {
66     my ($self, $value) = @_;
67     my $method         = "${attribute}_as_man_days";
68
69     if (@_ > 1) {
70       return undef if !defined $value;
71       $self->$method($::form->parse_amount(\%::myconfig, $value));
72     }
73
74     return $::form->format_amount(\%::myconfig, $self->$method // 0, 2);
75   };
76 }
77
78 1;
79 __END__
80
81 =pod
82
83 =encoding utf8
84
85 =head1 NAME
86
87 SL::DB::Helper::AttrDuration - Attribute helper for duration stored in
88 numeric columns
89
90 =head1 SYNOPSIS
91
92   # In a Rose model:
93   use SL::DB::Helper::AttrDuration;
94   __PACKAGE__->attr_duration('time_estimation');
95
96   # Read access:
97   print "Minutes: " . $obj->time_estimation_as_minutes . " hours: " . $obj->time_estimation_as_hours . "\n";
98
99   # Use formatted strings in input fields in templates:
100   <form method="post">
101     ...
102     [% L.input_tag('time_estimation_as_duration_string', SELF.obj.time_estimation_as_duration_string) %]
103   </form>
104
105 =head1 OVERVIEW
106
107 This is a helper for columns that store a duration as a numeric or
108 floating point number representing a number of hours. So the value
109 1.75 would stand for "1 hour, 45 minutes".
110
111 The helper methods created are:
112
113 =over 4
114
115 =item C<attribute_as_minutes [$new_value]>
116
117 Access only the minutes. Return values are in the range [0 - 59].
118
119 =item C<attribute_as_hours [$new_value]>
120
121 Access only the hours. Returns an integer value.
122
123 =item C<attribute_as_duration_string [$new_value]>
124
125 Access the full value as a formatted string according to the user's
126 locale settings.
127
128 =item C<attribute_as_man_days [$new_value]>
129
130 Access the attribute as a number of man days which are assumed to be 8
131 hours long. If the underlying attribute is less than 8 then the value
132 itself will be returned. Otherwise the value divided by 8 is returned.
133
134 If used as a setter then the underlying attribute is simply set to
135  C<$new_value>. Intentional use is to set the man days first and the
136  unit later, e.g.
137
138   $obj->attribute_as_man_days($::form->{attribute_as_man_days});
139   $obj->attribute_as_man_days_unit($::form->{attribute_as_man_days_unit});
140
141 Note that L<SL::DB::Object/assign_attributes> is aware of this and
142 handles this case correctly.
143
144 =item C<attribute_as_man_days_unit [$new_unit]>
145
146 Returns the unit that the number returned by L</attribute_as_man_days>
147 represents. This can be either C<h> if the underlying attribute is
148 less than 8 and C<man_day> otherwise.
149
150 If used as a setter then the underlying attribute is multiplied by 8
151 if C<$new_unit> equals C<man_day>. Otherwise the underlying attribute
152 is not modified. Intentional use is to set the man days first and the
153 unit later, e.g.
154
155   $obj->attribute_as_man_days($::form->{attribute_as_man_days});
156   $obj->attribute_as_man_days_unit($::form->{attribute_as_man_days_unit});
157
158 Note that L<SL::DB::Object/assign_attributes> is aware of this and
159 handles this case correctly.
160
161 =back
162
163 =head1 FUNCTIONS
164
165 =over 4
166
167 =item C<attr_duration @attributes>
168
169 Package method. Call with the names of attributes for which the helper
170 methods should be created.
171
172 =back
173
174 =head1 BUGS
175
176 Nothing here yet.
177
178 =head1 AUTHOR
179
180 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
181
182 =cut