diff options
author | Struan Donald <struan@exo.org.uk> | 2013-01-16 11:47:20 +0000 |
---|---|---|
committer | Struan Donald <struan@exo.org.uk> | 2013-01-16 11:47:20 +0000 |
commit | 682db36dca4db6c0682deeb4fb704e8cf222e38c (patch) | |
tree | 5811b7e2288f48b0bc814f7f505e19cb705294d9 | |
parent | 257b658e49da3665a426f1c98d9760b0d53b8d3d (diff) | |
parent | 3c4c0ec2f55d82502169d2313745920850efdc99 (diff) |
Merge branch 'bromley-new-statuses'
Conflicts:
bin/send-comments
conf/crontab.ugly
db/schema.sql
perllib/FixMyStreet/App/Controller/Admin.pm
perllib/FixMyStreet/DB/Result/Open311conf.pm
perllib/FixMyStreet/DB/ResultSet/Problem.pm
perllib/Open311.pm
t/app/controller/report_updates.t
t/open311.t
templates/web/default/report/display.html
templates/web/default/report/updates.html
templates/web/fixmystreet/report/display.html
30 files changed, 1107 insertions, 110 deletions
diff --git a/bin/send-comments b/bin/send-comments index 5a14098bf..24b436ac8 100755 --- a/bin/send-comments +++ b/bin/send-comments @@ -61,13 +61,20 @@ while ( my $council = $councils->next ) { $use_extended = 1; } - my $o = Open311->new( + my %open311_conf = ( endpoint => $council->endpoint, jurisdiction => $council->jurisdiction, api_key => $council->api_key, use_extended_updates => $use_extended, ); + + if ( $council->send_extended_statuses ) { + $open311_conf{extended_statuses} = 1; + } + + my $o = Open311->new( %open311_conf ); + if ( $council->area_id =~ /2482/ ) { my $endpoints = $o->endpoints; $endpoints->{update} = 'update.xml'; diff --git a/db/schema.sql b/db/schema.sql index 87e785de2..021c5561d 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -183,12 +183,16 @@ create table problem ( or state = 'investigating' or state = 'planned' or state = 'in progress' + or state = 'action scheduled' or state = 'closed' or state = 'fixed' or state = 'fixed - council' or state = 'fixed - user' or state = 'hidden' or state = 'partial' + or state = 'unable to fix' + or state = 'not responsible' + or state = 'duplicate' ), lang text not null default 'en-gb', service text not null default '', @@ -331,10 +335,14 @@ create table comment ( or problem_state = 'investigating' or problem_state = 'planned' or problem_state = 'in progress' + or problem_state = 'action scheduled' or problem_state = 'closed' or problem_state = 'fixed' or problem_state = 'fixed - council' or problem_state = 'fixed - user' + or problem_state = 'unable to fix' + or problem_state = 'not responsible' + or problem_state = 'duplicate' ), -- other fields? one to indicate whether this was written by the council -- and should be highlighted in the display? @@ -462,5 +470,6 @@ create table open311conf ( send_comments boolean not null default 'f', comment_user_id int references users(id), suppress_alerts boolean not null default 'f', - can_be_devolved boolean not null default 'f' + can_be_devolved boolean not null default 'f', + send_extended_statuses boolean not null default 'f' ); diff --git a/db/schema_0025-add_more_statuses_to_problem.sql b/db/schema_0025-add_more_statuses_to_problem.sql new file mode 100644 index 000000000..9c49c8566 --- /dev/null +++ b/db/schema_0025-add_more_statuses_to_problem.sql @@ -0,0 +1,75 @@ +BEGIN; + + ALTER TABLE problem DROP CONSTRAINT problem_state_check; + + ALTER TABLE problem ADD CONSTRAINT problem_state_check CHECK ( + state = 'unconfirmed' + or state = 'confirmed' + or state = 'investigating' + or state = 'planned' + or state = 'in progress' + or state = 'action scheduled' + or state = 'closed' + or state = 'fixed' + or state = 'fixed - council' + or state = 'fixed - user' + or state = 'hidden' + or state = 'partial' + or state = 'unable to fix' + or state = 'not responsible' + or state = 'duplicate' + ); + + + ALTER TABLE comment DROP CONSTRAINT comment_problem_state_check; + + ALTER TABLE comment ADD CONSTRAINT comment_problem_state_check CHECK ( + problem_state = 'confirmed' + or problem_state = 'investigating' + or problem_state = 'planned' + or problem_state = 'in progress' + or problem_state = 'action scheduled' + or problem_state = 'closed' + or problem_state = 'fixed' + or problem_state = 'fixed - council' + or problem_state = 'fixed - user' + or problem_state = 'unable to fix' + or problem_state = 'not responsible' + or problem_state = 'duplicate' + ); + + UPDATE alert_type set item_where = 'nearby.problem_id = problem.id and problem.state in + (''confirmed'', ''investigating'', ''planned'', ''in progress'', + ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'', + ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'' )' + WHERE ref = 'postcode_local_problems'; + UPDATE alert_type set item_where = 'problem.state in + (''confirmed'', ''investigating'', ''planned'', ''in progress'', + ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'' + ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'' )' + WHERE ref = 'new_problems'; + UPDATE alert_type set item_where = 'problem.state in (''fixed'', ''fixed - user'', ''fixed - council'')' WHERE ref = 'new_fixed_problems'; + UPDATE alert_type set item_where = 'nearby.problem_id = problem.id and problem.state in + (''confirmed'', ''investigating'', ''planned'', ''in progress'', + ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'', + ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'' )' + WHERE ref = 'local_problems'; + UPDATE alert_type set item_where = 'problem.state in + (''confirmed'', ''investigating'', ''planned'', ''in progress'', + ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'', + ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'' ) AND + (council like ''%''||?||''%'' or council is null) and + areas like ''%,''||?||'',%''' WHERE ref = 'council_problems'; + UPDATE alert_type set item_where = 'problem.state in + (''confirmed'', ''investigating'', ''planned'', ''in progress'', + ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'', + ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'' ) AND + (council like ''%''||?||''%'' or council is null) and + areas like ''%,''||?||'',%''' WHERE ref = 'ward_problems'; + UPDATE alert_type set item_where = 'problem.state in + (''confirmed'', ''investigating'', ''planned'', ''in progress'', + ''fixed'', ''fixed - council'', ''fixed - user'', ''closed'', + ''action scheduled'', ''not responsible'', ''duplicate'', ''unable to fix'' ) AND + areas like ''%,''||?||'',%''' WHERE ref = 'area_problems'; + +COMMIT; diff --git a/db/schema_0026-add_send_extended_comments_to_open311conf.sql b/db/schema_0026-add_send_extended_comments_to_open311conf.sql new file mode 100644 index 000000000..ee7b44b75 --- /dev/null +++ b/db/schema_0026-add_send_extended_comments_to_open311conf.sql @@ -0,0 +1,6 @@ +begin; + +ALTER table open311conf + ADD column send_extended_statuses BOOL NOT NULL DEFAULT 'f'; + +commit; diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index 7a2790b31..e14c7dc66 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -65,11 +65,9 @@ sub index : Path : Args(0) { %prob_counts = map { $_ => $prob_counts{$_} || 0 } - ('confirmed', 'investigating', 'in progress', 'closed', 'fixed - council', - 'fixed - user', 'fixed', 'unconfirmed', 'hidden', - 'partial', 'planned'); + ( FixMyStreet::DB::Result::Problem->all_states() ); $c->stash->{problems} = \%prob_counts; - $c->stash->{total_problems_live} += $prob_counts{$_} + $c->stash->{total_problems_live} += $prob_counts{$_} ? $prob_counts{$_} : 0 for ( FixMyStreet::DB::Result::Problem->visible_states() ); $c->stash->{total_problems_users} = $c->cobrand->problems->unique_users; @@ -351,7 +349,7 @@ sub update_contacts : Private { } elsif ( $posted eq 'open311' ) { $c->forward('check_token'); - my %params = map { $_ => $c->req->param($_) || '' } qw/open311_id endpoint jurisdiction api_key area_id send_method send_comments suppress_alerts comment_user_id devolved/; + my %params = map { $_ => $c->req->param($_) || '' } qw/open311_id endpoint jurisdiction api_key area_id send_method send_comments suppress_alerts extended_statuses comment_user_id devolved/; if ( $params{open311_id} ) { my $conf = $c->model('DB::Open311Conf')->find( { id => $params{open311_id} } ); @@ -364,6 +362,7 @@ sub update_contacts : Private { $conf->suppress_alerts( $params{suppress_alerts} || 0); $conf->comment_user_id( $params{comment_user_id} || undef ); $conf->can_be_devolved( $params{devolved} || 0 ); + $conf->send_extended_statuses( $params{extended_statuses} || 0 ); $conf->update(); @@ -379,6 +378,7 @@ sub update_contacts : Private { $conf->suppress_alerts( $params{suppress_alerts} || 0); $conf->comment_user_id( $params{comment_user_id} || undef ); $conf->can_be_devolved( $params{devolved} || 0 ); + $conf->send_extended_statuses( $params{extended_statuses} || 0 ); $conf->insert(); diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm index a5ba8ff07..17fd8b867 100644 --- a/perllib/FixMyStreet/App/Controller/Dashboard.pm +++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm @@ -138,6 +138,8 @@ sub index : Path : Args(0) { $prob_where->{state} = [ FixMyStreet::DB::Result::Problem->fixed_states() ]; } elsif ( $c->stash->{q_state} ) { $prob_where->{state} = $c->stash->{q_state}; + $prob_where->{state} = { IN => [ 'planned', 'action scheduled' ] } + if $prob_where->{state} eq 'action scheduled'; } my $params = { %$prob_where, @@ -181,11 +183,13 @@ sub updates_search : Private { map { $_ => $counts{$_} || 0 } ('confirmed', 'investigating', 'in progress', 'closed', 'fixed - council', 'fixed - user', 'fixed', 'unconfirmed', 'hidden', - 'partial', 'planned'); + 'partial', 'action scheduled', 'planned'); + + $counts{'action scheduled'} += $counts{planned} || 0; for my $vars ( [ 'time_to_fix', 'fixed - council' ], - [ 'time_to_mark', 'in progress', 'planned', 'investigating', 'closed' ], + [ 'time_to_mark', 'in progress', 'action scheduled', 'investigating', 'closed' ], ) { my $col = shift @$vars; my $substmt = "select min(id) from comment where me.problem_id=comment.problem_id and problem_state in ('" diff --git a/perllib/FixMyStreet/App/Controller/Report/Update.pm b/perllib/FixMyStreet/App/Controller/Report/Update.pm index da4cc33ca..5e0d9f388 100644 --- a/perllib/FixMyStreet/App/Controller/Report/Update.pm +++ b/perllib/FixMyStreet/App/Controller/Report/Update.pm @@ -203,8 +203,23 @@ sub process_update : Private { $params{state} = 'fixed - council' if $params{state} eq 'fixed' && $c->user && $c->user->belongs_to_council( $update->problem->council ); $update->problem_state( $params{state} ); + } else { + # we do this so we have a record of the state of the problem at this point + # for use when sending updates to external parties + if ( $update->mark_fixed ) { + $update->problem_state( 'fixed - user' ); + } elsif ( $update->mark_open ) { + $update->problem_state( 'confirmed' ); + # if there is not state param and neither of the above conditions apply + # then we are not changing the state of the problem so can use the current + # problem state + } else { + my $problem = $c->stash->{problem} || $update->problem; + $update->problem_state( $problem->state ); + } } + my @extra; # Next function fills this, but we don't need it here. # This is just so that the error checkign for these extra fields runs. # TODO Use extra here as it is used on reports. @@ -249,7 +264,8 @@ sub check_for_errors : Private { $error = 1 unless $c->user && $c->user->belongs_to_council( $c->stash->{update}->problem->council ); my $state = $c->req->param('state'); - $error = 1 unless ( grep { $state eq $_ } ( qw/confirmed closed fixed investigating planned/, 'in progress', 'fixed', 'fixed - user', 'fixed - council' ) ); + $state = 'fixed - council' if $state eq 'fixed'; + $error = 1 unless ( grep { $state eq $_ } ( FixMyStreet::DB::Result::Problem->council_states() ) ); if ( $error ) { $c->stash->{errors} ||= []; diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm index 8c9fea282..b551be9ef 100644 --- a/perllib/FixMyStreet/DB/Result/Comment.pm +++ b/perllib/FixMyStreet/DB/Result/Comment.pm @@ -146,6 +146,11 @@ sub check_for_errors { $errors{update} = _('Please enter a message') unless $self->text =~ m/\S/; + if ( $self->text && $self->problem && $self->problem->council + && $self->problem->council eq '2482' && length($self->text) > 2000 ) { + $errors{update} = _('Updates are limited to 2000 characters in length. Please shorten your update'); + } + return \%errors; } @@ -186,6 +191,10 @@ sub meta_problem_state { my $state = $self->problem_state; $state =~ s/ -.*$//; + $state = _("not the council's responsibility") + if $state eq 'not responsible'; + $state = _('duplicate report') if $state eq 'duplicate'; + return $state; } diff --git a/perllib/FixMyStreet/DB/Result/Open311conf.pm b/perllib/FixMyStreet/DB/Result/Open311conf.pm index 8051e27de..f01a20dec 100644 --- a/perllib/FixMyStreet/DB/Result/Open311conf.pm +++ b/perllib/FixMyStreet/DB/Result/Open311conf.pm @@ -36,6 +36,8 @@ __PACKAGE__->add_columns( { data_type => "boolean", default_value => \"false", is_nullable => 0 }, "can_be_devolved", { data_type => "boolean", default_value => \"false", is_nullable => 0 }, + "send_extended_statuses", + { data_type => "boolean", default_value => \"false", is_nullable => 0 }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->add_unique_constraint("open311conf_area_id_key", ["area_id"]); @@ -55,6 +57,5 @@ __PACKAGE__->belongs_to( # Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-08-29 14:04:20 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Yoult8K/ldH6DMAKURtr3Q - # You can replace this text with custom code or comments, and it will be preserved on regeneration 1; diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index dd09ad3c2..b1f59e78a 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -196,10 +196,11 @@ HASHREF. sub open_states { my $states = { - 'confirmed' => 1, - 'investigating' => 1, - 'planned' => 1, - 'in progress' => 1, + 'confirmed' => 1, + 'investigating' => 1, + 'in progress' => 1, + 'planned' => 1, + 'action scheduled' => 1, }; return wantarray ? keys %{$states} : $states; @@ -237,7 +238,10 @@ HASHREF. sub closed_states { my $states = { - 'closed' => 1, + 'closed' => 1, + 'unable to fix' => 1, + 'not responsible' => 1, + 'duplicate' => 1, }; return wantarray ? keys %{$states} : $states; @@ -248,7 +252,7 @@ sub closed_states { @states = FixMyStreet::DB::Problem::visible_states(); -Get a list or states that should be visible on the site. If called in +Get a list of states that should be visible on the site. If called in array context then returns an array of names, otherwise returns a HASHREF. @@ -256,14 +260,73 @@ HASHREF. sub visible_states { my $states = { - 'confirmed' => 1, - 'planned' => 1, - 'investigating' => 1, - 'in progress' => 1, - 'fixed' => 1, - 'fixed - council' => 1, - 'fixed - user' => 1, - 'closed' => 1, + 'confirmed' => 1, + 'investigating' => 1, + 'in progress' => 1, + 'planned' => 1, + 'action scheduled' => 1, + 'fixed' => 1, + 'fixed - council' => 1, + 'fixed - user' => 1, + 'unable to fix' => 1, + 'not responsible' => 1, + 'duplicate' => 1, + 'closed' => 1, + }; + + return wantarray ? keys %{$states} : $states; +} + +=head2 + + @states = FixMyStreet::DB::Problem::all_states(); + +Get a list of all states that a problem can have. If called in +array context then returns an array of names, otherwise returns a +HASHREF. + +=cut + +sub all_states { + my $states = { + 'hidden' => 1, + 'partial' => 1, + 'unconfirmed' => 1, + 'confirmed' => 1, + 'investigating' => 1, + 'in progress' => 1, + 'action scheduled' => 1, + 'fixed' => 1, + 'fixed - council' => 1, + 'fixed - user' => 1, + 'unable to fix' => 1, + 'not responsible' => 1, + 'duplicate' => 1, + 'closed' => 1, + }; + + return wantarray ? keys %{$states} : $states; +} + +=head2 + + @states = FixMyStreet::DB::Problem::council_states(); + +Get a list of states that are availble to council users. If called in +array context then returns an array of names, otherwise returns a +HASHREF. + +=cut +sub council_states { + my $states = { + 'confirmed' => 1, + 'investigating' => 1, + 'action scheduled' => 1, + 'in progress' => 1, + 'fixed - council' => 1, + 'unable to fix' => 1, + 'not responsible' => 1, + 'duplicate' => 1, }; return wantarray ? keys %{$states} : $states; @@ -364,6 +427,11 @@ sub check_for_errors { $self->category(undef); } + if ( $self->council && $self->detail && + $self->council eq '2482' && length($self->detail) > 2000 ) { + $errors{detail} = _('Reports are limited to 2000 characters in length. Please shorten your report'); + } + return \%errors; } diff --git a/perllib/Open311.pm b/perllib/Open311.pm index 7a5493704..dee985fca 100644 --- a/perllib/Open311.pm +++ b/perllib/Open311.pm @@ -25,6 +25,7 @@ has send_notpinpointed => ( is => 'ro', isa => 'Bool', default => 0 ); has extended_description => ( is => 'ro', isa => 'Str', default => 1 ); has use_service_as_deviceid => ( is => 'ro', isa => 'Bool', default => 0 ); has use_extended_updates => ( is => 'ro', isa => 'Bool', default => 0 ); +has extended_statuses => ( is => 'ro', isa => 'Bool', default => 0 ); before [ qw/get_service_list get_service_meta_info get_service_requests get_service_request_updates @@ -287,10 +288,37 @@ sub _populate_service_request_update_params { my $name = $comment->name || $comment->user->name; my ( $firstname, $lastname ) = ( $name =~ /(\w+)\.?\s+(.+)/ ); + # fall back to problem state as it's probably correct + my $state = $comment->problem_state || $comment->problem->state; + + my $status = 'OPEN'; + if ( $self->extended_statuses ) { + if ( FixMyStreet::DB::Result::Problem->fixed_states()->{$state} ) { + $status = 'FIXED'; + } elsif ( $state eq 'in progress' ) { + $status = 'IN_PROGRESS'; + } elsif ($state eq 'action scheduled' + || $state eq 'planned' ) { + $status = 'ACTION_SCHEDULED'; + } elsif ( $state eq 'investigating' ) { + $status = 'INVESTIGATING'; + } elsif ( $state eq 'duplicate' ) { + $status = 'DUPLICATE'; + } elsif ( $state eq 'not responsible' ) { + $status = 'NOT_COUNCILS_RESPONSIBILITY'; + } elsif ( $state eq 'unable to fix' ) { + $status = 'NO_FURTHER_ACTION'; + } + } else { + if ( !FixMyStreet::DB::Result::Problem->open_states()->{$state} ) { + $status = 'CLOSED'; + } + } + my $params = { updated_datetime => DateTime::Format::W3CDTF->format_datetime($comment->confirmed_local->set_nanosecond(0)), service_request_id => $comment->problem->external_id, - status => $comment->problem->is_open ? 'OPEN' : 'CLOSED', + status => $status, email => $comment->user->email, description => $comment->text, last_name => $lastname, diff --git a/perllib/Open311/GetServiceRequestUpdates.pm b/perllib/Open311/GetServiceRequestUpdates.pm index 0b4e037fd..e337c0f57 100644 --- a/perllib/Open311/GetServiceRequestUpdates.pm +++ b/perllib/Open311/GetServiceRequestUpdates.pm @@ -113,12 +113,14 @@ sub update_comments { # do not change the status of the problem as it's # tricky to determine the right thing to do. if ( $comment->created_local > $p->lastupdate_local ) { - if ( $p->is_open and lc($request->{status}) eq 'closed' ) { - $p->state( 'fixed - council' ); - $comment->problem_state( 'fixed - council' ); - } elsif ( ( $p->is_closed || $p->is_fixed ) and lc($request->{status}) eq 'open' ) { - $p->state( 'confirmed' ); - $comment->problem_state( 'confirmed' ); + my $state = $self->map_state( $request->{status} ); + + # don't update state unless it's an allowed state and it's + # actually changing the state of the problem + if ( FixMyStreet::DB::Result::Problem->council_states()->{$state} && $p->state ne $state && + !( $p->is_fixed && FixMyStreet::DB::Result::Problem->fixed_states()->{$state} ) ) { + $p->state($state); + $comment->problem_state($state); } } @@ -146,4 +148,22 @@ sub update_comments { return 1; } +sub map_state { + my $self = shift; + my $incoming_state = shift; + + $incoming_state = lc($incoming_state); + $incoming_state =~ s/_/ /g; + + my %state_map = ( + fixed => 'fixed - council', + 'not councils responsibility' => 'not responsible', + 'no further action' => 'unable to fix', + open => 'confirmed', + closed => 'fixed - council' + ); + + return $state_map{$incoming_state} || $incoming_state; +} + 1; diff --git a/t/app/controller/dashboard.t b/t/app/controller/dashboard.t index 47d10ff5c..25e144464 100644 --- a/t/app/controller/dashboard.t +++ b/t/app/controller/dashboard.t @@ -78,7 +78,7 @@ my $categories = scraper { process "tr[id=fixed_user] > td", 'user[]' => 'TEXT', process "tr[id=total_fixed] > td", 'total_fixed[]' => 'TEXT', process "tr[id=in_progress] > td", 'in_progress[]' => 'TEXT', - process "tr[id=planned] > td", 'planned[]' => 'TEXT', + process "tr[id=action_scheduled] > td", 'action_scheduled[]' => 'TEXT', process "tr[id=investigating] > td", 'investigating[]' => 'TEXT', process "tr[id=marked] > td", 'marked[]' => 'TEXT', process "tr[id=avg_marked] > td", 'avg_marked[]' => 'TEXT', @@ -212,10 +212,10 @@ foreach my $test ( } }, { - desc => 'marked as planned today', + desc => 'marked as action scheduled today', confirm_dt => DateTime->now->subtract( days => 1 ), mark_dt => DateTime->now, - state => 'planned', + state => 'action scheduled', counts => { totals => $is_monday ? [ 0,5,5,5] : [5,5,5,5], user => [1,1,1,1], @@ -224,15 +224,15 @@ foreach my $test ( avg_marked => [1,1,1,1], investigating => [1,1,1,1], in_progress => [1,1,1,1], - planned => [1,1,1,1], + action_scheduled => [1,1,1,1], marked => [3,3,3,3] } }, { - desc => 'marked as planned today, confirmed a week ago', + desc => 'marked as action scheduled today, confirmed a week ago', confirm_dt => DateTime->now->subtract( days => 8 ), mark_dt => DateTime->now, - state => 'planned', + state => 'action scheduled', counts => { totals => $is_monday ? [0,5,6,6] : [5,5,6,6], user => [1,1,1,1], @@ -241,7 +241,7 @@ foreach my $test ( avg_marked => [3,3,3,3], investigating => [1,1,1,1], in_progress => [1,1,1,1], - planned => [2,2,2,2], + action_scheduled => [2,2,2,2], marked => [4,4,4,4] } }, @@ -259,7 +259,7 @@ foreach my $test ( avg_marked => [3,3,3,3], investigating => [1,1,1,1], in_progress => [1,1,1,1], - planned => [2,2,2,2], + action_scheduled => [2,2,2,2], marked => [4,4,4,4] } }, @@ -277,7 +277,7 @@ foreach my $test ( avg_marked => [3,3,3,3], investigating => [1,1,1,1], in_progress => [1,1,1,1], - planned => [2,2,2,2], + action_scheduled => [2,2,2,2], marked => [4,4,4,4] } }, @@ -295,7 +295,7 @@ foreach my $test ( avg_marked => [3,3,3,3], investigating => [1,1,1,1], in_progress => [1,1,1,1], - planned => [2,2,2,2], + action_scheduled => [2,2,2,2], marked => [4,4,4,4] } }, @@ -313,11 +313,30 @@ foreach my $test ( avg_marked => [2,2,2,2], investigating => [1,1,1,1], in_progress => [1,1,1,1], - planned => [2,2,2,2], + action_scheduled => [2,2,2,2], closed => [1,1,1,1], marked => [5,5,5,5] } }, + { + desc => 'marked as planned', + confirm_dt => DateTime->now->subtract( days => 1 ), + mark_dt => DateTime->now, + state => 'planned', + counts => { + totals => $is_monday ? [0,7,10,11] : [7,7,10,11], + user => [1,1,1,2], + council => [2,2,3,3], + total_fixed => [3,3,4,5], + avg_fixed => [5,5,7,7], + avg_marked => [2,2,2,2], + investigating => [1,1,1,1], + in_progress => [1,1,1,1], + action_scheduled => [3,3,3,3], + closed => [1,1,1,1], + marked => [6,6,6,6] + } + }, ) { subtest $test->{desc} => sub { make_problem( @@ -528,6 +547,17 @@ for my $test ( report_counts_after => [1,0,0], }, { + desc => 'planned counted as action scheduled', + p1 => { + state => 'planned', + conf_dt => DateTime->now(), + category => 'Potholes', + }, + state => 'action scheduled', + report_counts => [3,0,0], + report_counts_after => [1,0,0], + }, + { desc => 'All fixed states count as fixed', p1 => { state => 'fixed - council', @@ -540,7 +570,7 @@ for my $test ( category => 'Potholes', }, state => 'fixed', - report_counts => [4,0,0], + report_counts => [5,0,0], report_counts_after => [3,0,0], }, ) { diff --git a/t/app/controller/questionnaire.t b/t/app/controller/questionnaire.t index 3a6a3d6ad..d8d1eb4f3 100644 --- a/t/app/controller/questionnaire.t +++ b/t/app/controller/questionnaire.t @@ -329,6 +329,10 @@ for my $test ( fixed => 0 }, { + state => 'action scheduled', + fixed => 0 + }, + { state => 'in progress', fixed => 0 }, @@ -337,6 +341,18 @@ for my $test ( fixed => 0 }, { + state => 'duplicate', + fixed => 0 + }, + { + state => 'not responsible', + fixed => 0 + }, + { + state => 'unable to fix', + fixed => 0 + }, + { state => 'closed', fixed => 0 }, diff --git a/t/app/controller/report_display.t b/t/app/controller/report_display.t index 3bb0913f1..82c98dc5c 100644 --- a/t/app/controller/report_display.t +++ b/t/app/controller/report_display.t @@ -283,6 +283,30 @@ for my $test ( fixed => 1 }, { + description => 'duplicate report', + date => DateTime->now, + state => 'duplicate', + banner_id => 'closed', + banner_text => 'closed', + fixed => 0 + }, + { + description => 'not responsible report', + date => DateTime->now, + state => 'not responsible', + banner_id => 'closed', + banner_text => 'closed', + fixed => 0 + }, + { + description => 'unable to fix report', + date => DateTime->now, + state => 'unable to fix', + banner_id => 'closed', + banner_text => 'closed', + fixed => 0 + }, + { description => 'closed report', date => DateTime->now, state => 'closed', @@ -299,6 +323,14 @@ for my $test ( fixed => 0 }, { + description => 'action scheduled report', + date => DateTime->now, + state => 'action scheduled', + banner_id => 'progress', + banner_text => 'progress', + fixed => 0 + }, + { description => 'planned report', date => DateTime->now, state => 'planned', @@ -307,7 +339,7 @@ for my $test ( fixed => 0 }, { - description => 'in progressreport', + description => 'in progress report', date => DateTime->now, state => 'in progress', banner_id => 'progress', diff --git a/t/app/controller/report_updates.t b/t/app/controller/report_updates.t index 82670d6cc..2204a9d99 100644 --- a/t/app/controller/report_updates.t +++ b/t/app/controller/report_updates.t @@ -477,64 +477,91 @@ for my $test ( state => 'investigating', }, { - desc => 'from authority user marks report as planned', + desc => 'from authority user marks report as in progress', fields => { name => $user->name, may_show_name => 1, add_alert => undef, photo => '', - update => 'Set state to planned', - state => 'planned', + update => 'Set state to in progress', + state => 'in progress', }, - state => 'planned', + state => 'in progress', }, { - desc => 'from authority user marks report as in progress', + desc => 'from authority user marks report as fixed', fields => { name => $user->name, may_show_name => 1, add_alert => undef, photo => '', - update => 'Set state to in progress', - state => 'in progress', + update => 'Set state to fixed', + state => 'fixed', }, - state => 'in progress', + state => 'fixed - council', }, { - desc => 'from authority user marks report as closed', + desc => 'from authority user marks report as confirmed', fields => { name => $user->name, may_show_name => 1, add_alert => undef, photo => '', - update => 'Set state to closed', - state => 'closed', + update => 'Set state to confirmed', + state => 'confirmed', }, - state => 'closed', + state => 'confirmed', + reopened => 1, }, { - desc => 'from authority user marks report as fixed', + desc => 'from authority user marks report as action scheduled', fields => { name => $user->name, may_show_name => 1, add_alert => undef, photo => '', - update => 'Set state to fixed', - state => 'fixed', + update => 'Set state to action scheduled', + state => 'action scheduled', }, - state => 'fixed - council', + state => 'action scheduled', }, { - desc => 'from authority user marks report as confirmed', + desc => 'from authority user marks report as unable to fix', fields => { name => $user->name, may_show_name => 1, add_alert => undef, photo => '', - update => 'Set state to confirmed', - state => 'confirmed', + update => 'Set state to unable to fix', + state => 'unable to fix', }, - state => 'confirmed', + state => 'unable to fix', + }, + { + desc => 'from authority user marks report as not responsible', + fields => { + name => $user->name, + may_show_name => 1, + add_alert => undef, + photo => '', + update => 'Set state to not responsible', + state => 'not responsible', + }, + state => 'not responsible', + meta => "not the council's responsibility" + }, + { + desc => 'from authority user marks report as duplicate', + fields => { + name => $user->name, + may_show_name => 1, + add_alert => undef, + photo => '', + update => 'Set state to duplicate', + state => 'duplicate', + }, + state => 'duplicate', + meta => 'duplicate report', }, { desc => 'from authority user marks report sent to two councils as fixed', @@ -577,11 +604,11 @@ for my $test ( is $update->problem_state, $test->{state}, 'problem state set'; my $update_meta = $mech->extract_update_metas; - # setting it to confirmed shouldn't say anything - if ( $test->{fields}->{state} ne 'confirmed' ) { - like $update_meta->[0], qr/marked as $test->{fields}->{state}$/, 'update meta includes state change'; + my $meta_state = $test->{meta} || $test->{fields}->{state}; + if ( $test->{reopened} ) { + like $update_meta->[0], qr/reopened$/, 'update meta says reopened'; } else { - like $update_meta->[0], qr/reopened$/, 'update meta includes state change'; + like $update_meta->[0], qr/marked as $meta_state$/, 'update meta includes state change'; } like $update_meta->[0], qr{Test User \(Westminster City Council\)}, 'update meta includes council name'; $mech->content_contains( 'Test User (<strong>Westminster City Council</strong>)', 'council name in bold'); @@ -629,6 +656,105 @@ subtest 'check meta correct for comments marked confirmed but not marked open' = unlike $update_meta->[0], qr/reopened$/, 'update meta does not say reopened'; }; +subtest "check comment with no status change has not status in meta" => sub { + $mech->log_in_ok( $user->email ); + $user->from_council( 0 ); + $user->update; + + my $comment = $report->comments->first; + $comment->update( { mark_fixed => 1, problem_state => 'fixed - council' } ); + + $mech->get_ok("/report/$report_id"); + + $mech->submit_form_ok( + { + with_fields => { + name => $user->name, + may_show_name => 1, + add_alert => undef, + photo => '', + update => 'Comment that does not change state', + }, + }, + 'submit update' + ); + + $report->discard_changes; + my @updates = $report->comments->all; + is scalar @updates, 2, 'correct number of updates'; + + warn $updates[0]->problem_state; + warn $updates[1]->problem_state; + my $update = pop @updates; + + is $report->state, 'fixed - council', 'correct report state'; + is $update->problem_state, 'fixed - council', 'corect update state'; + my $update_meta = $mech->extract_update_metas; + unlike $update_meta->[1], qr/marked as/, 'update meta does not include state change'; + + $user->from_council( 2504 ); + $user->update; + + $mech->get_ok("/report/$report_id"); + + $mech->submit_form_ok( + { + with_fields => { + name => $user->name, + may_show_name => 1, + add_alert => undef, + photo => '', + update => 'Comment that sets state to investigating', + state => 'investigating', + }, + }, + 'submit update' + ); + + $report->discard_changes; + @updates = $report->comments->all; + is scalar @updates, 3, 'correct number of updates'; + + $update = pop @updates; + + is $report->state, 'investigating', 'correct report state'; + is $update->problem_state, 'investigating', 'corect update state'; + $update_meta = $mech->extract_update_metas; + like $update_meta->[0], qr/marked as fixed/, 'first update meta says fixed'; + unlike $update_meta->[1], qr/marked as/, 'second update meta does not include state change'; + like $update_meta->[2], qr/marked as investigating/, 'third update meta says investigating'; + + my $dt = DateTime->now; + my $comment = FixMyStreet::App->model('DB::Comment')->find_or_create( + { + problem_id => $report_id, + user_id => $user->id, + name => 'Other User', + mark_fixed => 'false', + text => 'This is some update text', + state => 'confirmed', + confirmed => $dt->ymd . ' ' . $dt->hms, + anonymous => 'f', + } + ); + + $mech->get_ok("/report/$report_id"); + + $report->discard_changes; + @updates = $report->comments->all; + is scalar @updates, 4, 'correct number of updates'; + + $update = pop @updates; + + is $report->state, 'investigating', 'correct report state'; + is $update->problem_state, undef, 'no update state'; + $update_meta = $mech->extract_update_metas; + like $update_meta->[0], qr/marked as fixed/, 'first update meta says fixed'; + unlike $update_meta->[1], qr/marked as/, 'second update meta does not include state change'; + like $update_meta->[2], qr/marked as investigating/, 'third update meta says investigating'; + unlike $update_meta->[3], qr/marked as/, 'fourth update meta has no state change'; +}; + $user->from_council(0); $user->update; @@ -1286,6 +1412,232 @@ for my $test ( }; } +for my $test ( + { + desc => 'update confirmed without marking as fixed leaves state unchanged', + initial_state => 'confirmed', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 0, + }, + end_state => 'confirmed', + }, + { + desc => 'update investigating without marking as fixed leaves state unchanged', + initial_state => 'investigating', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 0, + }, + end_state => 'investigating', + }, + { + desc => 'update in progress without marking as fixed leaves state unchanged', + initial_state => 'in progress', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 0, + }, + end_state => 'in progress', + }, + { + desc => 'update action scheduled without marking as fixed leaves state unchanged', + initial_state => 'action scheduled', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 0, + }, + end_state => 'action scheduled', + }, + { + desc => 'update fixed without marking as open leaves state unchanged', + initial_state => 'fixed', + expected_form_fields => { + reopen => undef, + }, + submitted_form_fields => { + reopen => 0, + }, + end_state => 'fixed', + }, + { + desc => 'update unable to fix without marking as fixed leaves state unchanged', + initial_state => 'unable to fix', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 0, + }, + end_state => 'unable to fix', + }, + { + desc => 'update not responsible without marking as fixed leaves state unchanged', + initial_state => 'not responsible', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 0, + }, + end_state => 'not responsible', + }, + { + desc => 'update duplicate without marking as fixed leaves state unchanged', + initial_state => 'duplicate', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 0, + }, + end_state => 'duplicate', + }, + { + desc => 'can mark confirmed as fixed', + initial_state => 'confirmed', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 1, + }, + end_state => 'fixed - user', + }, + { + desc => 'can mark investigating as fixed', + initial_state => 'investigating', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 1, + }, + end_state => 'fixed - user', + }, + { + desc => 'can mark in progress as fixed', + initial_state => 'in progress', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 1, + }, + end_state => 'fixed - user', + }, + { + desc => 'can mark action scheduled as fixed', + initial_state => 'action scheduled', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 1, + }, + end_state => 'fixed - user', + }, + { + desc => 'cannot mark fixed as fixed, can mark as not fixed', + initial_state => 'fixed', + expected_form_fields => { + reopen => undef, + }, + submitted_form_fields => { + reopen => 1, + }, + end_state => 'confirmed', + }, + { + desc => 'can mark unable to fix as fixed, cannot mark not closed', + initial_state => 'unable to fix', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 1, + }, + end_state => 'fixed - user', + }, + { + desc => 'can mark not responsible as fixed, cannot mark not closed', + initial_state => 'not responsible', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 1, + }, + end_state => 'fixed - user', + }, + { + desc => 'can mark duplicate as fixed, cannot mark not closed', + initial_state => 'duplicate', + expected_form_fields => { + fixed => undef, + }, + submitted_form_fields => { + fixed => 1, + }, + end_state => 'fixed - user', + }, +) { + subtest $test->{desc} => sub { + $mech->log_in_ok( $report->user->email ); + + my %standard_fields = ( + name => $report->user->name, + update => 'update text', + photo => '', + may_show_name => 1, + add_alert => 1, + ); + + my %expected_fields = ( + %standard_fields, + %{ $test->{expected_form_fields} }, + update => '', + ); + + my %submitted_fields = ( + %standard_fields, + %{ $test->{submitted_form_fields} }, + ); + + # clear out comments for this problem to make + # checking details easier later + ok( $_->delete, 'deleted comment ' . $_->id ) for $report->comments; + + $report->discard_changes; + $report->state($test->{initial_state}); + $report->update; + + $mech->get_ok("/report/$report_id"); + + my $values = $mech->visible_form_values('updateForm'); + is_deeply $values, \%expected_fields, 'correct form fields present'; + + if ( $test->{submitted_form_fields} ) { + $mech->submit_form_ok( { + with_fields => \%submitted_fields + }, + 'submit update' + ); + + $report->discard_changes; + is $report->state, $test->{end_state}, 'update sets correct report state'; + } + }; +} + subtest 'check have to be logged in for creator fixed questionnaire' => sub { $mech->log_out_ok(); diff --git a/t/app/model/problem.t b/t/app/model/problem.t index 63204e05c..040790184 100644 --- a/t/app/model/problem.t +++ b/t/app/model/problem.t @@ -302,6 +302,13 @@ for my $test ( is_closed => 0, }, { + state => 'action scheduled', + is_visible => 1, + is_fixed => 0, + is_open => 1, + is_closed => 0, + }, + { state => 'in progress', is_visible => 1, is_fixed => 0, @@ -309,6 +316,27 @@ for my $test ( is_closed => 0, }, { + state => 'duplicate', + is_visible => 1, + is_fixed => 0, + is_open => 0, + is_closed => 1, + }, + { + state => 'not responsible', + is_visible => 1, + is_fixed => 0, + is_open => 0, + is_closed => 1, + }, + { + state => 'unable to fix', + is_visible => 1, + is_fixed => 0, + is_open => 0, + is_closed => 1, + }, + { state => 'fixed', is_visible => 1, is_fixed => 1, diff --git a/t/app/model/questionnaire.t b/t/app/model/questionnaire.t index 60b52043a..86af51c42 100644 --- a/t/app/model/questionnaire.t +++ b/t/app/model/questionnaire.t @@ -62,6 +62,10 @@ for my $test ( send_email => 1, }, { + state => 'action scheduled', + send_email => 1, + }, + { state => 'in progress', send_email => 1, }, @@ -78,6 +82,18 @@ for my $test ( send_email => 1, }, { + state => 'duplicate', + send_email => 1, + }, + { + state => 'unable to fix', + send_email => 1, + }, + { + state => 'not responsible', + send_email => 1, + }, + { state => 'closed', send_email => 1, }, diff --git a/t/map/tilma/original.t b/t/map/tilma/original.t index 04c4d578c..7f68df308 100644 --- a/t/map/tilma/original.t +++ b/t/map/tilma/original.t @@ -71,10 +71,26 @@ for my $test ( colour => 'yellow', }, { + state => 'duplicate', + colour => 'yellow', + }, + { + state => 'unable to fix', + colour => 'yellow', + }, + { + state => 'not responsible', + colour => 'yellow', + }, + { state => 'investigating', colour => 'yellow', }, { + state => 'action scheduled', + colour => 'yellow', + }, + { state => 'planned', colour => 'yellow', }, diff --git a/t/open311.t b/t/open311.t index cbc8cf474..4c451d55e 100644 --- a/t/open311.t +++ b/t/open311.t @@ -192,6 +192,7 @@ my $comment = FixMyStreet::App->model('DB::Comment')->new( { anonymous => 0, text => 'this is a comment', confirmed => $dt, + problem_state => 'confirmed', extra => { title => 'Mr', email_alerts_requested => 0 }, } ); @@ -216,7 +217,7 @@ subtest 'basic request update post parameters' => sub { }; subtest 'extended request update post parameters' => sub { - my $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>', 1 ); + my $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>', { extended_updates => 1 } ); is $results->{ res }, 248, 'got update id'; @@ -258,16 +259,40 @@ foreach my $test ( desc => 'comment with fixed state sends status of CLOSED', state => 'fixed', status => 'CLOSED', + extended => 'FIXED', }, { desc => 'comment with fixed - user state sends status of CLOSED', state => 'fixed - user', status => 'CLOSED', + extended => 'FIXED', }, { desc => 'comment with fixed - council state sends status of CLOSED', state => 'fixed - council', status => 'CLOSED', + extended => 'FIXED', + }, + { + desc => 'comment with duplicate state sends status of CLOSED', + state => 'duplicate', + anon => 0, + status => 'CLOSED', + extended => 'DUPLICATE', + }, + { + desc => 'comment with not reponsible state sends status of CLOSED', + state => 'not responsible', + anon => 0, + status => 'CLOSED', + extended => 'NOT_COUNCILS_RESPONSIBILITY', + }, + { + desc => 'comment with unable to fix state sends status of CLOSED', + state => 'unable to fix', + anon => 0, + status => 'CLOSED', + extended => 'NO_FURTHER_ACTION', }, { desc => 'comment with closed state sends status of CLOSED', @@ -278,11 +303,20 @@ foreach my $test ( desc => 'comment with investigating state sends status of OPEN', state => 'investigating', status => 'OPEN', + extended => 'INVESTIGATING', }, { desc => 'comment with planned state sends status of OPEN', state => 'planned', status => 'OPEN', + extended => 'ACTION_SCHEDULED', + }, + { + desc => 'comment with action scheduled state sends status of OPEN', + state => 'action scheduled', + anon => 0, + status => 'OPEN', + extended => 'ACTION_SCHEDULED', }, { desc => 'comment with in progress state sends status of OPEN', @@ -310,6 +344,7 @@ for my $test ( state => 'confirmed', anon => 0, status => 'OPEN', + extended => 'IN_PROGRESS', }, { desc => 'anonymous commment sets public_anonymity_required to true', @@ -319,13 +354,73 @@ for my $test ( }, ) { subtest $test->{desc} => sub { + $comment->problem_state( $test->{state} ); $comment->problem->state( $test->{state} ); $comment->anonymous( $test->{anon} ); - my $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>', 1 ); + my $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>', { extended_updates => 1 } ); my $c = CGI::Simple->new( $results->{ req }->content ); is $c->param('public_anonymity_required'), $test->{anon} ? 'TRUE' : 'FALSE', 'correct anonymity'; + + if ( $test->{extended} ) { + my $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>', { extended_statuses => 1 } ); + my $c = CGI::Simple->new( $results->{ req }->content ); + is $c->param('status'), $test->{extended}, 'correct extended status'; + } + }; +} + +my $dt2 = $dt->clone; +$dt2->add( 'minutes' => 1 ); + +my $comment2 = FixMyStreet::App->model('DB::Comment')->new( { + id => 38363, + user => $user, + problem => $problem, + anonymous => 0, + text => 'this is a comment', + confirmed => $dt, + problem_state => 'confirmed', + extra => { title => 'Mr', email_alerts_requested => 0 }, +} ); + +for my $test ( + { + desc => 'comment with fixed - council state sends status of CLOSED even if problem is open', + state => 'fixed - council', + problem_state => 'confirmed', + status => 'CLOSED', + extended => 'FIXED', + }, + { + desc => 'comment marked open sends status of OPEN even if problem is closed', + state => 'confirmed', + problem_state => 'fixed - council', + status => 'OPEN', + extended => 'OPEN', + }, + { + desc => 'comment with no problem state falls back to report state', + state => '', + problem_state => 'fixed - council', + status => 'CLOSED', + extended => 'FIXED', + }, +) { + subtest $test->{desc} => sub { + $comment->problem_state( $test->{state} ); + $comment->problem->state( $test->{problem_state} ); + my $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>' ); + + my $c = CGI::Simple->new( $results->{ req }->content ); + is $c->param('status'), $test->{status}, 'correct status'; + + if ( $test->{extended} ) { + my $results = make_update_req( $comment, '<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>', { extended_statuses => 1 } ); + my $c = CGI::Simple->new( $results->{ req }->content ); + is $c->param('status'), $test->{extended}, 'correct extended status'; + } }; } @@ -539,18 +634,16 @@ done_testing(); sub make_update_req { my $comment = shift; my $xml = shift; - my $extended = shift; + my $open311conf = shift || {}; my $params = { object => $comment, xml => $xml, method => 'post_service_request_update', path => 'servicerequestupdates.xml', + open311_conf => $open311_args, }; - if ( $extended ) { - $params->{ open311_conf } = { use_extended_updates => 1 }; - } return make_req( $params ); } diff --git a/t/open311/getservicerequestupdates.t b/t/open311/getservicerequestupdates.t index aba811e58..3f9c35c32 100644 --- a/t/open311/getservicerequestupdates.t +++ b/t/open311/getservicerequestupdates.t @@ -131,63 +131,197 @@ $problem->insert; for my $test ( { - desc => 'element with content', + desc => 'OPEN status for confirmed problem does not change state', updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), description => 'This is a note', external_id => 638344, start_state => 'confirmed', - close_comment => 0, + comment_status => 'OPEN', mark_fixed=> 0, mark_open => 0, problem_state => undef, end_state => 'confirmed', }, { - desc => 'comment closes report', + desc => 'bad state does not update states but does create update', updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), description => 'This is a note', external_id => 638344, start_state => 'confirmed', - close_comment => 1, + comment_status => 'INVALID_STATE', + mark_fixed=> 0, + mark_open => 0, + problem_state => undef, + end_state => 'confirmed', + }, + + { + desc => 'investigating status changes problem status', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'confirmed', + comment_status => 'INVESTIGATING', + mark_fixed=> 0, + mark_open => 0, + problem_state => 'investigating', + end_state => 'investigating', + }, + { + desc => 'in progress status changes problem status', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'confirmed', + comment_status => 'IN_PROGRESS', + mark_fixed=> 0, + mark_open => 0, + problem_state => 'in progress', + end_state => 'in progress', + }, + { + desc => 'action scheduled status changes problem status', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'confirmed', + comment_status => 'ACTION_SCHEDULED', + mark_fixed=> 0, + mark_open => 0, + problem_state => 'action scheduled', + end_state => 'action scheduled', + }, + { + desc => 'not responsible status changes problem status', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'confirmed', + comment_status => 'NOT_COUNCILS_RESPONSIBILITY', + mark_fixed=> 0, + mark_open => 0, + problem_state => 'not responsible', + end_state => 'not responsible', + }, + { + desc => 'duplicate status changes problem status', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'confirmed', + comment_status => 'DUPLICATE', + mark_fixed=> 0, + mark_open => 0, + problem_state => 'duplicate', + end_state => 'duplicate', + }, + { + desc => 'fixed status marks report as fixed - council', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'confirmed', + comment_status => 'FIXED', + mark_fixed=> 0, + mark_open => 0, + problem_state => 'fixed - council', + end_state => 'fixed - council', + }, + { + desc => 'status of CLOSED marks report as fixed - council', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'confirmed', + comment_status => 'CLOSED', mark_fixed=> 0, mark_open => 0, problem_state => 'fixed - council', end_state => 'fixed - council', }, { - desc => 'comment re-opens fixed report', + desc => 'status of OPEN re-opens fixed report', updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), description => 'This is a note', external_id => 638344, start_state => 'fixed - user', - close_comment => 0, + comment_status => 'OPEN', mark_fixed => 0, mark_open => 0, problem_state => 'confirmed', end_state => 'confirmed', }, { - desc => 'comment re-opens closed report', + desc => 'action sheduled re-opens fixed report as action scheduled', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'fixed - user', + comment_status => 'ACTION_SCHEDULED', + mark_fixed => 0, + mark_open => 0, + problem_state => 'action scheduled', + end_state => 'action scheduled', + }, + { + desc => 'open status re-opens closed report', updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), description => 'This is a note', external_id => 638344, - start_state => 'closed', - close_comment => 0, + start_state => 'not responsible', + comment_status => 'OPEN', mark_fixed => 0, mark_open => 0, problem_state => 'confirmed', end_state => 'confirmed', }, { - desc => 'comment leaves report closed', + desc => 'fixed status leaves fixed - user report as fixed - user', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'fixed - user', + comment_status => 'FIXED', + mark_fixed => 0, + mark_open => 0, + problem_state => undef, + end_state => 'fixed - user', + }, + { + desc => 'closed status updates fixed report', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'fixed - user', + comment_status => 'NO_FURTHER_ACTION', + mark_fixed => 0, + mark_open => 0, + problem_state => 'unable to fix', + end_state => 'unable to fix', + }, + { + desc => 'no futher action status closes report', + updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), + description => 'This is a note', + external_id => 638344, + start_state => 'confirmed', + comment_status => 'NO_FURTHER_ACTION', + mark_fixed => 0, + mark_open => 0, + problem_state => 'unable to fix', + end_state => 'unable to fix', + }, + { + desc => 'fixed status sets closed report as fixed', updated_datetime => sprintf( '<updated_datetime>%s</updated_datetime>', $dt ), description => 'This is a note', external_id => 638344, - start_state => 'closed', - close_comment => 1, + start_state => 'unable to fix', + comment_status => 'FIXED', mark_fixed => 0, mark_open => 0, - end_state => 'closed', + problem_state => 'fixed - council', + end_state => 'fixed - council', }, ) { subtest $test->{desc} => sub { @@ -195,7 +329,7 @@ for my $test ( $local_requests_xml =~ s/UPDATED_DATETIME/$test->{updated_datetime}/; $local_requests_xml =~ s#<service_request_id>\d+</service_request_id>#<service_request_id>@{[$problem->external_id]}</service_request_id>#; $local_requests_xml =~ s#<service_request_id_ext>\d+</service_request_id_ext>#<service_request_id_ext>@{[$problem->id]}</service_request_id_ext>#; - $local_requests_xml =~ s#<status>\w+</status>#<status>closed</status># if $test->{close_comment}; + $local_requests_xml =~ s#<status>\w+</status>#<status>$test->{comment_status}</status># if $test->{comment_status}; my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'servicerequestupdates.xml' => $local_requests_xml } ); diff --git a/templates/web/bromley/report/display.html b/templates/web/bromley/report/display.html index 13bc5f960..5288041f9 100644 --- a/templates/web/bromley/report/display.html +++ b/templates/web/bromley/report/display.html @@ -77,9 +77,11 @@ [% IF c.user && c.user.belongs_to_council( problem.council ) %] <label for="form_state">[% loc( 'State' ) %]</label> <select name="state" id="form_state"> - [% FOREACH state IN [ ['confirmed', loc('Open')], ['investigating', - loc('Investigating')], ['planned', loc('Planned')], ['in progress', - loc('In Progress')], ['closed', loc('Closed')], ['fixed', loc('Fixed')] ] %] + [% FOREACH state IN [ ['confirmed', loc('Open')], ['investigating', + loc('Investigating')], ['action scheduled', loc('Action Scheduled')], + ['in progress', loc('In Progress')], ['duplicate', loc('Duplicate')], + ['unable to fix', loc('Unable to fix')], ['not responsible', loc('Not Responsible')], + ['fixed', loc('Fixed')] ] %] <option [% 'selected ' IF state.0 == problem.state %] value="[% state.0 %]">[% state.1 %]</option> [% END %] </select> diff --git a/templates/web/default/admin/council_contacts.html b/templates/web/default/admin/council_contacts.html index be855cb95..56850a82b 100644 --- a/templates/web/default/admin/council_contacts.html +++ b/templates/web/default/admin/council_contacts.html @@ -161,6 +161,11 @@ </p> <p> + <label for="extended_statuses">Send extended open311 statuses with service request updates</label>: + <input type="checkbox" name="extended_statuses"[% ' checked' IF conf.send_extended_statuses %]> + </p> + + <p> <input type="hidden" name="open311_id" value="[% conf.id %]"> <input type="hidden" name="area_id" value="[% area_id %]"> <input type="hidden" name="posted" value="open311"> diff --git a/templates/web/default/dashboard/index.html b/templates/web/default/dashboard/index.html index 169d7d3fe..f5a3cfba3 100644 --- a/templates/web/default/dashboard/index.html +++ b/templates/web/default/dashboard/index.html @@ -81,7 +81,7 @@ [% rows = { '0' => [ "in progress", "Council has marked as in progress" ] - '1' => [ "planned", "Council has marked as planned" ] + '1' => [ "action scheduled", "Council has marked as planned" ] '2' => [ "investigating", "Council has marked as investigating" ] '3' => [ "closed", "Council has marked as closed" ] }; @@ -98,10 +98,14 @@ <tr class='subtotal' id="marked"> <th scope="row">Total marked</th> - <td>[% problems.wtd.${"in progress"} + problems.wtd.planned + problems.wtd.investigating + problems.wtd.closed %]</td> - <td>[% problems.week.${"in progress"} + problems.week.planned + problems.week.investigating + problems.wtd.closed %]</td> - <td>[% problems.weeks.${"in progress"} + problems.weeks.planned + problems.weeks.investigating + problems.wtd.closed %]</td> - <td>[% problems.ytd.${"in progress"} + problems.ytd.planned + problems.ytd.investigating + problems.wtd.closed %]</td> + <td>[% problems.wtd.${"in progress"} + problems.wtd.${"action scheduled"} + + problems.wtd.investigating + problems.wtd.closed %]</td> + <td>[% problems.week.${"in progress"} + problems.week.${"action scheduled"} + + problems.week.investigating + problems.wtd.closed %]</td> + <td>[% problems.weeks.${"in progress"} + problems.weeks.${"action scheduled"} + + problems.weeks.investigating + problems.wtd.closed %]</td> + <td>[% problems.ytd.${"in progress"} + problems.ytd.${"action scheduled"} + + problems.ytd.investigating + problems.wtd.closed %]</td> </tr> <tr id="avg_fixed"> @@ -136,7 +140,7 @@ <p>Report state: <select name="state"> <option value=''>All</option> [% FOREACH state IN [ ['confirmed', loc('Open')], ['investigating', - loc('Investigating')], ['planned', loc('Planned')], ['in progress', + loc('Investigating')], ['action scheduled', loc('Planned')], ['in progress', loc('In Progress')], ['closed', loc('Closed')], ['fixed', loc('Fixed')] ] %] <option [% 'selected ' IF state.0 == q_state %] value="[% state.0 %]">[% state.1 %]</option> [% END %] diff --git a/templates/web/default/report/banner.html b/templates/web/default/report/banner.html index 85aaed82d..52bfa6e67 100644 --- a/templates/web/default/report/banner.html +++ b/templates/web/default/report/banner.html @@ -14,7 +14,7 @@ [% IF problem.is_closed %] [% INCLUDE banner, id = 'closed', text = loc('This problem has been closed') %] [% END %] -[% states = [ 'investigating', 'in progress', 'planned' ]; +[% states = [ 'investigating', 'in progress', 'planned', 'action scheduled' ]; IF states.grep(problem.state).size %] [% INCLUDE banner, id = 'progress', text = loc('This problem is in progress') %] [% END %] diff --git a/templates/web/default/report/update-form.html b/templates/web/default/report/update-form.html index 7e39f79b7..d993ce28f 100644 --- a/templates/web/default/report/update-form.html +++ b/templates/web/default/report/update-form.html @@ -28,8 +28,10 @@ <label for="form_state">[% loc( 'State:' ) %]</label> <select name="state" id="form_state"> [% FOREACH state IN [ ['confirmed', loc('Open')], ['investigating', - loc('Investigating')], ['planned', loc('Planned')], ['in progress', - loc('In Progress')], ['closed', loc('Closed')], ['fixed', loc('Fixed')] ] %] + loc('Investigating')], ['action scheduled', loc('Action Scheduled')], + ['in progress', loc('In Progress')], ['duplicate', loc('Duplicate')], + ['unable to fix', loc('Unable to fix')], ['not responsible', loc('Not Responsible')], + ['fixed', loc('Fixed')] ] %] <option [% 'selected ' IF state.0 == problem.state %] value="[% state.0 %]">[% state.1 %]</option> [% END %] </select> diff --git a/templates/web/default/report/updates.html b/templates/web/default/report/updates.html index eaf5209ff..736d36528 100644 --- a/templates/web/default/report/updates.html +++ b/templates/web/default/report/updates.html @@ -1,3 +1,4 @@ +[% global.last_state = '' %] [% FOREACH update IN updates %] [% INCLUDE 'report/update.html' %] [% END %] @@ -22,8 +23,20 @@ [%- ELSE %] [% tprintf( loc( 'Posted by %s at %s' ), update.name, prettify_epoch( update.confirmed_local.epoch ) ) | html -%] [%- END -%] - [%- ", " _ loc( 'marked as fixed' ) IF update.mark_fixed %] - [%- ", " _ loc( 'reopened' ) IF update.mark_open OR update.problem_state == 'confirmed' %] - [%- ", " _ tprintf(loc( 'marked as %s' ), update.meta_problem_state) IF update.problem_state AND update.problem_state != 'confirmed' %] + [%- update_state = '' %] + [%- IF update.mark_fixed %][% update_state = ", " _ loc( 'marked as fixed' ) %][% END %] + [%- IF update.mark_open %][% update_state = ", " _ loc( 'reopened' ) %][% END %] + [%- IF !update_state && update.problem_state %] + [%- state = update.meta_problem_state %] + [%- IF c.cobrand.moniker == 'bromley' AND update.problem_state == 'unable to fix' %] + [%- state = loc('no further action') %] + [% END %] + [%- IF update.problem_state == 'confirmed' %] + [%- update_state = ", " _ loc('reopened') %] + [%- ELSE %] + [%- update_state = ", " _ tprintf(loc( 'marked as %s' ), state ) %] + [% END %] + [%- END %] + [%- update_state IF update_state != global.last_state %] + [%- global.last_state = update_state %] [% END %] - diff --git a/templates/web/fixmystreet/report/banner.html b/templates/web/fixmystreet/report/banner.html index 58712604e..c6201cafc 100644 --- a/templates/web/fixmystreet/report/banner.html +++ b/templates/web/fixmystreet/report/banner.html @@ -5,7 +5,7 @@ </div> [% END %] -[% IF problem.is_open AND date.now - problem.lastupdate_local.epoch > 8 * 7 * 24 * 60 * 60 %] +[% IF c.cobrand.moniker != 'bromley' AND problem.is_open AND date.now - problem.lastupdate_local.epoch > 8 * 7 * 24 * 60 * 60 %] [% INCLUDE banner, id = 'unknown', text = loc('Unknown') %] [% END %] [% IF problem.is_fixed %] @@ -14,8 +14,8 @@ [% IF problem.is_closed %] [% INCLUDE banner, id = 'closed', text = loc('Closed') %] [% END %] -[% states = [ 'investigating', 'in progress', 'planned' ]; - IF states.grep(problem.state).size %] +[% states = [ 'investigating', 'in progress', 'planned', 'action scheduled' ]; + IF c.cobrand.moniker != 'bromley' && states.grep(problem.state).size %] [% INCLUDE banner, id = 'progress', text = loc('In progress') %] [% END %] diff --git a/templates/web/fixmystreet/report/update-form.html b/templates/web/fixmystreet/report/update-form.html index 14efdb51b..a632cfc4a 100644 --- a/templates/web/fixmystreet/report/update-form.html +++ b/templates/web/fixmystreet/report/update-form.html @@ -26,8 +26,10 @@ <label for="form_state">[% loc( 'State' ) %]</label> <select name="state" id="form_state"> [% FOREACH state IN [ ['confirmed', loc('Open')], ['investigating', - loc('Investigating')], ['planned', loc('Planned')], ['in progress', - loc('In Progress')], ['closed', loc('Closed')], ['fixed', loc('Fixed')] ] %] + loc('Investigating')], ['action scheduled', loc('Action Scheduled')], + ['in progress', loc('In Progress')], ['duplicate', loc('Duplicate')], + ['unable to fix', loc('Unable to fix')], ['not responsible', loc('Not Responsible')], + ['fixed', loc('Fixed')] ] %] <option [% 'selected ' IF state.0 == problem.state %] value="[% state.0 %]">[% state.1 %]</option> [% END %] </select> diff --git a/web/cobrands/fixmystreet/_layout.scss b/web/cobrands/fixmystreet/_layout.scss index 7a84af521..28c1b6cb8 100644 --- a/web/cobrands/fixmystreet/_layout.scss +++ b/web/cobrands/fixmystreet/_layout.scss @@ -681,6 +681,15 @@ body.twothirdswidthpage { border-bottom: 0.75em solid $col_fixed_label_dark; } } + &#closed { + padding-top:5em; + background-image:url(/cobrands/fixmystreet/images/sprite.png); + background-position:-318px -326px; + background-repeat:no-repeat; + &:before { + border-bottom: 0.75em solid #666; + } + } } } .ie6 .banner p { |