diff options
Diffstat (limited to 'perllib/FixMyStreet/App')
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Admin.pm | 13 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm | 219 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm | 1 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report.pm | 19 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report/New.pm | 9 |
5 files changed, 249 insertions, 12 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index 5d496e7e8..11bdca805 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -1217,6 +1217,8 @@ sub user_add : Path('user_edit') : Args(0) { key => 'users_email_key' } ); $c->stash->{user} = $user; + $c->forward('user_cobrand_extra_fields'); + $user->update; $c->forward( 'log_edit', [ $user->id, 'user', 'edit' ] ); @@ -1281,6 +1283,8 @@ sub user_edit : Path('user_edit') : Args(1) { $user->from_body( undef ); } + $c->forward('user_cobrand_extra_fields'); + # Has the user's from_body changed since we fetched areas (if we ever did)? # If so, we need to re-fetch areas so the UI is up to date. if ( $user->from_body && $user->from_body->id ne $c->stash->{fetched_areas_body_id} ) { @@ -1397,6 +1401,15 @@ sub user_edit : Path('user_edit') : Args(1) { return 1; } +sub user_cobrand_extra_fields : Private { + my ( $self, $c ) = @_; + + my @extra_fields = @{ $c->cobrand->call_hook('user_extra_fields') || [] }; + foreach ( @extra_fields ) { + $c->stash->{user}->set_extra_metadata( $_ => $c->get_param("extra[$_]") ); + } +} + sub flagged : Path('flagged') : Args(0) { my ( $self, $c ) = @_; diff --git a/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm b/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm new file mode 100644 index 000000000..164a4b42d --- /dev/null +++ b/perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm @@ -0,0 +1,219 @@ +package FixMyStreet::App::Controller::Admin::ExorDefects; +use Moose; +use namespace::autoclean; + +use Text::CSV; +use DateTime; +use mySociety::Random qw(random_bytes); + +BEGIN { extends 'Catalyst::Controller'; } + + +sub begin : Private { + my ( $self, $c ) = @_; + + $c->forward('/admin/begin'); +} + +sub index : Path : Args(0) { + my ( $self, $c ) = @_; + + foreach (qw(error_message start_date end_date user_id)) { + if ( defined $c->flash->{$_} ) { + $c->stash->{$_} = $c->flash->{$_}; + } + } + + my @inspectors = $c->cobrand->users->search({ + 'user_body_permissions.permission_type' => 'report_inspect' + }, { + join => 'user_body_permissions', + distinct => 1, + } + )->all; + $c->stash->{inspectors} = \@inspectors; + + # Default start/end date is today + my $now = DateTime->now( time_zone => + FixMyStreet->time_zone || FixMyStreet->local_time_zone ); + $c->stash->{start_date} ||= $now; + $c->stash->{end_date} ||= $now; + +} + +sub download : Path('download') : Args(0) { + my ( $self, $c ) = @_; + + if ( !$c->cobrand->can('exor_rdi_link_id') ) { + # This only works on the Oxfordshire cobrand currently. + $c->detach( '/page_error_404_not_found', [] ); + } + + my $parser = DateTime::Format::Strptime->new( pattern => '%d/%m/%Y' ); + my $start_date = $parser-> parse_datetime ( $c->get_param('start_date') ); + my $end_date = $parser-> parse_datetime ( $c->get_param('end_date') ) ; + my $one_day = DateTime::Duration->new( days => 1 ); + + my %params = ( + -and => [ + state => [ 'action scheduled' ], + 'admin_log_entries.action' => 'inspected', + 'admin_log_entries.whenedited' => { '>=', $start_date }, + 'admin_log_entries.whenedited' => { '<=', $end_date + $one_day }, + ] + ); + + my $user; + if ( $c->get_param('user_id') ) { + my $uid = $c->get_param('user_id'); + $params{'admin_log_entries.user_id'} = $uid; + $user = $c->model('DB::User')->find( { id => $uid } ); + } + + my $problems = $c->cobrand->problems->search( + \%params, + { + join => 'admin_log_entries', + distinct => 1, + } + ); + + if ( !$problems->count ) { + if ( defined $user ) { + $c->flash->{error_message} = _("No inspections by that inspector in the selected date range."); + } else { + $c->flash->{error_message} = _("No inspections in the selected date range."); + } + $c->flash->{start_date} = $start_date; + $c->flash->{end_date} = $end_date; + $c->flash->{user_id} = $user->id if $user; + $c->res->redirect( $c->uri_for( '' ) ); + } + + # A single RDI file might contain inspections from multiple inspectors, so + # we need to group inspections by inspector within G records. + my $inspectors = {}; + my $inspector_initials = {}; + while ( my $report = $problems->next ) { + my $user = $report->inspection_log_entry->user; + $inspectors->{$user->id} ||= []; + push @{ $inspectors->{$user->id} }, $report; + unless ( $inspector_initials->{$user->id} ) { + $inspector_initials->{$user->id} = $user->get_extra_metadata('initials'); + } + } + + my $csv = Text::CSV->new({ binary => 1, eol => "" }); + + my $p_count = 0; + my $link_id = $c->cobrand->exor_rdi_link_id; + + # RDI first line is always the same + $csv->combine("1", "1.8", "1.0.0.0", "ENHN", ""); + my @body = ($csv->string); + + my $i = 0; + foreach my $inspector_id (keys %$inspectors) { + my $inspections = $inspectors->{$inspector_id}; + my $initials = $inspector_initials->{$inspector_id}; + + $csv->combine( + "G", # start of an area/sequence + $link_id, # area/link id, fixed value for our purposes + "","", # must be empty + $initials || "XX", # inspector initials + $start_date->strftime("%y%m%d"), # date of inspection yymmdd + "0700", # time of inspection hhmm, set to static value for now + "D", # inspection variant, should always be D + "INS", # inspection type, always INS + "N", # Area of the county - north (N) or south (S) + "", "", "", "" # empty fields + ); + push @body, $csv->string; + + $csv->combine( + "H", # initial inspection type + "MC" # minor carriageway (changes depending on activity code) + ); + push @body, $csv->string; + + foreach my $report (@$inspections) { + my ($eastings, $northings) = $report->local_coords; + my $description = sprintf("%s %s", $report->external_id || "", $report->get_extra_metadata('detailed_information') || ""); + $csv->combine( + "I", # beginning of defect record + "MC", # activity code - minor carriageway, also FC (footway) + "", # empty field, can also be A (seen on MC) or B (seen on FC) + sprintf("%03d", ++$i), # randomised sequence number + "${eastings}E ${northings}N", # defect location field, which we don't capture from inspectors + $report->inspection_log_entry->whenedited->strftime("%H%M"), # defect time raised + "","","","","","","", # empty fields + $report->get_extra_metadata('traffic_information') ? 'TM required' : 'TM none', # further description + $description, # defect description + ); + push @body, $csv->string; + + $csv->combine( + "J", # georeferencing record + $report->get_extra_metadata('defect_type') || 'SFP2', # defect type - SFP2: sweep and fill <1m2, POT2 also seen + $report->response_priority ? + $report->response_priority->external_id : + "2", # priority of defect + "","", # empty fields + $eastings, # eastings + $northings, # northings + "","","","","" # empty fields + ); + push @body, $csv->string; + + $csv->combine( + "M", # bill of quantities record + "resolve", # permanent repair + "","", # empty fields + "/CMC", # /C + activity code + "", "" # empty fields + ); + push @body, $csv->string; + } + + # end this group of defects with a P record + $csv->combine( + "P", # end of area/sequence + 0, # always 0 + 999999, # charging code, always 999999 in OCC + ); + push @body, $csv->string; + $p_count++; + } + + # end the RDI file with an X record + my $record_count = $i; + $csv->combine( + "X", # end of inspection record + $p_count, + $p_count, + $record_count, # number of I records + $record_count, # number of J records + 0, 0, 0, # always zero + $record_count, # number of M records + 0, # always zero + $p_count, + 0, 0, 0 # error counts, always zero + ); + push @body, $csv->string; + + my $start = $start_date->strftime("%Y%m%d"); + my $end = $end_date->strftime("%Y%m%d"); + my $filename = sprintf("exor_defects-%s-%s.rdi", $start, $end); + if ( $user ) { + my $initials = $user->get_extra_metadata("initials") || ""; + $filename = sprintf("exor_defects-%s-%s-%s.rdi", $start, $end, $initials); + } + $c->res->content_type('text/csv; charset=utf-8'); + $c->res->header('content-disposition' => "attachment; filename=$filename"); + # The RDI format is very weird CSV - each line must be wrapped in + # double quotes. + $c->res->body( join "", map { "\"$_\"\r\n" } @body ); +} + +1;
\ No newline at end of file diff --git a/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm b/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm index a6c13c117..bae0f71a7 100644 --- a/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm +++ b/perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm @@ -70,6 +70,7 @@ sub edit : Path : Args(2) { $priority->deleted( $c->get_param('deleted') ? 1 : 0 ); $priority->name( $c->get_param('name') ); $priority->description( $c->get_param('description') ); + $priority->external_id( $c->get_param('external_id') ); $priority->update_or_insert; my @live_contact_ids = map { $_->id } @live_contacts; diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 175db4a19..35d7afd5b 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -339,16 +339,13 @@ sub inspect : Private { my %update_params = (); if ($permissions->{report_inspect}) { - foreach (qw/detailed_information traffic_information duplicate_of/) { + foreach (qw/detailed_information traffic_information duplicate_of defect_type/) { $problem->set_extra_metadata( $_ => $c->get_param($_) ); } - if ( $c->get_param('save_inspected') ) { + if ( $c->get_param('include_update') ) { $update_text = Utils::cleanup_text( $c->get_param('public_update'), { allow_multiline => 1 } ); - if ($update_text) { - $problem->set_extra_metadata( inspected => 1 ); - $reputation_change = 1; - } else { + if (!$update_text) { $valid = 0; $c->stash->{errors} ||= []; push @{ $c->stash->{errors} }, _('Please provide a public update for this report.'); @@ -374,6 +371,16 @@ sub inspect : Private { } if ( $problem->state ne $old_state ) { $c->forward( '/admin/log_edit', [ $problem->id, 'problem', 'state_change' ] ); + + # If the state has been changed by an inspector, consider the + # report to be inspected. + unless ($problem->get_extra_metadata('inspected')) { + $problem->set_extra_metadata( inspected => 1 ); + $c->forward( '/admin/log_edit', [ $problem->id, 'problem', 'inspected' ] ); + my $state = $problem->state; + $reputation_change = 1 if $c->cobrand->reputation_increment_states->{$state}; + $reputation_change = -1 if $c->cobrand->reputation_decrement_states->{$state}; + } } } diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index 6d90b6ee9..2a68b170e 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -659,8 +659,7 @@ sub setup_categories_and_bodies : Private { push @category_options, _('Other') if $seen{_('Other')}; } - $c->cobrand->munge_category_list(\@category_options, \@contacts, \%category_extras) - if $c->cobrand->can('munge_category_list'); + $c->cobrand->call_hook(munge_category_list => \@category_options, \@contacts, \%category_extras); # put results onto stash for display $c->stash->{bodies} = \%bodies; @@ -903,7 +902,7 @@ sub contacts_to_bodies : Private { if ($c->stash->{unresponsive}{$category} || $c->stash->{unresponsive}{ALL}) { []; } else { - if ( $c->cobrand->can('singleton_bodies_str') && $c->cobrand->singleton_bodies_str ) { + if ( $c->cobrand->call_hook('singleton_bodies_str') ) { # Cobrands like Zurich can only ever have a single body: 'x', because some functionality # relies on string comparison against bodies_str. [ $contacts[0]->body ]; @@ -1033,9 +1032,7 @@ sub send_problem_confirm_email : Private { $template = 'problem-confirm-not-sending.txt' unless $report->bodies_str; $c->stash->{token_url} = $c->uri_for_email( '/P', $token->token ); - if ($c->cobrand->can('problem_confirm_email_extras')) { - $c->cobrand->problem_confirm_email_extras($report); - } + $c->cobrand->call_hook(problem_confirm_email_extras => $report); $c->send_email( $template, { to => [ $report->name ? [ $report->user->email, $report->name ] : $report->user->email ], |