Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bexley][WW] Fetch successful collections alongside other in-cab logs #4969

Merged
merged 2 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 64 additions & 42 deletions perllib/FixMyStreet/Cobrand/Bexley/Waste.pm
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,12 @@
$property->{missed_collection_reports}
= $self->_missed_collection_reports($property);
$property->{recent_collections} = $self->_recent_collections($property);
my ($property_logs, $street_logs) = $self->_in_cab_logs($property);

my ( $property_logs, $street_logs, $successful_collections )

Check warning on line 212 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L212

Added line #L212 was not covered by tests
= $self->_in_cab_logs($property);
$property->{successful_collections} = $successful_collections;

Check warning on line 214 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L214

Added line #L214 was not covered by tests
$property->{red_tags} = $property_logs;
$property->{service_updates} = grep { $_->{service_update} } @$street_logs;
$property->{service_updates} = $street_logs;

Check warning on line 216 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L216

Added line #L216 was not covered by tests

# Set certain things outside of services loop
my $containers = $self->_containers($property);
Expand Down Expand Up @@ -260,18 +262,29 @@
}

my ($round) = split / /, $service->{RoundSchedule};

# 'Next collection date' could be today; successful collection logs
# will tell us if the collection has already been made
my $successful_collection_dt
= $property->{successful_collections}{$round};

Check warning on line 269 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L269

Added line #L269 was not covered by tests
my $collected_today = $successful_collection_dt
&& $now_dt->delta_days($successful_collection_dt)
->in_units('days') == 0
? 1 : 0;

my $filtered_service = {
id => $service->{SiteServiceID},
service_id => $service->{ServiceItemName},
service_name => $container->{name},
service_description => $container->{description},
round_schedule => $service->{RoundSchedule},
round => $round,
next => {
date => $service->{NextCollectionDate},
ordinal => ordinal( $next_dt->day ),
changed => 0,
is_today => $now_dt->ymd eq $next_dt->ymd,
next => {
date => $service->{NextCollectionDate},
ordinal => ordinal( $next_dt->day ),
changed => 0,
is_today => $now_dt->ymd eq $next_dt->ymd,
already_collected => $collected_today,
},
assisted_collection => $service->{ServiceName} && $service->{ServiceName} eq 'Assisted Collection' ? 1 : 0,
};
Expand Down Expand Up @@ -426,7 +439,9 @@
}

