aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet')
-rw-r--r--perllib/FixMyStreet/App.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm13
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/ExorDefects.pm219
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/ResponsePriorities.pm1
-rw-r--r--perllib/FixMyStreet/App/Controller/Report.pm19
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm9
-rw-r--r--perllib/FixMyStreet/Cobrand/Base.pm12
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm11
-rw-r--r--perllib/FixMyStreet/Cobrand/Oxfordshire.pm35
-rw-r--r--perllib/FixMyStreet/Cobrand/UKCouncils.pm2
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm28
-rw-r--r--perllib/FixMyStreet/DB/Result/ResponsePriority.pm6
-rw-r--r--perllib/FixMyStreet/Script/Reports.pm4
-rw-r--r--perllib/FixMyStreet/SendReport/Email.pm2
14 files changed, 328 insertions, 35 deletions
diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm
index 7c5ef488b..2fc560bc8 100644
--- a/perllib/FixMyStreet/App.pm
+++ b/perllib/FixMyStreet/App.pm
@@ -163,7 +163,7 @@ sub setup_request {
my $cobrand = $c->cobrand;
- $cobrand->add_response_headers if $cobrand->can('add_response_headers');
+ $cobrand->call_hook('add_response_headers');
# append the cobrand templates to the include path
$c->stash->{additional_template_paths} = $cobrand->path_to_web_templates;
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 ],
diff --git a/perllib/FixMyStreet/Cobrand/Base.pm b/perllib/FixMyStreet/Cobrand/Base.pm
index a9eed0018..ea2b8f410 100644
--- a/perllib/FixMyStreet/Cobrand/Base.pm
+++ b/perllib/FixMyStreet/Cobrand/Base.pm
@@ -65,6 +65,18 @@ sub is_default {
return $self->moniker eq 'default';
}
+=head2 call_hook
+
+ $cobrand->call_hook(foo => 1, 2, 3); # calls $cobrand->foo(1, 2, 3) if it exists
+
+=cut
+
+sub call_hook {
+ my ($self, $method_name, @args) = @_;
+ my $method = $self->can($method_name) or return;
+ return $self->$method(@args);
+}
+
# NB: this Base class is for 'meta' features. To add base methods for all cobrands,
# you may want to look at FMS::Cobrand::Default instead!
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index 1fdbe9de2..63db8b64a 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -665,7 +665,6 @@ sub admin_pages {
$pages->{responsepriorities} = [ _('Priorities'), 4 ];
$pages->{responsepriority_edit} = [ undef, undef ];
};
-
if ( $user->has_body_permission_to('user_edit') ) {
$pages->{users} = [ _('Users'), 6 ];
$pages->{user_edit} = [ undef, undef ];
@@ -1188,6 +1187,16 @@ sub category_extra_hidden {
return 0;
}
+=head2 reputation_increment_states/reputation_decrement_states
+
+Get a hashref of states that cause the reporting user's reputation to be
+incremented/decremented, if a report is changed to this state upon inspection.
+
+=cut
+
+sub reputation_increment_states { {} };
+sub reputation_decrement_states { {} };
+
sub traffic_management_options {
return [
_("Yes"),
diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
index e58c7f36b..7fa548406 100644
--- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
+++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
@@ -129,5 +129,40 @@ sub traffic_management_options {
];
}
+sub admin_pages {
+ my $self = shift;
+
+ my $user = $self->{c}->user;
+
+ my $pages = $self->next::method();
+
+ # Oxfordshire have a custom admin page for downloading reports in an Exor-
+ # friendly format which anyone with report_instruct permission can use.
+ if ( $user->is_superuser || $user->has_body_permission_to('report_instruct') ) {
+ $pages->{exordefects} = [ _('Download Exor RDI'), 10 ];
+ }
+
+ return $pages;
+}
+
+sub defect_types {
+ {
+ SFP2 => "SFP2: sweep and fill <1m2",
+ POT2 => "POT2",
+ };
+}
+
+sub exor_rdi_link_id { 1989169 }
+sub exor_rdi_link_length { 50 }
+
+sub reputation_increment_states {
+ return {
+ 'action scheduled' => 1,
+ };
+}
+
+sub user_extra_fields {
+ return [ 'initials' ];
+}
1;
diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
index 4e900e653..e0b6b5298 100644
--- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm
+++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
@@ -76,7 +76,7 @@ sub users_restriction {
my $or_query = [
from_body => $self->council_id,
- id => [ { -in => $problem_user_ids }, { -in => $update_user_ids } ],
+ 'me.id' => [ { -in => $problem_user_ids }, { -in => $update_user_ids } ],
];
if ($self->can('admin_user_domain')) {
my $domain = $self->admin_user_domain;
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index 97cb28fe8..d78eda78f 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -613,9 +613,7 @@ sub meta_line {
my $meta = '';
my $category = $problem->category;
- if ($c->cobrand->can('change_category_text')) {
- $category = $c->cobrand->change_category_text($category);
- }
+ $category = $c->cobrand->call_hook(change_category_text => $category) || $category;
if ( $problem->anonymous ) {
if ( $problem->service and $category && $category ne _('Other') ) {
@@ -748,17 +746,10 @@ sub can_display_external_id {
sub duration_string {
my ( $problem, $c ) = @_;
- my $body;
- if ( $c->cobrand->can('link_to_council_cobrand') ) {
- $body = $c->cobrand->link_to_council_cobrand($problem);
- } else {
- $body = $problem->body( $c );
- }
- if ( $c->cobrand->can('get_body_handler_for_problem') ) {
- my $handler = $c->cobrand->get_body_handler_for_problem( $problem );
- if ( $handler->can('is_council_with_case_management') && $handler->is_council_with_case_management ) {
- return sprintf(_('Received by %s moments later'), $body);
- }
+ my $body = $c->cobrand->call_hook(link_to_council_cobrand => $problem) || $problem->body($c);
+ my $handler = $c->cobrand->call_hook(get_body_handler_for_problem => $problem);
+ if ( $handler && $handler->call_hook('is_council_with_case_management') ) {
+ return sprintf(_('Received by %s moments later'), $body);
}
return unless $problem->whensent;
return sprintf(_('Sent to %s %s later'), $body,
@@ -1109,4 +1100,13 @@ has traffic_management_options => (
},
);
+has inspection_log_entry => (
+ is => 'ro',
+ lazy => 1,
+ default => sub {
+ my $self = shift;
+ return $self->admin_log_entries->search({ action => 'inspected' }, { order_by => { -desc => 'whenedited' } })->first;
+ },
+);
+
1;
diff --git a/perllib/FixMyStreet/DB/Result/ResponsePriority.pm b/perllib/FixMyStreet/DB/Result/ResponsePriority.pm
index 6bc8474fa..44635d174 100644
--- a/perllib/FixMyStreet/DB/Result/ResponsePriority.pm
+++ b/perllib/FixMyStreet/DB/Result/ResponsePriority.pm
@@ -26,6 +26,8 @@ __PACKAGE__->add_columns(
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
"description",
{ data_type => "text", is_nullable => 1 },
+ "external_id",
+ { data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->add_unique_constraint("response_priorities_body_id_name_key", ["body_id", "name"]);
@@ -49,8 +51,8 @@ __PACKAGE__->has_many(
);
-# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-10-17 16:37:28
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:wok3cPA7cPjG4e9lnc1PIg
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-12-14 17:12:09
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:glsO0fLK6fNvg4TmW1DMPg
__PACKAGE__->many_to_many( contacts => 'contact_response_priorities', 'contact' );
diff --git a/perllib/FixMyStreet/Script/Reports.pm b/perllib/FixMyStreet/Script/Reports.pm
index 193c5fa41..a7f3cb84b 100644
--- a/perllib/FixMyStreet/Script/Reports.pm
+++ b/perllib/FixMyStreet/Script/Reports.pm
@@ -112,9 +112,7 @@ sub send(;$) {
$h{user_details} .= sprintf(_('Email: %s'), $row->user->email) . "\n\n";
}
- if ($cobrand->can('process_additional_metadata_for_email')) {
- $cobrand->process_additional_metadata_for_email($row, \%h);
- }
+ $cobrand->call_hook(process_additional_metadata_for_email => $row, \%h);
my $bodies = FixMyStreet::DB->resultset('Body')->search(
{ id => $row->bodies_str_ids },
diff --git a/perllib/FixMyStreet/SendReport/Email.pm b/perllib/FixMyStreet/SendReport/Email.pm
index 4cee58d42..5a287a208 100644
--- a/perllib/FixMyStreet/SendReport/Email.pm
+++ b/perllib/FixMyStreet/SendReport/Email.pm
@@ -84,7 +84,7 @@ sub send {
From => $self->send_from( $row ),
};
- $cobrand->munge_sendreport_params($row, $h, $params) if $cobrand->can('munge_sendreport_params');
+ $cobrand->call_hook(munge_sendreport_params => $row, $h, $params);
$params->{Bcc} = $self->bcc if @{$self->bcc};