1 package SL::DB::Helper::AttrDuration;
 
   5 use parent qw(Exporter);
 
   6 our @EXPORT = qw(attr_duration attr_duration_minutes);
 
  11   my ($package, @attributes) = @_;
 
  13   _make($package, $_) for @attributes;
 
  16 sub attr_duration_minutes {
 
  17   my ($package, @attributes) = @_;
 
  19   _make_minutes($package, $_) for @attributes;
 
  23   my ($package, $attribute) = @_;
 
  27   *{ $package . '::' . $attribute . '_as_hours' } = sub {
 
  28     my ($self, $value) = @_;
 
  30     $self->$attribute(int($value) + ($self->$attribute - int($self->$attribute))) if @_ > 1;
 
  31     return int($self->$attribute // 0);
 
  34   *{ $package . '::' . $attribute . '_as_minutes' } = sub {
 
  35     my ($self, $value) = @_;
 
  37     $self->$attribute(int($self->$attribute) * 1.0 + ($value // 0) / 60.0) if @_ > 1;
 
  38     return int(($self->$attribute // 0) * 60.0 + 0.5) % 60;
 
  41   *{ $package . '::' . $attribute . '_as_duration_string' } = sub {
 
  42     my ($self, $value) = @_;
 
  44     $self->$attribute(defined($value) ? $::form->parse_amount(\%::myconfig, $value) * 1 : undef) if @_ > 1;
 
  45     return defined($self->$attribute) ? $::form->format_amount(\%::myconfig, $self->$attribute // 0, 2) : undef;
 
  48   *{ $package . '::' . $attribute . '_as_man_days' } = sub {
 
  49     my ($self, $value) = @_;
 
  52       return undef if !defined $value;
 
  53       $self->$attribute($value);
 
  55     $value = $self->$attribute // 0;
 
  56     return $value >= 8.0 ? $value / 8.0 : $value;
 
  59   *{ $package . '::' . $attribute . '_as_man_days_unit' } = sub {
 
  60     my ($self, $unit) = @_;
 
  63       return undef if !defined $unit;
 
  64       croak "Unknown unit '${unit}'"                    if $unit !~ m/^(?:h|hour|man_day)$/;
 
  65       $self->$attribute(($self->$attribute // 0) * 8.0) if $unit eq 'man_day';
 
  68     return ($self->$attribute // 0) >= 8.0 ? 'man_day' : 'h'
 
  71   *{ $package . '::' . $attribute . '_as_man_days_string' } = sub {
 
  72     my ($self, $value) = @_;
 
  73     my $method         = "${attribute}_as_man_days";
 
  76       return undef if !defined $value;
 
  77       $self->$method($::form->parse_amount(\%::myconfig, $value));
 
  80     return $::form->format_amount(\%::myconfig, $self->$method // 0, 2);
 
  85   my ($package, $attribute) = @_;
 
  89   *{ $package . '::' . $attribute . '_as_hours' } = sub {
 
  90     my ($self, $value) = @_;
 
  92     $self->$attribute($value * 60 + ($self->$attribute % 60)) if @_ > 1;
 
  93     return int(($self->$attribute // 0) / 60);
 
  96   *{ $package . '::' . $attribute . '_as_minutes' } = sub {
 
  97     my ($self, $value) = @_;
 
  99     $self->$attribute(int($self->$attribute) - (int($self->$attribute) % 60) + ($value // 0)) if @_ > 1;
 
 100     return ($self->$attribute // 0) % 60;
 
 103   *{ $package . '::' . $attribute . '_as_duration_string' } = sub {
 
 104     my ($self, $value) = @_;
 
 107       if (!defined($value) || ($value eq '')) {
 
 108         $self->$attribute(undef);
 
 110         croak $::locale->text("Invalid duration format") if $value !~ m{^(?:(\d*):)?(\d+)$};
 
 111         $self->$attribute(($1 // 0) * 60 + ($2 // 0));
 
 115     my $as_hours   = "${attribute}_as_hours";
 
 116     my $as_minutes = "${attribute}_as_minutes";
 
 117     return defined($self->$attribute) ? sprintf('%d:%02d', $self->$as_hours, $self->$as_minutes) : undef;
 
 130 SL::DB::Helper::AttrDuration - Attribute helper for duration stored in
 
 136   use SL::DB::Helper::AttrDuration;
 
 137   __PACKAGE__->attr_duration('time_estimation');
 
 138   __PACKAGE__->attr_duration_minutes('hours');
 
 141   print "Minutes: " . $obj->time_estimation_as_minutes . " hours: " . $obj->time_estimation_as_hours . "\n";
 
 143   # Use formatted strings in input fields in templates:
 
 146     [% L.input_tag('time_estimation_as_duration_string', SELF.obj.time_estimation_as_duration_string) %]
 
 151 This is a helper for columns that store a duration in one of two formats:
 
 155 =item 1. as a numeric or floating point number representing a number
 
 158 =item 2. as an integer presenting a number of minutes
 
 162 In the first case the value 1.75 would stand for "1 hour, 45
 
 163 minutes". In the second case the value 105 represents the same
 
 166 The helper methods created depend on the mode. Calling
 
 167 C<attr_duration> makes the following methods available:
 
 171 =item C<attribute_as_minutes [$new_value]>
 
 173 Access only the minutes. Return values are in the range [0 - 59].
 
 175 =item C<attribute_as_hours [$new_value]>
 
 177 Access only the hours. Returns an integer value.
 
 179 =item C<attribute_as_duration_string [$new_value]>
 
 181 Access the full value as a formatted string according to the user's
 
 184 =item C<attribute_as_man_days [$new_value]>
 
 186 Access the attribute as a number of man days which are assumed to be 8
 
 187 hours long. If the underlying attribute is less than 8 then the value
 
 188 itself will be returned. Otherwise the value divided by 8 is returned.
 
 190 If used as a setter then the underlying attribute is simply set to
 
 191  C<$new_value>. Intentional use is to set the man days first and the
 
 194   $obj->attribute_as_man_days($::form->{attribute_as_man_days});
 
 195   $obj->attribute_as_man_days_unit($::form->{attribute_as_man_days_unit});
 
 197 Note that L<SL::DB::Object/assign_attributes> is aware of this and
 
 198 handles this case correctly.
 
 200 =item C<attribute_as_man_days_unit [$new_unit]>
 
 202 Returns the unit that the number returned by L</attribute_as_man_days>
 
 203 represents. This can be either C<h> if the underlying attribute is
 
 204 less than 8 and C<man_day> otherwise.
 
 206 If used as a setter then the underlying attribute is multiplied by 8
 
 207 if C<$new_unit> equals C<man_day>. Otherwise the underlying attribute
 
 208 is not modified. Intentional use is to set the man days first and the
 
 211   $obj->attribute_as_man_days($::form->{attribute_as_man_days});
 
 212   $obj->attribute_as_man_days_unit($::form->{attribute_as_man_days_unit});
 
 214 Note that L<SL::DB::Object/assign_attributes> is aware of this and
 
 215 handles this case correctly.
 
 219 With C<attr_duration_minutes> the following methods are available:
 
 223 =item C<attribute_as_minutes [$new_value]>
 
 225 Access only the minutes. Return values are in the range [0 - 59].
 
 227 =item C<attribute_as_hours [$new_value]>
 
 229 Access only the hours. Returns an integer value.
 
 231 =item C<attribute_as_duration_string [$new_value]>
 
 233 Access the full value as a formatted string in the form C<h:mm>,
 
 234 e.g. C<1:30> for the value 90 minutes. Parsing such a string is
 
 243 =item C<attr_duration @attributes>
 
 245 Package method. Call with the names of attributes for which the helper
 
 246 methods should be created.
 
 248 =item C<attr_duration_minutes @attributes>
 
 250 Package method. Call with the names of attributes for which the helper
 
 251 methods should be created.
 
 261 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>