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

[Merton] Initial bulky waste functionality #4924

Merged
merged 3 commits into from
May 16, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 0 additions & 8 deletions perllib/FixMyStreet/Cobrand/Brent.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1567,14 +1567,6 @@ sub collection_date {

sub _bulky_refund_cutoff_date { }

sub _bulky_date_to_dt {
my ($self, $date) = @_;
$date = (split(";", $date))[0];
my $parser = DateTime::Format::Strptime->new( pattern => '%FT%T', time_zone => FixMyStreet->local_time_zone);
my $dt = $parser->parse_datetime($date);
return $dt ? $dt->truncate( to => 'day' ) : undef;
}

sub waste_munge_bulky_data {
my ($self, $data) = @_;

Expand Down
8 changes: 0 additions & 8 deletions perllib/FixMyStreet/Cobrand/Bromley.pm
Original file line number Diff line number Diff line change
Expand Up @@ -944,14 +944,6 @@ sub collection_date {

sub _bulky_refund_cutoff_date { }

sub _bulky_date_to_dt {
my ($self, $date) = @_;
$date = (split(";", $date))[0];
my $parser = DateTime::Format::Strptime->new( pattern => '%FT%T', time_zone => FixMyStreet->local_time_zone);
my $dt = $parser->parse_datetime($date);
return $dt ? $dt->truncate( to => 'day' ) : undef;
}

sub waste_munge_bulky_data {
my ($self, $data) = @_;

Expand Down
41 changes: 37 additions & 4 deletions perllib/FixMyStreet/Cobrand/Merton/Waste.pm
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
my $service_id = $unit->{service_id};
my $time_banded = $self->{c}->stash->{property_time_banded};

return "$base/sack-black" if $service_id == 2242 && $time_banded;
return "$base/sack-black" if $service_id eq 2242 && $time_banded;
if (my $container = $unit->{request_containers}[0]) {
return "$base/sack-purple" if $container == 17;
}
Expand Down Expand Up @@ -129,9 +129,6 @@
return 0;
}

# TODO
sub waste_bulky_missed_blocked_codes {}

sub garden_collection_time { '6:30am' }
sub garden_waste_new_bin_admin_fee { 0 }

Expand Down Expand Up @@ -188,8 +185,8 @@
$action_id = 1; # Deliver
$reason_id = 4; # New
} elsif ($reason eq 'more') {
$action_id = 1; # Deliver
$reason_id = 3; # Change capacity

Check warning on line 189 in perllib/FixMyStreet/Cobrand/Merton/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Merton/Waste.pm#L188-L189

Added lines #L188 - L189 were not covered by tests
} else {
# No reason, must be a bag
$action_id = 1; # Deliver
Expand All @@ -200,7 +197,7 @@
if ($reason eq 'damaged' || $reason eq 'missing') {
$data->{title} = "Request replacement $container";
} elsif ($reason eq 'change_capacity') {
$data->{title} = "Request exchange for $container";

Check warning on line 200 in perllib/FixMyStreet/Cobrand/Merton/Waste.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/Cobrand/Merton/Waste.pm#L200

Added line #L200 was not covered by tests
} else {
$data->{title} = "Request new $container";
}
Expand Down Expand Up @@ -271,4 +268,40 @@
}
}

=head2 Bulky waste collection

Merton has a 6am collection and cut-off for cancellation time.
Everything else is configured in SLWPEcho.pm

=cut

sub bulky_collection_time { { hours => 6, minutes => 0 } }
sub bulky_cancellation_cutoff_time { { hours => 6, minutes => 0 } }
sub bulky_allowed_property {
my ( $self, $property ) = @_;
return 1 if $self->bulky_enabled && $property->{has_bulky_service};
}
sub bulky_collection_window_days { 28 }

=item bulky_open_overdue

Returns true if the booking is open and after 6pm on the day of the collection.

=cut

sub bulky_open_overdue {
my ($self, $event) = @_;

if ($event->{state} eq 'open' && $self->_bulky_collection_overdue($event)) {
return 1;
}
}

sub _bulky_collection_overdue {
my $collection_due_date = $_[1]->{date};
$collection_due_date->truncate(to => 'day')->set_hour(18);
my $today = DateTime->now->set_time_zone(FixMyStreet->local_time_zone);
return $today > $collection_due_date;
}

1;
35 changes: 27 additions & 8 deletions perllib/FixMyStreet/Roles/Cobrand/Echo.pm
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,6 @@ sub _parse_events {
# Only care about open requests/enquiries
my $closed = $self->_closed_event($_);
next if $type ne 'missed' && $type ne 'bulky' && $closed;
next if $type eq 'bulky' && !$closed;

if ($type eq 'request') {
my $report = $self->problems->search({ external_id => $_->{Guid} })->first;
Expand All @@ -364,13 +363,20 @@ sub _parse_events {
$self->parse_event_missed($_, $closed, $events);
} elsif ($type eq 'bulky') {
my $report = $self->problems->search({ external_id => $_->{Guid} })->first;
my $resolved_date = construct_bin_date($_->{ResolvedDate});
$events->{enquiry}{$event_type}{$_->{Guid}} = {
date => $resolved_date,
report => $report,
resolution => $_->{ResolutionCodeId},
state => $_->{EventStateId},
};
if ($report) {
my $row = {
report => $report,
resolution => $_->{ResolutionCodeId},
};
if ($closed) {
$row->{date} = construct_bin_date($_->{ResolvedDate});
$row->{state} = $_->{EventStateId};
} else {
$row->{date} = $self->collection_date($report);
$row->{state} = 'open';
}
$events->{enquiry}{$event_type}{$_->{Guid}} = $row;
}
} else { # General enquiry of some sort
$events->{enquiry}->{$event_type} = 1;
}
Expand Down Expand Up @@ -1052,10 +1058,15 @@ sub bulky_check_missed_collection {
}
}
}

# Open events are coming through and we only want to continue under specific circumstances with an open event
next unless (!$event->{state} || $event->{state} ne 'open') || $self->{c}->cobrand->call_hook('bulky_open_overdue', $event);

$row->{report_allowed} = $in_time && !$row->{report_locked_out};

my $recent_events = $self->_events_since_date($event->{date}, $missed_events);
$row->{report_open} = $recent_events->{open} || $recent_events->{closed};

$self->{c}->stash->{bulky_missed}{$guid} = $row;
}
}
Expand Down Expand Up @@ -1281,4 +1292,12 @@ sub per_photo_size_limit_for_report_in_bytes {
return min($max_size_per_image, $max_size_per_image_from_total);
};