# Returns a hash of recent collections, mapping Round + Schedule to collection
# date
# date.
# NOTE These denote *scheduled* recent collections; *actual* recent
# collections are recorded in the in-cab logs.
sub _recent_collections {
my ( $self, $property ) = @_;

Expand Down Expand Up @@ -469,7 +484,7 @@
# Returns a hashref of recent in-cab logs for the property, split by USRN and
# UPRN
sub _in_cab_logs {
my ( $self, $property, $all_logs ) = @_;
my ( $self, $property ) = @_;

Check warning on line 487 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L487

Added line #L487 was not covered by tests

# Logs are recorded against parent properties, not children
$property = $property->{parent_property} if $property->{parent_property};
Expand Down Expand Up @@ -502,35 +517,44 @@

my @property_logs;
my @street_logs;
my %successful_collections;

Check warning on line 520 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L520

Added line #L520 was not covered by tests

return ( \@property_logs, \@street_logs ) unless $cab_logs;
return ( \@property_logs, \@street_logs, \%successful_collections )
unless $cab_logs;

for (@$cab_logs) {
# Skip non-exceptional logs
next if (!$_->{Reason} || $_->{Reason} eq 'N/A') && !$all_logs;

my $logdate = DateTime::Format::Strptime->new( pattern => '%Y-%m-%dT%H:%M:%S' )->parse_datetime( $_->{LogDate} );

if ( $_->{Uprn} && $_->{Uprn} eq $property->{uprn} ) {
push @property_logs, {
uprn => $_->{Uprn},
round => $_->{RoundCode},
reason => $_->{Reason},
date => $logdate,
ordinal => ordinal( $logdate->day ),
};
} else {
push @street_logs, {
service_update => $_->{Uprn} ? 0 : 1,
round => $_->{RoundCode},
reason => $_->{Reason},
date => $logdate,
ordinal => ordinal( $logdate->day ),
};
# There aren't necessarily round completion logs; the presence of any
# log against a round code should be taken as a sign that the round
# has been completed or at least attempted for the property.
# Overwrite entry for given round if a later logdate is found.
$successful_collections{ $_->{RoundCode} } = $logdate
if !$successful_collections{ $_->{RoundCode} }
|| $successful_collections{ $_->{RoundCode} } < $logdate;

# Gather property-level and street-level exceptions
if ( $_->{Reason} && $_->{Reason} ne 'N/A' ) {
if ( $_->{Uprn} && $_->{Uprn} eq $property->{uprn} ) {
push @property_logs, {
uprn => $_->{Uprn},
round => $_->{RoundCode},
reason => $_->{Reason},
date => $logdate,

Check warning on line 543 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L543

Added line #L543 was not covered by tests
ordinal => ordinal( $logdate->day ),
};
} elsif ( !$_->{Uprn} ) {
push @street_logs, {
round => $_->{RoundCode},
reason => $_->{Reason},
date => $logdate,

Check warning on line 550 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L550

Added line #L550 was not covered by tests
ordinal => ordinal( $logdate->day ),
};
}
}
}

return ( \@property_logs, \@street_logs );
return ( \@property_logs, \@street_logs, \%successful_collections );

Check warning on line 557 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L557

Added line #L557 was not covered by tests
}

sub can_report_missed {
Expand All @@ -540,7 +564,7 @@
return 0 if $property->{missed_collection_reports}{ $service->{service_id} };

# Prevent reporting if there are service updates
return 0 if $property->{service_updates};
return 0 if @{ $property->{service_updates} // [] };

# Prevent reporting if there are red tags on the service
# Red tags are matched to services based on prefix
Expand All @@ -554,18 +578,16 @@
= $property->{recent_collections}{ $service->{round_schedule} };

if ($last_expected_collection_dt) {
# We need to consider both property and street logs here,
# as either type may log a successful collection
# (i.e. 'Reason' = 'N/A' for given round)
my ( $property_logs, $street_logs )
= $self->_in_cab_logs( $property, 1 );
# TODO We can probably get successful collections directly off the
# property rather than query _in_cab_logs again
my ( undef, undef, $successful_collections )

Check warning on line 583 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L583

Added line #L583 was not covered by tests
= $self->_in_cab_logs($property);

# If there is a log for this collection, that is when
# the round was completed so we can make a report if
# we're within that time
my ($log_for_round)
= grep { $_->{round} eq $service->{round} }
( @$property_logs, @$street_logs );
my $logged_time_for_round
= $successful_collections->{ $service->{round} };

Check warning on line 590 in perllib/FixMyStreet/Cobrand/Bexley/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Bexley/Waste.pm#L590

Added line #L590 was not covered by tests

# log time needs to be greater than or equal to 3 working days ago,
# less than today
Expand All @@ -580,9 +602,9 @@
# fortnightly, but they share a round code prefix.
return 0 if $last_expected_collection_dt < $min_dt && !$service->{next}{is_today};

return ( $log_for_round->{date} < $now_dt
&& $log_for_round->{date} >= $min_dt ) ? 1 : 0
if $log_for_round;
return ( $logged_time_for_round < $now_dt
&& $logged_time_for_round >= $min_dt ) ? 1 : 0
if $logged_time_for_round;

$service->{last}{is_delayed} =
($last_expected_collection_dt < $today_dt && $last_expected_collection_dt >= $min_dt)
Expand Down
155 changes: 132 additions & 23 deletions t/app/controller/waste_bexley.t
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,34 @@ $dbi_mock->mock( 'connect', sub {
} );

my $whitespace_mock = Test::MockModule->new('Integrations::Whitespace');
sub default_mocks {
# These are overridden for some tests
$whitespace_mock->mock(
'GetSiteCollections',
sub {
my ( $self, $uprn ) = @_;
return _site_collections()->{$uprn};
}
);
$whitespace_mock->mock( 'GetInCabLogsByUprn', sub {
my ( $self, $uprn ) = @_;
return [ grep { $_->{Uprn} eq $uprn } @{ _in_cab_logs() } ];
});
$whitespace_mock->mock( 'GetInCabLogsByUsrn', sub {
my ( $self, $usrn ) = @_;
return _in_cab_logs();
});
};

default_mocks();

$whitespace_mock->mock(
'GetSiteInfo',
sub {
my ( $self, $uprn ) = @_;
return _site_info()->{$uprn};
}
);
$whitespace_mock->mock(
'GetSiteCollections',
sub {
my ( $self, $uprn ) = @_;
return _site_collections()->{$uprn};
}
);
$whitespace_mock->mock( 'GetAccountSiteID', &_account_site_id );
$whitespace_mock->mock( 'GetCollectionByUprnAndDate',
sub {
Expand All @@ -122,14 +136,6 @@ $whitespace_mock->mock(
return _worksheet_detail_service_items()->{$worksheet_id};
}
);
$whitespace_mock->mock( 'GetInCabLogsByUprn', sub {
my ( $self, $uprn ) = @_;
return [ grep { $_->{Uprn} eq $uprn } @{ _in_cab_logs() } ];
});
$whitespace_mock->mock( 'GetInCabLogsByUsrn', sub {
my ( $self, $usrn ) = @_;
return _in_cab_logs();
});
my $comment_user = $mech->create_user_ok('comment');
my $body = $mech->create_body_ok(
2494,
Expand Down Expand Up @@ -274,6 +280,7 @@ FixMyStreet::override_config {
ordinal => ignore(),
date => ignore(),
is_today => ignore(),
already_collected => 0,
},
last => {
ordinal => ignore(),
Expand Down Expand Up @@ -433,18 +440,120 @@ FixMyStreet::override_config {
}
};

subtest 'Shows when a collection is due today' => sub {
set_fixed_time('2024-04-01T07:00:00'); # April 1st, 08:00 BST
subtest 'Various logs for today' => sub {
$whitespace_mock->mock( 'GetSiteCollections', sub {
return [
{ SiteServiceID => 8,
ServiceItemDescription => 'Service 8',
ServiceItemName => 'PC-55', # Blue Recycling Box
ServiceName => 'Blue Recycling Box',
NextCollectionDate => '2024-04-01T00:00:00',
SiteServiceValidFrom => '2024-03-31T00:59:59',
SiteServiceValidTo => '0001-01-01T00:00:00',

RoundSchedule => 'RND-8-9 Mon, RND-8-9 Wed',
},
];
} );
$whitespace_mock->mock( 'GetInCabLogsByUprn', sub { [] } );
$whitespace_mock->mock( 'GetInCabLogsByUsrn', sub { [] } );

$mech->get_ok('/waste');
$mech->submit_form_ok( { with_fields => { postcode => 'DA1 3LD' } } );
$mech->submit_form_ok( { with_fields => { address => 10001 } } );
set_fixed_time('2024-04-01T07:00:00'); # April 1st, 08:00 BST

# Blue and green recycling boxes are due today
note 'No in-cab logs';
$mech->get_ok('/waste/10001');
$mech->content_lacks('Service status');
$mech->content_contains('Being collected today');
$mech->content_lacks('Collection completed or attempted earlier today');

# Put time back to previous value
# Set time to later in the day
set_fixed_time('2024-04-01T16:01:00'); # April 1st, 17:01 BST

note 'Successful collection has occurred';
$whitespace_mock->mock( 'GetInCabLogsByUsrn', sub {
return [
{
LogID => 1,
Reason => 'N/A',
RoundCode => 'RND-8-9',
LogDate => '2024-04-01T12:00:00.417',
Uprn => '',
Usrn => '321',
},
];
});
$mech->get_ok('/waste/10001');
$mech->content_lacks('Service status');
$mech->content_lacks('Being collected today');
$mech->content_contains('Collection completed or attempted earlier today');

note 'Property has red tag on collection attempted earlier today';
$whitespace_mock->mock( 'GetInCabLogsByUprn', sub {
return [
{
LogID => 1,
Reason => 'Bin has gone feral',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤣

RoundCode => 'RND-8-9',
LogDate => '2024-04-01T12:00:00.417',
Uprn => '10001',
Usrn => '321',
},
];
});
$whitespace_mock->mock( 'GetInCabLogsByUsrn', sub { [] } );
$mech->get_ok('/waste/10001');
$mech->content_contains('Service status');
$mech->content_contains(
'Our collection teams have reported the following problems with your bins:'
);
$mech->content_lacks('Being collected today');
$mech->content_contains('Collection completed or attempted earlier today');

note 'Red tag on other property on same street';
$whitespace_mock->mock( 'GetInCabLogsByUprn', sub { [] } );
$whitespace_mock->mock( 'GetInCabLogsByUsrn', sub {
return [
{
LogID => 1,
Reason => 'Bin has gone feral',
RoundCode => 'RND-8-9',
LogDate => '2024-04-01T12:00:00.417',
Uprn => '19991',
Usrn => '321',
},
];
});
$mech->get_ok('/waste/10001');
$mech->content_lacks('Service status');
$mech->content_lacks('Being collected today');
$mech->content_contains('Collection completed or attempted earlier today');

note 'Service update on street';
$whitespace_mock->mock( 'GetInCabLogsByUprn', sub { [] } );
$whitespace_mock->mock( 'GetInCabLogsByUsrn', sub {
return [
{
LogID => 1,
Reason => 'Streetwide fox invasion',
RoundCode => 'RND-8-9',
LogDate => '2024-04-01T12:00:00.417',
Uprn => '',
Usrn => '321',
},
];
});
$mech->get_ok('/waste/10001');
$mech->content_contains('Service status');
$mech->content_contains('Streetwide fox invasion');
$mech->content_lacks(
'Our collection teams have reported the following problems with your bins:'
);
$mech->content_lacks('Being collected today');
$mech->content_contains('Collection completed or attempted earlier today');

# Reinstate original mocks
set_fixed_time('2024-03-31T01:00:00'); # March 31st, 02:00 BST
default_mocks();
};

subtest 'Asks user for location of bins on missed collection form' => sub {
Expand Down Expand Up @@ -638,7 +747,7 @@ FixMyStreet::override_config {
{ LogDate => '2024-04-19T10:00:00.977',
Reason => 'N/A',
RoundCode => 'RES-R4', # For RES-660
Uprn => '123456',
Uprn => '10001',
},
# Successful collection earlier than allowed window
{ LogDate => '2024-04-16T10:00:00.977',
Expand Down
4 changes: 3 additions & 1 deletion templates/web/base/waste/bin_days.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ <h3 class="govuk-heading-l govuk-warning-text__heading">Your subscription is soo
<dt class="govuk-summary-list__key">Next collection</dt>
<dd class="govuk-summary-list__value">
[% IF unit.next %]
[% IF unit.next.is_today %]
[% IF unit.next.already_collected %]
<strong>Collection completed or attempted earlier today</strong>
[% ELSIF unit.next.is_today %]
<strong>Being collected today</strong>
[% ELSE %]
[% date.format(unit.next.date) | replace('~~~', unit.next.ordinal) %]
Expand Down
Loading