diff options
author | Matthew Somerville <matthew@mysociety.org> | 2020-06-16 16:04:21 +0100 |
---|---|---|
committer | M Somerville <matthew-github@dracos.co.uk> | 2020-09-02 14:56:41 +0100 |
commit | 32c80504c0f4aad36f7d9eaef5ff3f2f6d851b77 (patch) | |
tree | 2b13714b6419d58ee9025e831fbc02f657e4cfc8 | |
parent | 764a6b7f8056d55aeba4656cba279b27a60d6b1a (diff) |
[Zurich] Factor out working days calculator.
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Zurich.pm | 43 | ||||
-rw-r--r-- | perllib/FixMyStreet/WorkingDays.pm | 78 | ||||
-rw-r--r-- | t/workingdays.t | 21 |
3 files changed, 106 insertions, 36 deletions
diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm index 5635939ac..4b893af40 100644 --- a/perllib/FixMyStreet/Cobrand/Zurich.pm +++ b/perllib/FixMyStreet/Cobrand/Zurich.pm @@ -10,6 +10,7 @@ use DateTime::Format::Pg; use Try::Tiny; use FixMyStreet::Geocode::Zurich; +use FixMyStreet::WorkingDays; use strict; use warnings; @@ -221,7 +222,7 @@ sub get_body_sender { # Report overdue functions -my %public_holidays = map { $_ => 1 } ( +my @public_holidays = ( # New Year's Day, Saint Berchtold, Good Friday, Easter Monday, # Sechseläuten, Labour Day, Ascension Day, Whit Monday, # Swiss National Holiday, Knabenschiessen, Christmas, St Stephen's Day @@ -247,53 +248,23 @@ my %public_holidays = map { $_ => 1 } ( '2021-09-13', ); -sub is_public_holiday { - my $dt = shift; - return $public_holidays{$dt->ymd}; -} - -sub is_weekend { - my $dt = shift; - return $dt->dow > 5; -} - -sub add_days { - my ( $dt, $days ) = @_; - $dt = $dt->clone; - while ( $days > 0 ) { - $dt->add ( days => 1 ); - next if is_public_holiday($dt) or is_weekend($dt); - $days--; - } - return $dt; -} - -sub sub_days { - my ( $dt, $days ) = @_; - $dt = $dt->clone; - while ( $days > 0 ) { - $dt->subtract ( days => 1 ); - next if is_public_holiday($dt) or is_weekend($dt); - $days--; - } - return $dt; -} - sub overdue { my ( $self, $problem ) = @_; my $w = $problem->created; return 0 unless $w; + my $wd = FixMyStreet::WorkingDays->new( public_holidays => \@public_holidays ); + # call with previous state if ( $problem->state eq 'submitted' ) { # One working day - $w = add_days( $w, 1 ); + $w = $wd->add_days( $w, 1 ); return $w < DateTime->now() ? 1 : 0; } elsif ( $problem->state eq 'confirmed' || $problem->state eq 'in progress' || $problem->state eq 'feedback pending' ) { # States which affect the subdiv_overdue statistic. TODO: this may no longer be required # Six working days from creation - $w = add_days( $w, 6 ); + $w = $wd->add_days( $w, 6 ); return $w < DateTime->now() ? 1 : 0; # call with new state @@ -301,7 +272,7 @@ sub overdue { # States which affect the closed_overdue statistic # Five working days from moderation (so 6 from creation) - $w = add_days( $w, 6 ); + $w = $wd->add_days( $w, 6 ); return $w < DateTime->now() ? 1 : 0; } } diff --git a/perllib/FixMyStreet/WorkingDays.pm b/perllib/FixMyStreet/WorkingDays.pm new file mode 100644 index 000000000..615b226c6 --- /dev/null +++ b/perllib/FixMyStreet/WorkingDays.pm @@ -0,0 +1,78 @@ +package FixMyStreet::WorkingDays; + +use Moo; + +=head1 FixMyStreet::WorkingDays + +Given a list of public holiday dates, creates an object that can be used to +add/subtract days from a date, only counting working days (excluding public +holidays and weekends). + +=over + +=cut + +has public_holidays => ( + is => 'ro', + coerce => sub { + return { map { $_ => 1 } @{$_[0]} }; + }, +); + +=item add_days + +Given a DateTime object and a number of days, returns a new DateTime object +that many working days (excluding public holidays and weekends) later. + +=cut + +sub add_days { + my ( $self, $dt, $days, $subtract ) = @_; + $dt = $dt->clone; + while ( $days > 0 ) { + $dt->add ( days => $subtract ? -1 : 1 ); + next if $self->is_public_holiday($dt); + next if $self->is_weekend($dt); + $days--; + } + return $dt; +} + +=item sub_days + +Given a DateTime object and a number of days, returns a new DateTime object +that many working days (excluding public holidays and weekends) earlier. + +=cut + +sub sub_days { + my $self = shift; + return $self->add_days(@_, 1); +} + +=item is_public_holiday + +Given a DateTime object, return true if it is a public holiday. + +=cut + +sub is_public_holiday { + my ($self, $dt) = @_; + return $self->public_holidays->{$dt->ymd}; +} + +=item is_weekend + +Given a DateTime object, return true if it is a weekend. + +=cut + +sub is_weekend { + my ($self, $dt) = @_; + return $dt->dow > 5; +} + +1; + +=back + diff --git a/t/workingdays.t b/t/workingdays.t new file mode 100644 index 000000000..326cf05c9 --- /dev/null +++ b/t/workingdays.t @@ -0,0 +1,21 @@ +use Test::More; +use DateTime; + +use_ok 'FixMyStreet::WorkingDays'; + + +my $wd = FixMyStreet::WorkingDays->new( + public_holidays => [ + '2020-09-21', + '2020-09-15', + ], +); + +my $dt = DateTime->new(year => 2020, month => 9, day => 19); + +is $wd->add_days($dt, 1)->ymd, '2020-09-22'; +is $wd->sub_days($dt, 5)->ymd, '2020-09-11'; +is $wd->is_public_holiday($dt), undef; +is $wd->is_weekend($dt), 1; + +done_testing; |