sub _bulky_date_to_dt {
my ($self, $date) = @_;
$date = (split(";", $date))[0];
my $parser = DateTime::Format::Strptime->new( pattern => '%FT%T', time_zone => FixMyStreet->local_time_zone);
my $dt = $parser->parse_datetime($date);
return $dt ? $dt->truncate( to => 'day' ) : undef;
}

1;
184 changes: 0 additions & 184 deletions perllib/FixMyStreet/Roles/Cobrand/KingstonSutton.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ package FixMyStreet::Roles::Cobrand::KingstonSutton;

use Moo::Role;
with 'FixMyStreet::Roles::Cobrand::SLWP';
with 'FixMyStreet::Roles::Cobrand::BulkyWaste';

use FixMyStreet::App::Form::Waste::Garden::Sacks;
use FixMyStreet::App::Form::Waste::Garden::Sacks::Renew;
Expand Down Expand Up @@ -216,29 +215,6 @@ sub waste_quantity_max {
);
}

sub waste_bulky_missed_blocked_codes {
return {
# Partially completed
12399 => {
507 => 'Not all items presented',
380 => 'Some items too heavy',
},
# Completed
12400 => {
606 => 'More items presented than booked',
},
# Not Completed
12401 => {
460 => 'Nothing out',
379 => 'Item not as described',
100 => 'No access',
212 => 'Too heavy',
473 => 'Damage on site',
234 => 'Hazardous waste',
},
};
}

sub waste_munge_bin_services_open_requests {
my ($self, $open_requests) = @_;
if ($open_requests->{+CONTAINER_REFUSE_140}) { # Sutton
Expand Down Expand Up @@ -433,164 +409,4 @@ sub dashboard_export_problems_add_columns {
});
}

=head2 Bulky waste collection

SLWP looks 8 weeks ahead for collection dates, and cancels by sending an
update, not a new report. It sends the event to the backend before collecting
payment, and does not refund on cancellations. It has a hard-coded list of
property types allowed to book collections.

=cut

sub bulky_collection_window_days { 56 }

sub bulky_cancel_by_update { 1 }
sub bulky_send_before_payment { 1 }
sub bulky_show_location_field_mandatory { 1 }

sub bulky_can_refund { 0 }
sub _bulky_refund_cutoff_date { }

=head2 bulky_collection_window_start_date

K&S have an 11pm cut-off for looking to book next day collections.

=cut

