diff options
author | Matthew Somerville <matthew@mysociety.org> | 2020-06-29 16:07:52 +0100 |
---|---|---|
committer | M Somerville <matthew-github@dracos.co.uk> | 2020-11-11 10:29:05 +0000 |
commit | dbde76a5090e772c806bd189426ee078b9b7e4ba (patch) | |
tree | f15015485554b852865e2388063a6942940f8340 | |
parent | ce1b3ec61fdaa954c26e55b8ce8cd1ad619b3538 (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.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Waste.pm | 263 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Form/Page/Waste.pm | 11 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Form/Waste.pm | 52 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Form/Waste/AboutYou.pm | 38 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Form/Waste/Report.pm | 65 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Form/Waste/Request.pm | 64 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Bromley.pm | 50 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/FixMyStreet.pm | 20 | ||||
-rw-r--r-- | t/app/controller/waste.t | 85 | ||||
-rw-r--r-- | t/cobrand/bromley.t | 7 | ||||
-rw-r--r-- | templates/web/base/waste/confirmation.html | 34 | ||||
-rw-r--r-- | templates/web/base/waste/index.html | 3 | ||||
-rw-r--r-- | templates/web/base/waste/summary.html | 70 | ||||
-rw-r--r-- | templates/web/base/waste/summary_report.html | 19 | ||||
-rw-r--r-- | templates/web/base/waste/summary_request.html | 20 | ||||
-rw-r--r-- | templates/web/bromley/waste/services.html | 14 |
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 %] |