aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Somerville <matthew@mysociety.org>2020-06-29 16:07:52 +0100
committerM Somerville <matthew-github@dracos.co.uk>2020-11-11 10:29:05 +0000
commitdbde76a5090e772c806bd189426ee078b9b7e4ba (patch)
treef15015485554b852865e2388063a6942940f8340
parentce1b3ec61fdaa954c26e55b8ce8cd1ad619b3538 (diff)
[Bromley] Add waste reporting service.
This creates a non-map property-based reporting flow for reporting missed collections and requesting new containers. Such reports are always private, in categories that are hidden from the map filters and never shown on .com.
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Waste.pm263
-rw-r--r--perllib/FixMyStreet/App/Form/Page/Waste.pm11
-rw-r--r--perllib/FixMyStreet/App/Form/Waste.pm52
-rw-r--r--perllib/FixMyStreet/App/Form/Waste/AboutYou.pm38
-rw-r--r--perllib/FixMyStreet/App/Form/Waste/Report.pm65
-rw-r--r--perllib/FixMyStreet/App/Form/Waste/Request.pm64
-rw-r--r--perllib/FixMyStreet/Cobrand/Bromley.pm50
-rw-r--r--perllib/FixMyStreet/Cobrand/FixMyStreet.pm20
-rw-r--r--t/app/controller/waste.t85
-rw-r--r--t/cobrand/bromley.t7
-rw-r--r--templates/web/base/waste/confirmation.html34
-rw-r--r--templates/web/base/waste/index.html3
-rw-r--r--templates/web/base/waste/summary.html70
-rw-r--r--templates/web/base/waste/summary_report.html19
-rw-r--r--templates/web/base/waste/summary_request.html20
-rw-r--r--templates/web/bromley/waste/services.html14
17 files changed, 809 insertions, 8 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 3b42085ff..98ebd4972 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -1140,7 +1140,7 @@ sub process_report : Private {
# save the cobrand and language related information
$report->cobrand( $c->cobrand->moniker );
- $report->cobrand_data( '' );
+ $report->cobrand_data( $c->stash->{cobrand_data} || '' );
$report->lang( $c->stash->{lang_code} );
return 1;
diff --git a/perllib/FixMyStreet/App/Controller/Waste.pm b/perllib/FixMyStreet/App/Controller/Waste.pm
index 6319b5f22..667edad10 100644
--- a/perllib/FixMyStreet/App/Controller/Waste.pm
+++ b/perllib/FixMyStreet/App/Controller/Waste.pm
@@ -5,7 +5,11 @@ use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller' }
use utf8;
+use Lingua::EN::Inflect qw( NUMWORDS );
use FixMyStreet::App::Form::Waste::UPRN;
+use FixMyStreet::App::Form::Waste::AboutYou;
+use FixMyStreet::App::Form::Waste::Request;
+use FixMyStreet::App::Form::Waste::Report;
sub auto : Private {
my ( $self, $c ) = @_;
@@ -55,6 +59,9 @@ sub address_list_form {
sub redirect_to_uprn : Private {
my ($self, $c, $uprn) = @_;
my $uri = '/waste/uprn/' . $uprn;
+ my $type = $c->get_param('type') || '';
+ $uri .= '/request' if $type eq 'request';
+ $uri .= '/report' if $type eq 'report';
$c->res->redirect($uri);
$c->detach;
}
@@ -84,6 +91,262 @@ sub bin_days : Chained('uprn') : PathPart('') : Args(0) {
my ($self, $c) = @_;
}
+sub construct_bin_request_form {
+ my $c = shift;
+
+ my $field_list = [];
+
+ foreach (@{$c->stash->{service_data}}) {
+ next unless $_->{next};
+ my $name = $_->{service_name};
+ my $containers = $_->{request_containers};
+ my $max = $_->{request_max};
+ foreach my $id (@$containers) {
+ push @$field_list, "container-$id" => {
+ type => 'Checkbox',
+ apply => [
+ {
+ when => { "quantity-$id" => sub { $_[0] > 0 } },
+ check => qr/^1$/,
+ message => 'Please tick the box',
+ },
+ ],
+ label => $name,
+ option_label => $c->stash->{containers}->{$id},
+ tags => { toggle => "form-quantity-$id-row" },
+ };
+ $name = ''; # Only on first container
+ push @$field_list, "quantity-$id" => {
+ type => 'Select',
+ label => 'Quantity',
+ tags => {
+ hint => "You can request a maximum of " . NUMWORDS($max) . " containers",
+ initial_hidden => 1,
+ },
+ options => [
+ { value => "", label => '-' },
+ map { { value => $_, label => $_ } } (1..$max),
+ ],
+ required_when => { "container-$id" => 1 },
+ };
+ }
+ }
+
+ return $field_list;
+}
+
+sub request : Chained('uprn') : Args(0) {
+ my ($self, $c) = @_;
+
+ my $field_list = construct_bin_request_form($c);
+
+ $c->stash->{first_page} = 'request';
+ $c->stash->{form_class} = 'FixMyStreet::App::Form::Waste::Request';
+ $c->stash->{page_list} = [
+ request => {
+ fields => [ grep { ! ref $_ } @$field_list, 'submit' ],
+ title => 'Which containers do you need?',
+ next => 'about_you',
+ },
+ ];
+ $c->stash->{field_list} = $field_list;
+ $c->forward('form');
+}
+
+sub process_request_data : Private {
+ my ($self, $c, $form) = @_;
+ my $data = $form->saved_data;
+ my $address = $c->stash->{property}->{address};
+ my @services = grep { /^container-/ && $data->{$_} } keys %$data;
+ foreach (@services) {
+ my ($id) = /container-(.*)/;
+ my $container = $c->stash->{containers}{$id};
+ my $quantity = $data->{"quantity-$id"};
+ $data->{title} = "Request new $container";
+ $data->{detail} = "Quantity: $quantity\n\n$address";
+ $c->set_param('Container_Type', $id);
+ $c->set_param('Quantity', $quantity);
+ $c->forward('add_report', [ $data ]) or return;
+ push @{$c->stash->{report_ids}}, $c->stash->{report}->id;
+ }
+ return 1;
+}
+
+sub construct_bin_report_form {
+ my $c = shift;
+
+ my $field_list = [];
+
+ foreach (@{$c->stash->{service_data}}) {
+ next unless $_->{last};
+ my $id = $_->{service_id};
+ my $name = $_->{service_name};
+ push @$field_list, "service-$id" => {
+ type => 'Checkbox',
+ label => $name,
+ option_label => $name,
+ };
+ }
+
+ return $field_list;
+}
+
+sub report : Chained('uprn') : Args(0) {
+ my ($self, $c) = @_;
+
+ my $field_list = construct_bin_report_form($c);
+
+ $c->stash->{first_page} = 'report';
+ $c->stash->{form_class} = 'FixMyStreet::App::Form::Waste::Report';
+ $c->stash->{page_list} = [
+ report => {
+ fields => [ grep { ! ref $_ } @$field_list, 'submit' ],
+ title => 'Select your missed collection',
+ next => 'about_you',
+ },
+ ];
+ $c->stash->{field_list} = $field_list;
+ $c->forward('form');
+}
+
+sub process_report_data : Private {
+ my ($self, $c, $form) = @_;
+ my $data = $form->saved_data;
+ my $address = $c->stash->{property}->{address};
+ my @services = grep { /^service-/ && $data->{$_} } keys %$data;
+ foreach (@services) {
+ my ($id) = /service-(.*)/;
+ my $service = $c->stash->{services}{$id}{service_name};
+ $data->{title} = "Report missed $service";
+ $data->{detail} = "$data->{title}\n\n$address";
+ $c->set_param('service_id', $id);
+ $c->forward('add_report', [ $data ]) or return;
+ push @{$c->stash->{report_ids}}, $c->stash->{report}->id;
+ }
+ return 1;
+}
+
+sub load_form {
+ my ($c, $previous_form) = @_;
+
+ my $page;
+ if ($previous_form) {
+ $page = $previous_form->next;
+ } else {
+ $page = $c->forward('get_page');
+ }
+
+ my $form = $c->stash->{form_class}->new(
+ page_list => $c->stash->{page_list},
+ $c->stash->{field_list} ? (field_list => $c->stash->{field_list}) : (),
+ page_name => $page,
+ csrf_token => $c->stash->{csrf_token},
+ c => $c,
+ previous_form => $previous_form,
+ saved_data_encoded => $c->get_param('saved_data'),
+ no_preload => 1,
+ );
+
+ if (!$form->has_current_page) {
+ $c->detach('/page_error_400_bad_request', [ 'Bad request' ]);
+ }
+
+ return $form;
+}
+
+sub form : Private {
+ my ($self, $c) = @_;
+
+ my $form = load_form($c);
+ if ($c->get_param('process')) {
+ $c->forward('/auth/check_csrf_token');
+ $form->process(params => $c->req->body_params);
+ if ($form->validated) {
+ $form = load_form($c, $form);
+ }
+ }
+
+ $form->process unless $form->processed;
+
+ $c->stash->{template} = $form->template || 'waste/index.html';
+ $c->stash->{form} = $form;
+}
+
+sub get_page : Private {
+ my ($self, $c) = @_;
+
+ my $goto = $c->get_param('goto') || '';
+ my $process = $c->get_param('process') || '';
+ $goto = $c->stash->{first_page} unless $goto || $process;
+ if ($goto && $process) {
+ $c->detach('/page_error_400_bad_request', [ 'Bad request' ]);
+ }
+
+ return $goto || $process;
+}
+
+sub add_report : Private {
+ my ( $self, $c, $data ) = @_;
+
+ $c->stash->{cobrand_data} = 'waste';
+
+ # XXX Is this best way to do this?
+ if ($c->user_exists && $c->user->from_body && $c->user->email ne $data->{email}) {
+ $c->set_param('form_as', 'another_user');
+ $c->set_param('username', $data->{email} || $data->{phone});
+ } else {
+ $c->set_param('username_register', $data->{email} || $data->{phone});
+ }
+
+ # Set the data as if a new report form has been submitted
+
+ $c->set_param('submit_problem', 1);
+ $c->set_param('pc', '');
+ $c->set_param('non_public', 1);
+
+ $c->set_param('name', $data->{name});
+ $c->set_param('phone', $data->{phone});
+
+ $c->set_param('category', $data->{category});
+ $c->set_param('title', $data->{title});
+ $c->set_param('detail', $data->{detail});
+ $c->set_param('uprn', $c->stash->{uprn});
+
+ $c->forward('setup_categories_and_bodies') unless $c->stash->{contacts};
+ $c->forward('/report/new/non_map_creation', [['/waste/remove_name_errors']]) or return;
+ my $report = $c->stash->{report};
+ $report->confirm;
+ $report->update;
+
+ $c->model('DB::Alert')->find_or_create({
+ user => $report->user,
+ alert_type => 'new_updates',
+ parameter => $report->id,
+ cobrand => $report->cobrand,
+ lang => $report->lang,
+ })->confirm;
+
+ return 1;
+}
+
+sub remove_name_errors : Private {
+ my ($self, $c) = @_;
+ # We do not mind about missing title/split name here
+ my $field_errors = $c->stash->{field_errors};
+ delete $field_errors->{fms_extra_title};
+ delete $field_errors->{first_name};
+ delete $field_errors->{last_name};
+}
+
+sub setup_categories_and_bodies : Private {
+ my ($self, $c) = @_;
+
+ $c->stash->{all_areas} = $c->stash->{all_areas_mapit} = { $c->cobrand->council_area_id => { id => $c->cobrand->council_area_id } };
+ $c->forward('/report/new/setup_categories_and_bodies');
+ my $contacts = $c->stash->{contacts};
+ @$contacts = grep { grep { $_ eq 'Waste' } @{$_->groups} } @$contacts;
+}
+
__PACKAGE__->meta->make_immutable;
1;
diff --git a/perllib/FixMyStreet/App/Form/Page/Waste.pm b/perllib/FixMyStreet/App/Form/Page/Waste.pm
new file mode 100644
index 000000000..5275cae7f
--- /dev/null
+++ b/perllib/FixMyStreet/App/Form/Page/Waste.pm
@@ -0,0 +1,11 @@
+package FixMyStreet::App::Form::Page::Waste;
+use Moose;
+extends 'FixMyStreet::App::Form::Page::Simple';
+
+# Title to use for this page
+has title => ( is => 'ro', isa => 'Str' );
+
+# Special template to use in preference to the default
+has template => ( is => 'ro', isa => 'Str' );
+
+1;
diff --git a/perllib/FixMyStreet/App/Form/Waste.pm b/perllib/FixMyStreet/App/Form/Waste.pm
new file mode 100644
index 000000000..c430506c7
--- /dev/null
+++ b/perllib/FixMyStreet/App/Form/Waste.pm
@@ -0,0 +1,52 @@
+package FixMyStreet::App::Form::Waste;
+
+use HTML::FormHandler::Moose;
+extends 'FixMyStreet::App::Form::Wizard';
+
+has c => ( is => 'ro' );
+
+has default_page_type => ( is => 'ro', isa => 'Str', default => 'Waste' );
+
+has finished_action => ( is => 'ro' );
+
+before _process_page_array => sub {
+ my ($self, $pages) = @_;
+ foreach my $page (@$pages) {
+ $page->{type} = $self->default_page_type
+ unless $page->{type};
+ }
+};
+
+# Add some functions to the form to pass through to the current page
+has '+current_page' => (
+ handles => {
+ title => 'title',
+ template => 'template',
+ }
+);
+
+sub wizard_finished {
+ my ($form, $action) = @_;
+ my $c = $form->c;
+ my $success = $c->forward($action, [ $form ]);
+ if (!$success) {
+ $form->add_form_error('Something went wrong, please try again');
+ foreach (keys %{$c->stash->{field_errors}}) {
+ $form->add_form_error("$_: " . $c->stash->{field_errors}{$_});
+ }
+ }
+ return $success;
+}
+
+# Make sure we can have pre-ticked things on the first page
+before after_build => sub {
+ my $self = shift;
+
+ my $saved_data = $self->previous_form ? $self->previous_form->saved_data : $self->saved_data;
+
+ my $c = $self->c;
+
+ map { $saved_data->{$_} = 1 } grep { /^(service|container)-/ && $c->req->params->{$_} } keys %{$c->req->params};
+};
+
+1;
diff --git a/perllib/FixMyStreet/App/Form/Waste/AboutYou.pm b/perllib/FixMyStreet/App/Form/Waste/AboutYou.pm
new file mode 100644
index 000000000..d5bb3df2b
--- /dev/null
+++ b/perllib/FixMyStreet/App/Form/Waste/AboutYou.pm
@@ -0,0 +1,38 @@
+package FixMyStreet::App::Form::Waste::AboutYou;
+
+use utf8;
+use HTML::FormHandler::Moose::Role;
+use FixMyStreet::SMS;
+
+has_field name => (
+ type => 'Text',
+ label => 'Your name',
+ required => 1,
+ validate_method => sub {
+ my $self = shift;
+ $self->add_error('Please enter your full name.')
+ if length($self->value) < 5
+ || $self->value !~ m/\s/
+ || $self->value =~ m/\ba\s*n+on+((y|o)mo?u?s)?(ly)?\b/i;
+ },
+);
+
+has_field phone => (
+ type => 'Text',
+ label => 'Telephone number',
+ validate_method => sub {
+ my $self = shift;
+ my $parsed = FixMyStreet::SMS->parse_username($self->value);
+ $self->add_error('Please provide a valid phone number')
+ unless $parsed->{phone};
+ }
+);
+
+has_field email => (
+ type => 'Email',
+ tags => {
+ hint => 'If you provide an email address, we can send you order status updates'
+ },
+);
+
+1;
diff --git a/perllib/FixMyStreet/App/Form/Waste/Report.pm b/perllib/FixMyStreet/App/Form/Waste/Report.pm
new file mode 100644
index 000000000..589e75d48
--- /dev/null
+++ b/perllib/FixMyStreet/App/Form/Waste/Report.pm
@@ -0,0 +1,65 @@
+package FixMyStreet::App::Form::Waste::Report;
+
+use utf8;
+use HTML::FormHandler::Moose;
+extends 'FixMyStreet::App::Form::Waste';
+
+# First page has dynamic fields, so is set in code
+
+has_page about_you => (
+ fields => ['name', 'email', 'phone', 'continue'],
+ title => 'About you',
+ next => 'summary',
+);
+
+with 'FixMyStreet::App::Form::Waste::AboutYou';
+
+has_page summary => (
+ fields => ['submit'],
+ title => 'Submit missed collection',
+ template => 'waste/summary_report.html',
+ finished => sub {
+ return $_[0]->wizard_finished('process_report_data');
+ },
+ next => 'done',
+);
+
+has_page done => (
+ title => 'Missed collection sent',
+ template => 'waste/confirmation.html',
+);
+
+has_field category => (
+ type => 'Hidden',
+ default => 'Report missed collection'
+);
+
+has_field continue => (
+ type => 'Submit',
+ value => 'Continue',
+ element_attr => { class => 'govuk-button' },
+);
+
+has_field submit => (
+ type => 'Submit',
+ value => 'Report collection as missed',
+ element_attr => { class => 'govuk-button' },
+ order => 999,
+);
+
+sub validate {
+ my $self = shift;
+ my $any = 0;
+
+ foreach ($self->all_fields) {
+ $any = 1 if $_->name =~ /^service-/ && ($_->value || $self->saved_data->{$_->name});
+ }
+ $self->add_form_error('Please specify what was missed')
+ unless $any;
+
+ $self->add_form_error('Please specify at least one of phone or email')
+ unless $self->field('phone')->is_inactive || $self->field('phone')->value || $self->field('email')->value;
+}
+
+1;
+
diff --git a/perllib/FixMyStreet/App/Form/Waste/Request.pm b/perllib/FixMyStreet/App/Form/Waste/Request.pm
new file mode 100644
index 000000000..e7caaa206
--- /dev/null
+++ b/perllib/FixMyStreet/App/Form/Waste/Request.pm
@@ -0,0 +1,64 @@
+package FixMyStreet::App::Form::Waste::Request;
+
+use utf8;
+use HTML::FormHandler::Moose;
+extends 'FixMyStreet::App::Form::Waste';
+
+# First page has dynamic fields, so is set in code
+
+has_page about_you => (
+ fields => ['name', 'email', 'phone', 'continue'],
+ title => 'About you',
+ next => 'summary',
+);
+
+with 'FixMyStreet::App::Form::Waste::AboutYou';
+
+has_page summary => (
+ fields => ['submit'],
+ title => 'Submit container request',
+ template => 'waste/summary_request.html',
+ finished => sub {
+ return $_[0]->wizard_finished('process_request_data');
+ },
+ next => 'done',
+);
+
+has_page done => (
+ title => 'Container request sent',
+ template => 'waste/confirmation.html',
+);
+
+has_field category => (
+ type => 'Hidden',
+ default => 'Request new container',
+);
+
+has_field continue => (
+ type => 'Submit',
+ value => 'Continue',
+ element_attr => { class => 'govuk-button' },
+);
+
+has_field submit => (
+ type => 'Submit',
+ value => 'Request new containers',
+ element_attr => { class => 'govuk-button' },
+ order => 999,
+);
+
+sub validate {
+ my $self = shift;
+ my $any = 0;
+
+ foreach ($self->all_fields) {
+ $any = 1 if $_->name =~ /^container-/ && ($_->value || $self->saved_data->{$_->name});
+ }
+ $self->add_form_error('Please specify what you need')
+ unless $any;
+
+ $self->add_form_error('Please specify at least one of phone or email')
+ unless $self->field('phone')->is_inactive || $self->field('phone')->value || $self->field('email')->value;
+}
+
+1;
diff --git a/perllib/FixMyStreet/Cobrand/Bromley.pm b/perllib/FixMyStreet/Cobrand/Bromley.pm
index e4e509f77..6441180e3 100644
--- a/perllib/FixMyStreet/Cobrand/Bromley.pm
+++ b/perllib/FixMyStreet/Cobrand/Bromley.pm
@@ -378,6 +378,25 @@ sub munge_load_and_group_problems {
}
}
+sub munge_around_category_where {
+ my ($self, $where) = @_;
+ $where->{extra} = [ undef, { -not_like => '%Waste%' } ];
+}
+
+sub munge_reports_category_list {
+ my ($self, $categories) = @_;
+ @$categories = grep { grep { $_ ne 'Waste' } @{$_->groups} } @$categories;
+}
+
+sub munge_report_new_contacts {
+ my ($self, $categories) = @_;
+
+ return if $self->{c}->action =~ /^waste/;
+
+ @$categories = grep { grep { $_ ne 'Waste' } @{$_->groups} } @$categories;
+ $self->SUPER::munge_report_new_contacts($categories);
+}
+
sub bin_addresses_for_postcode {
my $self = shift;
my $pc = shift;
@@ -442,6 +461,33 @@ sub bin_services_for_address {
545 => 'Garden Waste',
);
+ $self->{c}->stash->{containers} = {
+ 1 => 'Green Box (Plastic)',
+ 2 => 'Wheeled Bin (Plastic)',
+ 12 => 'Black Box (Paper)',
+ 13 => 'Wheeled Bin (Paper)',
+ 9 => 'Kitchen Caddy',
+ 10 => 'Outside Food Waste Container',
+ 45 => 'Wheeled Bin (Food)',
+ };
+ my %service_to_containers = (
+ 535 => [ 1 ],
+ 536 => [ 2 ],
+ 537 => [ 12 ],
+ 541 => [ 13 ],
+ 542 => [ 9, 10 ],
+ 544 => [ 45 ],
+ );
+ my %request_allowed = map { $_ => 1 } keys %service_to_containers;
+ my %quantity_max = (
+ 535 => 6,
+ 536 => 4,
+ 537 => 6,
+ 541 => 4,
+ 542 => 6,
+ 544 => 4,
+ );
+
my $echo = $self->feature('echo');
$echo = Integrations::Echo->new(%$echo);
my $result = $echo->GetServiceUnitsForObject($property->{uprn});
@@ -456,10 +502,14 @@ sub bin_services_for_address {
next unless $schedules->{next} or $schedules->{last};
+ my $containers = $service_to_containers{$_->{ServiceId}};
my $row = {
id => $_->{Id},
service_id => $_->{ServiceId},
service_name => $service_name_override{$_->{ServiceId}} || $_->{ServiceName},
+ request_allowed => $request_allowed{$_->{ServiceId}},
+ request_containers => $containers,
+ request_max => $quantity_max{$_->{ServiceId}},
service_task_id => $servicetask->{Id},
service_task_name => $servicetask->{TaskTypeName},
service_task_type_id => $servicetask->{TaskTypeId},
diff --git a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
index 7344a0f5e..ae96924d8 100644
--- a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
+++ b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
@@ -35,15 +35,19 @@ sub restriction {
return {};
}
-# FixMyStreet needs to not show TfL reports...
+# FixMyStreet needs to not show TfL reports or Bromley waste reports
sub problems_restriction {
my ($self, $rs) = @_;
my $table = ref $rs eq 'FixMyStreet::DB::ResultSet::Nearby' ? 'problem' : 'me';
- return $rs->search({ "$table.cobrand" => { '!=' => 'tfl' } });
+ return $rs->search({
+ "$table.cobrand" => { '!=' => 'tfl' },
+ "$table.cobrand_data" => { '!=' => 'waste' },
+ });
}
sub problems_sql_restriction {
my $self = shift;
return "AND cobrand != 'tfl'";
+ # Doesn't need Bromley one as all waste reports non-public
}
sub relative_url_for_report {
@@ -61,6 +65,10 @@ sub munge_around_category_where {
# can't determine the body
$where->{send_method} = [ { '!=' => 'Triage' }, undef ];
}
+ my $bromley = grep { $_->name eq 'Bromley Council' } @{ $self->{c}->stash->{around_bodies} };
+ if ($bromley) {
+ $where->{extra} = [ undef, { -not_like => '%Waste%' } ];
+ }
}
sub _iow_category_munge {
@@ -75,13 +83,16 @@ sub _iow_category_munge {
@$categories = grep { $_->send_method && $_->send_method eq 'Triage' } @$categories;
}
-sub munge_reports_categories_list {
+sub munge_reports_category_list {
my ($self, $categories) = @_;
my %bodies = map { $_->body->name => $_->body } @$categories;
if ( my $body = $bodies{'Isle of Wight Council'} ) {
return $self->_iow_category_munge($body, $categories);
}
+ if ( $bodies{'Bromley Council'} ) {
+ @$categories = grep { grep { $_ ne 'Waste' } @{$_->groups} } @$categories;
+ }
}
sub munge_reports_area_list {
@@ -122,6 +133,9 @@ sub munge_report_new_contacts {
if ( my $body = $bodies{'Isle of Wight Council'} ) {
return $self->_iow_category_munge($body, $contacts);
}
+ if ( $bodies{'Bromley Council'} ) {
+ @$contacts = grep { grep { $_ ne 'Waste' } @{$_->groups} } @$contacts;
+ }
if ( $bodies{'TfL'} ) {
# Presented categories vary if we're on/off a red route
my $tfl = FixMyStreet::Cobrand->get_class_for_moniker( 'tfl' )->new({ c => $self->{c} });
diff --git a/t/app/controller/waste.t b/t/app/controller/waste.t
index 77b1ef5bc..454a593a6 100644
--- a/t/app/controller/waste.t
+++ b/t/app/controller/waste.t
@@ -1,8 +1,35 @@
use Test::MockModule;
use FixMyStreet::TestMech;
+FixMyStreet::App->log->disable('info');
+END { FixMyStreet::App->log->enable('info'); }
+
my $mech = FixMyStreet::TestMech->new;
+my $body = $mech->create_body_ok(2482, 'Bromley Council');
+my $user = $mech->create_user_ok('test@example.net', name => 'Normal User');
+my $staff_user = $mech->create_user_ok('staff@example.org', from_body => $body, name => 'Staff User');
+$staff_user->user_body_permissions->create({ body => $body, permission_type => 'contribute_as_another_user' });
+$staff_user->user_body_permissions->create({ body => $body, permission_type => 'report_mark_private' });
+
+sub create_contact {
+ my ($params, @extra) = @_;
+ my $contact = $mech->create_contact_ok(body => $body, %$params);
+ $contact->set_extra_metadata(group => ['Waste']);
+ $contact->set_extra_fields(
+ { code => 'uprn', required => 1, automated => 'hidden_field' },
+ { code => 'service_id', required => 0, automated => 'hidden_field' },
+ @extra,
+ );
+ $contact->update;
+}
+
+create_contact({ category => 'Report missed collection', email => 'missed' });
+create_contact({ category => 'Request new container', email => 'request' },
+ { code => 'Quantity', required => 1, automated => 'hidden_field' },
+ { code => 'Container_Type', required => 1, automated => 'hidden_field' },
+);
+
FixMyStreet::override_config {
ALLOWED_COBRANDS => ['bromley', 'fixmystreet'],
COBRAND_FEATURES => { echo => { bromley => { sample_data => 1 } }, waste => { bromley => 1 } },
@@ -21,6 +48,64 @@ FixMyStreet::override_config {
$mech->content_contains('2 Example Street');
$mech->content_contains('Food Waste');
};
+ subtest 'Report a missed bin' => sub {
+ $mech->follow_link_ok({ text => 'Report a missed collection' });
+ $mech->submit_form_ok({ form_number => 2 });
+ $mech->content_contains('Please specify what was missed');
+ $mech->submit_form_ok({ with_fields => { 'service-101' => 1 } });
+ $mech->submit_form_ok({ with_fields => { name => "Test" } });
+ $mech->content_contains('Please enter your full name');
+ $mech->content_contains('Please specify at least one of phone or email');
+ $mech->submit_form_ok({ with_fields => { name => "Test McTest", email => 'test@example.org' } });
+ $mech->content_contains('Refuse collection');
+ $mech->content_contains('Test McTest');
+ $mech->content_contains('test@example.org');
+ $mech->submit_form_ok({ form_number => 3 });
+ $mech->submit_form_ok({ with_fields => { name => "Test McTest", email => $user->email } });
+ $mech->content_contains($user->email);
+ $mech->submit_form_ok({ with_fields => { process => 'summary' } });
+ $mech->content_contains('Your report has been sent');
+
+ is $user->alerts->count, 1;
+ };
+ subtest 'Check report visibility' => sub {
+ my $report = FixMyStreet::DB->resultset("Problem")->first;
+ my $res = $mech->get('/report/' . $report->id);
+ is $res->code, 403;
+ $mech->log_in_ok($user->email);
+ $mech->get_ok('/report/' . $report->id);
+ $mech->log_in_ok($staff_user->email);
+ $mech->get_ok('/report/' . $report->id);
+
+ $mech->host('www.fixmystreet.com');
+ $res = $mech->get('/report/' . $report->id);
+ is $res->code, 404;
+ $mech->log_in_ok($user->email);
+ $res = $mech->get('/report/' . $report->id);
+ is $res->code, 404;
+ $mech->log_in_ok($staff_user->email);
+ $res = $mech->get('/report/' . $report->id);
+ is $res->code, 404;
+ $mech->host('bromley.fixmystreet.com');
+ };
+ subtest 'Request a new container' => sub {
+ $mech->get_ok('/waste/uprn/1000000002/request');
+ $mech->submit_form_ok({ form_number => 2 });
+ $mech->content_contains('Please specify what you need');
+ $mech->submit_form_ok({ with_fields => { 'container-1' => 1 } });
+ $mech->content_contains('Quantity field is required');
+ $mech->submit_form_ok({ with_fields => { 'container-1' => 1, 'quantity-1' => 2 } });
+ $mech->submit_form_ok({ with_fields => { name => "Test McTest", email => $user->email } });
+ $mech->content_contains('Green Box');
+ $mech->content_contains('Test McTest');
+ $mech->content_contains($user->email);
+ $mech->submit_form_ok({ with_fields => { process => 'summary' } });
+ $mech->content_contains('Your request has been sent');
+ my $report = FixMyStreet::DB->resultset("Problem")->search(undef, { order_by => { -desc => 'id' } })->first;
+ is $report->get_extra_field_value('uprn'), 1000000002;
+ is $report->get_extra_field_value('Quantity'), 2;
+ is $report->get_extra_field_value('Container_Type'), 1;
+ };
};
package SOAP::Result;
diff --git a/t/cobrand/bromley.t b/t/cobrand/bromley.t
index d26b10709..f2b1c7a39 100644
--- a/t/cobrand/bromley.t
+++ b/t/cobrand/bromley.t
@@ -26,6 +26,10 @@ $mech->create_contact_ok(
email => 'tfl@example.org',
);
+my $waste = $mech->create_contact_ok(body => $body, category => 'Report missed collection', email => 'missed');
+$waste->set_extra_metadata(group => ['Waste']);
+$waste->update;
+
my @reports = $mech->create_problems_for_body( 1, $body->id, 'Test', {
latitude => 51.402096,
longitude => 0.015784,
@@ -177,7 +181,7 @@ for my $test (
};
}
-subtest 'check display of TfL reports' => sub {
+subtest 'check display of TfL and waste reports' => sub {
$mech->create_problems_for_body( 1, $tfl->id, 'TfL Test', {
latitude => 51.402096,
longitude => 0.015784,
@@ -193,6 +197,7 @@ subtest 'check display of TfL reports' => sub {
};
$mech->content_like(qr{<a title="TfL Test[^>]*www.example.org[^>]*><img[^>]*grey});
$mech->content_like(qr{<a title="Test Test[^>]*href="/[^>]*><img[^>]*yellow});
+ $mech->content_lacks('Report missed collection');
};
subtest 'check geolocation overrides' => sub {
diff --git a/templates/web/base/waste/confirmation.html b/templates/web/base/waste/confirmation.html
new file mode 100644
index 000000000..9bacd9a2b
--- /dev/null
+++ b/templates/web/base/waste/confirmation.html
@@ -0,0 +1,34 @@
+[%
+IF first_page == 'request';
+ title = 'Container request sent';
+ELSIF first_page == 'report';
+ title = 'Missed collection reported';
+ELSE;
+ title = 'Enquiry submitted';
+END ~%]
+[% INCLUDE header.html %]
+
+<div class="govuk-panel govuk-panel--confirmation">
+ <h1 class="govuk-panel__title">
+ [% title %]
+ </h1>
+ <div class="govuk-panel__body">
+ <p>Your [% first_page %] has been sent;
+ [% IF data.email %]
+ a copy has been sent to your email address, [% data.email %].
+ [% END %]
+ </p>
+ <p>
+ [% IF first_page == 'request' %]
+ Containers arrive typically within two weeks, but this may vary due to demand.
+ [% END %]
+ [% IF report_ids.size > 1 %]
+ Your reference numbers are: <strong>[% report_ids.join(', ') %]</strong>.
+ [% ELSE %]
+ Your reference number is <strong>[% report_ids.join(', ') %]</strong>.
+ [% END %]
+ </p>
+ </div>
+</div>
+
+[% INCLUDE footer.html %]
diff --git a/templates/web/base/waste/index.html b/templates/web/base/waste/index.html
index 8e02c5b71..0750ac82a 100644
--- a/templates/web/base/waste/index.html
+++ b/templates/web/base/waste/index.html
@@ -14,9 +14,6 @@
[% END %]
<form method="post">
[% PROCESS form %]
- <input type="hidden" name="token" value="[% csrf_token %]">
- <input type="hidden" name="process" value="[% process %]">
- <input type="hidden" name="saved_data" value="[% saved_data %]">
</form>
[% INCLUDE footer.html %]
diff --git a/templates/web/base/waste/summary.html b/templates/web/base/waste/summary.html
new file mode 100644
index 000000000..7fa79b05b
--- /dev/null
+++ b/templates/web/base/waste/summary.html
@@ -0,0 +1,70 @@
+[% SET bodyclass = 'waste' %]
+
+[% USE date(format = '%A, %-d~~~ %B') ~%]
+[% PROCESS 'waste/govuk/fields.html' ~%]
+[% INCLUDE header.html %]
+
+[% PROCESS errors %]
+[% SET data = form.saved_data ~%]
+
+<h1 class="govuk-heading-xl">[% title %]</h1>
+<p>Please review the information you’ve provided before you submit your [% thing %].</p>
+
+<div class="waste__summary">
+<dl class="govuk-summary-list">
+ <div class="govuk-summary-list__row">
+ <dt class="govuk-summary-list__key">
+ [% summary_title %]
+ </dt>
+ <dd class="govuk-summary-list__value">
+ </dd>
+ <dd class="govuk-summary-list__actions">
+ <form method="post">
+ <input type="hidden" name="saved_data" value="[% form.fif.saved_data %]">
+ <input type="hidden" name="goto" value="[% step1 %]">
+ <input type="submit" class="govuk-button govuk-button--secondary govuk-!-margin-bottom-0" value="Change answers">
+ </form>
+ </dd>
+ </div>
+ <div class="govuk-summary-list__row">
+ <dt class="govuk-summary-list__key govuk-summary-list__key--sub">Address</dt>
+ <dd class="govuk-summary-list__value">[% property.address %]</dd>
+ </div>
+ [% INCLUDE answers %]
+
+ <div class="govuk-summary-list__row">
+ <dt class="govuk-summary-list__key">
+ About you
+ </dt>
+ <dd class="govuk-summary-list__value">
+ </dd>
+ <dd class="govuk-summary-list__actions">
+ <form method="post">
+ <input type="hidden" name="saved_data" value="[% form.fif.saved_data %]">
+ <input type="hidden" name="goto" value="about_you">
+ <input type="submit" class="govuk-button govuk-button--secondary govuk-!-margin-bottom-0" value="Change answers">
+ </form>
+ </dd>
+ </div>
+
+ <div class="govuk-summary-list__row">
+ <dt class="govuk-summary-list__key govuk-summary-list__key--sub">Your name</dt>
+ <dd class="govuk-summary-list__value">[% data.name %]</dd>
+ </div>
+ <div class="govuk-summary-list__row">
+ <dt class="govuk-summary-list__key govuk-summary-list__key--sub">Telephone number</dt>
+ <dd class="govuk-summary-list__value">[% data.phone %]</dd>
+ </div>
+ <div class="govuk-summary-list__row">
+ <dt class="govuk-summary-list__key govuk-summary-list__key--sub">Email</dt>
+ <dd class="govuk-summary-list__value">[% data.email %]</dd>
+ </div>
+
+</dl>
+
+<form method="post">
+ [% PROCESS form %]
+</form>
+</div>
+
+[% INCLUDE footer.html %]
diff --git a/templates/web/base/waste/summary_report.html b/templates/web/base/waste/summary_report.html
new file mode 100644
index 000000000..a67090e6e
--- /dev/null
+++ b/templates/web/base/waste/summary_report.html
@@ -0,0 +1,19 @@
+[%
+title = 'Submit missed bin report';
+thing = 'missed bin report';
+summary_title = 'Missed collection';
+step1 = 'report';
+%]
+
+[% BLOCK answers %]
+ [% FOR service IN data.keys.grep('^service-') %]
+ [% NEXT UNLESS data.$service %]
+ [% SET service_id = service.replace('service-', '') %]
+ <div class="govuk-summary-list__row">
+ <dt class="govuk-summary-list__key govuk-summary-list__key--sub">[% services.$service_id.service_name %]</dt>
+ <dd class="govuk-summary-list__value">[% date.format(services.$service_id.last.date) | replace('~~~', services.$service_id.last.ordinal) %]</dd>
+ </div>
+ [% END %]
+[% END %]
+
+[% PROCESS waste/summary.html %]
diff --git a/templates/web/base/waste/summary_request.html b/templates/web/base/waste/summary_request.html
new file mode 100644
index 000000000..83c4091aa
--- /dev/null
+++ b/templates/web/base/waste/summary_request.html
@@ -0,0 +1,20 @@
+[%
+title = 'Submit container request';
+thing = 'container request';
+summary_title = 'Container requests';
+step1 = 'request';
+%]
+
+[% BLOCK answers %]
+ [% FOR container IN data.keys.grep('^container-') %]
+ [% NEXT UNLESS data.$container %]
+ [% SET container_id = container.replace('container-', '') %]
+ [% SET quantity_key = container.replace('container-', 'quantity-') %]
+ <div class="govuk-summary-list__row">
+ <dt class="govuk-summary-list__key govuk-summary-list__key--sub">[% containers.$container_id %]</dt>
+ <dd class="govuk-summary-list__value">[% data.$quantity_key %]</dd>
+ </div>
+ [% END %]
+[% END %]
+
+[% PROCESS waste/summary.html %]
diff --git a/templates/web/bromley/waste/services.html b/templates/web/bromley/waste/services.html
index e69de29bb..2f683ab2f 100644
--- a/templates/web/bromley/waste/services.html
+++ b/templates/web/bromley/waste/services.html
@@ -0,0 +1,14 @@
+ [% any_report_allowed = 1 %]
+ <form method="post" action="[% c.uri_for_action('waste/report', [ uprn ]) %]">
+ <input type="hidden" name="token" value="[% csrf_token %]">
+ <input type="hidden" name="service-[% unit.service_id %]" value="1">
+ <input type="submit" value="Report a [% unit.service_name FILTER lower %] collection as missed" class="waste-service-descriptor waste-service-link">
+ </form>
+[% IF unit.request_allowed %]
+ [% any_request_allowed = 1 %]
+ <form method="post" action="[% c.uri_for_action('waste/request', [ uprn ]) %]">
+ <input type="hidden" name="token" value="[% csrf_token %]">
+ <input type="hidden" name="container-[% unit.request_containers.0 %]" value="1">
+ <input type="submit" value="Request a new [% unit.service_name FILTER lower %] container" class="waste-service-descriptor waste-service-link">
+ </form>
+[% END %]