sub bulky_collection_window_start_date {
my $self = shift;
my $now = DateTime->now( time_zone => FixMyStreet->local_time_zone );
my $start_date = $now->clone->truncate( to => 'day' )->add( days => 1 );
# If past 11pm, push start date one day later
if ($now->hour >= 23) {
$start_date->add( days => 1 );
}
return $start_date;
}

sub bulky_allowed_property {
my ( $self, $property ) = @_;

return if $property->{has_no_services};
my $cfg = $self->feature('echo');

my $type = $property->{type_id} || 0;
my $valid_type = grep { $_ == $type } @{ $cfg->{bulky_address_types} || [] };
my $domestic_farm = $type != 7 || $property->{domestic_refuse_bin};
return $self->bulky_enabled && $valid_type && $domestic_farm;
}

sub collection_date {
my ($self, $p) = @_;
return $self->_bulky_date_to_dt($p->get_extra_field_value('Collection_Date'));
}

sub bulky_free_collection_available { 0 }

sub bulky_hide_later_dates { 1 }

sub _bulky_date_to_dt {
my ($self, $date) = @_;
$date = (split(";", $date))[0];
my $parser = DateTime::Format::Strptime->new( pattern => '%FT%T', time_zone => FixMyStreet->local_time_zone);
my $dt = $parser->parse_datetime($date);
return $dt ? $dt->truncate( to => 'day' ) : undef;
}

=head2 Sending to Echo

We use the reserved slot GUID and reference,
and the provided date/location information.
Items are sent through with their notes as individual entries

=cut

sub waste_munge_bulky_data {
my ($self, $data) = @_;

my $c = $self->{c};
my ($date, $ref, $expiry) = split(";", $data->{chosen_date});

my $guid_key = $self->council_url . ":echo:bulky_event_guid:" . $c->stash->{property}->{id};
$data->{extra_GUID} = $self->{c}->session->{$guid_key};
$data->{extra_reservation} = $ref;

$data->{title} = "Bulky goods collection";
$data->{detail} = "Address: " . $c->stash->{property}->{address};
$data->{category} = "Bulky collection";
$data->{extra_Collection_Date} = $date;
$data->{extra_Exact_Location} = $data->{location};

my $first_date = $self->{c}->session->{first_date_returned};
$first_date = DateTime::Format::W3CDTF->parse_datetime($first_date);
my $dt = DateTime::Format::W3CDTF->parse_datetime($date);
$data->{'extra_First_Date_Returned_to_Customer'} = $first_date->strftime("%d/%m/%Y");
$data->{'extra_Customer_Selected_Date_Beyond_SLA?'} = $dt > $first_date ? 1 : 0;

my @items_list = @{ $self->bulky_items_master_list };
my %items = map { $_->{name} => $_->{bartec_id} } @items_list;

my @notes;
my @ids;
my @photos;

my $max = $self->bulky_items_maximum;
for (1..$max) {
if (my $item = $data->{"item_$_"}) {
push @notes, $data->{"item_notes_$_"} || '';
push @ids, $items{$item};
push @photos, $data->{"item_photos_$_"} || '';
};
}
$data->{extra_Bulky_Collection_Notes} = join("::", @notes);
$data->{extra_Bulky_Collection_Bulky_Items} = join("::", @ids);
$data->{extra_Image} = join("::", @photos);
$self->bulky_total_cost($data);
}

sub waste_reconstruct_bulky_data {
my ($self, $p) = @_;

my $saved_data = {
"chosen_date" => $p->get_extra_field_value('Collection_Date'),
"location" => $p->get_extra_field_value('Exact_Location'),
"location_photo" => $p->get_extra_metadata("location_photo"),
};

my @fields = split /::/, $p->get_extra_field_value('Bulky_Collection_Bulky_Items');
my @notes = split /::/, $p->get_extra_field_value('Bulky_Collection_Notes');
for my $id (1..@fields) {
$saved_data->{"item_$id"} = $p->get_extra_metadata("item_$id");
$saved_data->{"item_notes_$id"} = $notes[$id-1];
$saved_data->{"item_photo_$id"} = $p->get_extra_metadata("item_photo_$id");
}

$saved_data->{name} = $p->name;
$saved_data->{email} = $p->user->email;
$saved_data->{phone} = $p->phone_waste;

return $saved_data;
}

=head2 suppress_report_sent_email

For Bulky Waste reports, we want to send the email after payment has been confirmed, so we
suppress the email here.

=cut

sub suppress_report_sent_email {
my ($self, $report) = @_;

if ($report->cobrand_data eq 'waste' && $report->category eq 'Bulky collection') {
return 1;
}

return 0;
}

sub bulky_location_photo_prompt {
'Help us by attaching a photo of where the items will be left for collection.';
}

1;