From: Moritz Bunkus Date: Fri, 3 Jul 2015 08:08:27 +0000 (+0200) Subject: AttrDuration: Implementation für Spalten, die Dauer in Minuten speichern X-Git-Tag: release-3.3.0beta~32^2~16 X-Git-Url: http://wagnertech.de/git?a=commitdiff_plain;h=ae87c27e82eaa39a78e2380c9c069abe674ced86;p=kivitendo-erp.git AttrDuration: Implementation für Spalten, die Dauer in Minuten speichern --- diff --git a/SL/DB/Helper/AttrDuration.pm b/SL/DB/Helper/AttrDuration.pm index 704c340ae..5bdd4bf7d 100644 --- a/SL/DB/Helper/AttrDuration.pm +++ b/SL/DB/Helper/AttrDuration.pm @@ -3,7 +3,7 @@ package SL::DB::Helper::AttrDuration; use strict; use parent qw(Exporter); -our @EXPORT = qw(attr_duration); +our @EXPORT = qw(attr_duration attr_duration_minutes); use Carp; @@ -13,6 +13,12 @@ sub attr_duration { _make($package, $_) for @attributes; } +sub attr_duration_minutes { + my ($package, @attributes) = @_; + + _make_minutes($package, $_) for @attributes; +} + sub _make { my ($package, $attribute) = @_; @@ -75,6 +81,43 @@ sub _make { }; } +sub _make_minutes { + my ($package, $attribute) = @_; + + no strict 'refs'; + + *{ $package . '::' . $attribute . '_as_hours' } = sub { + my ($self, $value) = @_; + + $self->$attribute($value * 60 + ($self->$attribute % 60)) if @_ > 1; + return int(($self->$attribute // 0) / 60); + }; + + *{ $package . '::' . $attribute . '_as_minutes' } = sub { + my ($self, $value) = @_; + + $self->$attribute(int($self->$attribute) - (int($self->$attribute) % 60) + ($value // 0)) if @_ > 1; + return ($self->$attribute // 0) % 60; + }; + + *{ $package . '::' . $attribute . '_as_duration_string' } = sub { + my ($self, $value) = @_; + + if (@_ > 1) { + if (!defined($value) || ($value eq '')) { + $self->$attribute(undef); + } else { + croak $::locale->text("Invalid duration format") if $value !~ m{^(?:(\d*):)?(\d+)$}; + $self->$attribute(($1 // 0) * 60 + ($2 // 0)); + } + } + + my $as_hours = "${attribute}_as_hours"; + my $as_minutes = "${attribute}_as_minutes"; + return defined($self->$attribute) ? sprintf('%d:%02d', $self->$as_hours, $self->$as_minutes) : undef; + }; +} + 1; __END__ @@ -92,6 +135,7 @@ numeric columns # In a Rose model: use SL::DB::Helper::AttrDuration; __PACKAGE__->attr_duration('time_estimation'); + __PACKAGE__->attr_duration_minutes('hours'); # Read access: print "Minutes: " . $obj->time_estimation_as_minutes . " hours: " . $obj->time_estimation_as_hours . "\n"; @@ -104,11 +148,23 @@ numeric columns =head1 OVERVIEW -This is a helper for columns that store a duration as a numeric or -floating point number representing a number of hours. So the value -1.75 would stand for "1 hour, 45 minutes". +This is a helper for columns that store a duration in one of two formats: -The helper methods created are: +=over 2 + +=item 1. as a numeric or floating point number representing a number +of hours + +=item 2. as an integer presenting a number of minutes + +=back + +In the first case the value 1.75 would stand for "1 hour, 45 +minutes". In the second case the value 105 represents the same +duration. + +The helper methods created depend on the mode. Calling +C makes the following methods available: =over 4 @@ -160,6 +216,26 @@ handles this case correctly. =back +With C the following methods are available: + +=over 4 + +=item C + +Access only the minutes. Return values are in the range [0 - 59]. + +=item C + +Access only the hours. Returns an integer value. + +=item C + +Access the full value as a formatted string in the form C, +e.g. C<1:30> for the value 90 minutes. Parsing such a string is +supported, too. + +=back + =head1 FUNCTIONS =over 4 @@ -169,6 +245,11 @@ handles this case correctly. Package method. Call with the names of attributes for which the helper methods should be created. +=item C + +Package method. Call with the names of attributes for which the helper +methods should be created. + =back =head1 BUGS diff --git a/t/db_helper/attr_duration.t b/t/db_helper/attr_duration.t index da05a3211..0f41cfa03 100644 --- a/t/db_helper/attr_duration.t +++ b/t/db_helper/attr_duration.t @@ -4,16 +4,20 @@ use base qw(SL::DB::Object); __PACKAGE__->meta->setup( table => 'dummy', - columns => [ dummy => { type => 'numeric', precision => 2, scale => 12 }, ] + columns => [ + dummy => { type => 'numeric', precision => 2, scale => 12 }, + inty => { type => 'integer' }, + ] ); use SL::DB::Helper::AttrDuration; __PACKAGE__->attr_duration('dummy'); +__PACKAGE__->attr_duration_minutes('inty'); package main; -use Test::More tests => 91; +use Test::More; # tests => 91; use Test::Exception; use strict; @@ -31,6 +35,8 @@ sub new_item { Support::TestSetup::login(); my $item; +### attr_duration + # Wenn das Attribut undef ist: is(new_item->dummy, undef, 'uninitialized: raw'); is(new_item->dummy_as_hours, 0, 'uninitialized: as_hours'); @@ -165,4 +171,51 @@ lives_ok { new_item()->dummy_as_man_days_unit('h') } 'known unit h'; lives_ok { new_item()->dummy_as_man_days_unit('hour') } 'known unit hour'; lives_ok { new_item()->dummy_as_man_days_unit('man_day') } 'known unit man_day'; +### attr_duration_minutes + +# Wenn das Attribut undef ist: +is(new_item->inty, undef, 'uninitialized: raw'); +is(new_item->inty_as_hours, 0, 'uninitialized: as_hours'); +is(new_item->inty_as_minutes, 0, 'uninitialized: as_minutes'); +is(new_item->inty_as_duration_string, undef, 'uninitialized: as_duration_string'); + +# Auslesen kleiner 60 Minuten: +is(new_item(inty => 37)->inty, 37, 'initialized < 60: raw'); +is(new_item(inty => 37)->inty_as_hours, 0, 'initialized < 60: as_hours'); +is(new_item(inty => 37)->inty_as_minutes, 37, 'initialized < 60: as_minutes'); +is(new_item(inty => 37)->inty_as_duration_string, '0:37', 'initialized < 60: as_duration_string'); + +# Auslesen größer 60 Minuten: +is(new_item(inty => 145)->inty, 145, 'initialized > 60: raw'); +is(new_item(inty => 145)->inty_as_hours, 2, 'initialized > 60: as_hours'); +is(new_item(inty => 145)->inty_as_minutes, 25, 'initialized > 60: as_minutes'); +is(new_item(inty => 145)->inty_as_duration_string, '2:25', 'initialized > 60: as_duration_string'); + +$item = new_item(inty => 145); $item->inty_as_duration_string(undef); +is($item->inty, undef, 'write as_duration_string undef read raw'); +is($item->inty_as_minutes, 0, 'write as_duration_string undef read as_minutes'); +is($item->inty_as_hours, 0, 'write as_duration_string undef read as_hours'); +is($item->inty_as_duration_string, undef, 'write as_duration_string undef read as_duration_string'); + +$item = new_item(inty => 145); $item->inty_as_duration_string(''); +is($item->inty, undef, 'write as_duration_string "" read raw'); +is($item->inty_as_minutes, 0, 'write as_duration_string "" read as_minutes'); +is($item->inty_as_hours, 0, 'write as_duration_string "" read as_hours'); +is($item->inty_as_duration_string, undef, 'write as_duration_string "" read as_duration_string'); + +$item = new_item(inty => 145); $item->inty_as_duration_string("3:21"); +is($item->inty, 201, 'write as_duration_string 3:21 read raw'); +is($item->inty_as_minutes, 21, 'write as_duration_string 3:21 read as_minutes'); +is($item->inty_as_hours, 3, 'write as_duration_string 3:21 read as_hours'); +is($item->inty_as_duration_string, "3:21", 'write as_duration_string 3:21 read as_duration_string'); + +$item = new_item(inty => 145); $item->inty_as_duration_string("03:1"); +is($item->inty, 181, 'write as_duration_string 03:1 read raw'); +is($item->inty_as_minutes, 1, 'write as_duration_string 03:1 read as_minutes'); +is($item->inty_as_hours, 3, 'write as_duration_string 03:1 read as_hours'); +is($item->inty_as_duration_string, "3:01", 'write as_duration_string 03:1 read as_duration_string'); + +# Parametervalidierung +throws_ok { new_item()->inty_as_duration_string('invalid') } qr/invalid.*format/i, 'invalid duration format'; + done_testing();