aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/SendReport
diff options
context:
space:
mode:
authorDave Whiteland <dave@mysociety.org>2012-05-29 15:57:41 +0100
committerDave Whiteland <dave@mysociety.org>2012-05-29 15:57:41 +0100
commit67da8efc720d2d0bd22bd9fe8655b7e983b35bb4 (patch)
tree38b8570647124df06c637d4b923f6010211ef328 /perllib/FixMyStreet/SendReport
parent40b3a51d33caefa8f5fb97ce9be18ef936c7e260 (diff)
parent131ff6e9bf3626d6a8fff6ae54669d250148a63a (diff)
Merge remote branch 'origin/master' into fmb-read-only
Conflicts: bin/send-reports perllib/FixMyStreet/Cobrand/Default.pm perllib/FixMyStreet/Cobrand/FixMyStreet.pm templates/web/fixmystreet/alert/index.html templates/web/fixmystreet/around/display_location.html web/cobrands/fixmystreet/_layout.scss web/js/map-OpenLayers.js
Diffstat (limited to 'perllib/FixMyStreet/SendReport')
-rw-r--r--perllib/FixMyStreet/SendReport/Barnet.pm222
-rw-r--r--perllib/FixMyStreet/SendReport/EastHants.pm62
-rw-r--r--perllib/FixMyStreet/SendReport/Email.pm111
-rw-r--r--perllib/FixMyStreet/SendReport/EmptyHomes.pm51
-rw-r--r--perllib/FixMyStreet/SendReport/London.pm113
-rw-r--r--perllib/FixMyStreet/SendReport/Open311.pm125
6 files changed, 684 insertions, 0 deletions
diff --git a/perllib/FixMyStreet/SendReport/Barnet.pm b/perllib/FixMyStreet/SendReport/Barnet.pm
new file mode 100644
index 000000000..9a54dd91d
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/Barnet.pm
@@ -0,0 +1,222 @@
+package FixMyStreet::SendReport::Barnet;
+
+use Moose;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+use BarnetInterfaces::service::ZLBB_SERVICE_ORDER;
+use Encode;
+use Utils;
+use mySociety::Config;
+use mySociety::Web qw(ent);
+
+# maximum number of webservice attempts to send before not trying any more (XXX may be better in config?)
+use constant SEND_FAIL_RETRIES_CUTOFF => 3;
+
+# specific council numbers
+use constant COUNCIL_ID_BARNET => 2489;
+use constant MAX_LINE_LENGTH => 132;
+
+sub should_skip {
+ my $self = shift;
+ my $problem = shift;
+
+ my $council_name = 'Barnet';
+ my $err_msg = "";
+
+ if ($problem->send_fail_count >= SEND_FAIL_RETRIES_CUTOFF) {
+ $council_name &&= " to $council_name";
+ $err_msg = "skipped: problem id=" . $problem->id . " send$council_name has failed "
+ . $problem->send_fail_count . " times, cutoff is " . SEND_FAIL_RETRIES_CUTOFF;
+
+ $self->skipped( $err_msg );
+
+ return 1;
+ }
+}
+
+sub construct_message {
+ my %h = @_;
+ my $message = <<EOF;
+Subject: $h{title}
+
+Details: $h{detail}
+
+$h{fuzzy}, or to provide an update on the problem, please visit the following link:
+
+$h{url}
+
+$h{closest_address}
+EOF
+}
+
+
+sub send {
+ my ( $self, $problem, $h, $to, $template, $recips, $nomail ) = @_;
+
+ my %h = %$h;
+
+ $h{message} = construct_message(%h);
+
+ my $return = 1;
+ my $err_msg = "";
+
+ my $default_kbid = 14; # This is the default, "Street Scene"
+ my $kbid = sprintf( "%050d", Utils::barnet_categories()->{$h{category}} || $default_kbid);
+
+ my $geo_code = "$h{easting} $h{northing}";
+
+ my $interface = BarnetInterfaces::service::ZLBB_SERVICE_ORDER->new();
+
+ my ($nearest_postcode, $nearest_street) = ('', '');
+ for ($h{closest_address}) {
+ $nearest_postcode = sprintf("%-10s", $1) if /Nearest postcode [^:]+: ((\w{1,4}\s?\w+|\w+))/;
+ # use partial postcode or comma as delimiter, strip leading number (possible letter 221B) off too
+ # "99 Foo Street, London N11 1XX" becomes Foo Street
+ # "99 Foo Street N11 1XX" becomes Foo Street
+ $nearest_street = $1 if /Nearest road [^:]+: (?:\d+\w? )?(.*?)(\b[A-Z]+\d|,|$)/m;
+ }
+ my $postcode = mySociety::PostcodeUtil::is_valid_postcode($h{query})
+ ? $h{query} : $nearest_postcode; # use given postcode if available
+
+ # note: endpoint can be of form 'https://username:password@url'
+ my $council_config = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => COUNCIL_ID_BARNET} )->first;
+ if ($council_config and $council_config->endpoint) {
+ $interface->set_proxy($council_config->endpoint);
+ # Barnet web service doesn't like namespaces in the elements so use a prefix
+ $interface->set_prefix('urn');
+ # uncomment these lines to print XML that will be sent rather
+ # than connecting to the endpoint
+ #$interface->outputxml(1);
+ #$interface->no_dispatch(1);
+ } else {
+ die "Barnet webservice FAIL: looks like you're missing some config data: no endpoint (URL) found for area_id=" . COUNCIL_ID_BARNET;
+ }
+
+ eval {
+ my $result = $interface->Z_CRM_SERVICE_ORDER_CREATE( {
+ ET_RETURN => { # ignored by server
+ item => {
+ TYPE => "", ID => "", NUMBER => "", MESSAGE => "", LOG_NO => "", LOG_MSG_NO => "",
+ MESSAGE_V1 => "", MESSAGE_V2 => "", MESSAGE_V3 => "", MESSAGE_V4 => "", PARAMETER => "",
+ ROW => "", FIELD => "", SYSTEM => "",
+ },
+ },
+ IT_PROBLEM_DESC => { # MyTypes::TABLE_OF_CRMT_SERVICE_REQUEST_TEXT
+ item => [ # MyTypes::CRMT_SERVICE_REQUEST_TEXT
+ map { { TEXT_LINE => $_ } } split_text_with_entities(ent(encode_utf8($h{message})), 132) # char132
+ ],
+ },
+ IV_CUST_EMAIL => truncate_string_with_entities(ent(encode_utf8($h{email})), 241), # char241
+ IV_CUST_NAME => truncate_string_with_entities(ent(encode_utf8($h{name})), 50), # char50
+ IV_KBID => $kbid, # char50
+ IV_PROBLEM_ID => $h{id}, # char35
+ IV_PROBLEM_LOC => { # MyTypes::BAPI_TTET_ADDRESS_COM
+ COUNTRY2 => 'GB', # char2
+ REGION => "", # char3
+ COUNTY => "", # char30
+ CITY => "", # char30
+ POSTALCODE => $postcode, # char10
+ STREET => truncate_string_with_entities(ent(encode_utf8($nearest_street)), 30), # char30
+ STREETNUMBER => "", # char5
+ GEOCODE => $geo_code, # char32
+ },
+ IV_PROBLEM_SUB => truncate_string_with_entities(ent(encode_utf8($h{title})), 40), # char40
+ },
+ );
+ if ($result) {
+ # currently not using this: get_EV_ORDER_GUID (maybe that's the customer number in the CRM)
+ if (my $barnet_id = $result->get_EV_ORDER_NO()) {
+ $problem->external_id( $barnet_id );
+ $problem->external_body( 'Barnet Borough Council' ); # better to use $problem->body()?
+ $problem->send_method_used('barnet');
+ $return = 0;
+ } else {
+ my @returned_items = split /<item[^>]*>/, $result->get_ET_RETURN;
+ my @messages = ();
+ foreach my $item (@returned_items) {
+ if ($item=~/<MESSAGE [^>]*>\s*(\S.*?)<\/MESSAGE>/) { # if there's a non-null MESSAGE in there, grab it
+ push @messages, $1; # best stab at extracting useful error message back from convoluted response
+ }
+ }
+ push @messages, "service returned no external id" unless @messages;
+ $err_msg = "Failed (problem id $h{id}): " . join(" \n ", @messages);
+ }
+ } else {
+ my %fault = (
+ 'code' => $result->get_faultcode(),
+ 'actor' => $result->get_faultactor(),
+ 'string' => $result->get_faultstring(),
+ 'detail' => $result->get_detail(), # possibly only contains debug info
+ );
+ $fault{$_}=~s/^\s*|\s*$//g foreach keys %fault;
+ $fault{actor}&&=" (actor: $fault{actor})";
+ $fault{'detail'} &&= "\n" . $fault{'detail'};
+ $err_msg = "Failed (problem id $h{id}): Fault $fault{code}$fault{actor}\n$fault{string}$fault{detail}";
+ }
+
+ };
+ print "$err_msg\n" if $err_msg;
+ if ($@) {
+ my $e = shift;
+ print "Caught an error: $@\n";
+ }
+ if ( $return ) {
+ $self->error( "Error sending to Barnet: $err_msg" );
+ }
+ $self->success( !$return );
+ return $return;
+}
+
+# for barnet webservice: max-length fields require truncate and split
+
+# truncate_string_with_entities
+# args: text to truncate
+# max number of chars
+# returns: string truncated
+# Note: must not partially truncate an entity (e.g., &amp;)
+sub truncate_string_with_entities {
+ my ($str, $max_len) = @_;
+ my $retVal = "";
+ foreach my $chunk (split /(\&(?:\#\d+|\w+);)/, $str) {
+ if ($chunk=~/^\&(\#\d+|\w+);$/){
+ my $next = $retVal.$chunk;
+ last if length $next > $max_len;
+ $retVal=$next
+ } else {
+ $retVal.=$chunk;
+ if (length $retVal > $max_len) {
+ $retVal = substr($retVal, 0, $max_len);
+ last
+ }
+ }
+ }
+ return $retVal
+}
+
+# split_text_with_entities into lines
+# args: text to be broken into lines
+# max length (option: uses constant MAX_LINE_LENGTH)
+# returns: array of lines
+# Must not to split an entity (e.g., &amp;)
+# Not worrying about hyphenating here, since a word is only ever split if
+# it's longer than the whole line, which is uncommon in genuine problem reports
+sub split_text_with_entities {
+ my ($text, $max_line_length) = @_;
+ $max_line_length ||= MAX_LINE_LENGTH;
+ my @lines;
+ foreach my $line (split "\n", $text) {
+ while (length $line > $max_line_length) {
+ if (! ($line =~ s/^(.{1,$max_line_length})\s// # break on a space
+ or $line =~ s/^(.{1,$max_line_length})(\&(\#\d+|\w+);)/$2/ # break before an entity
+ or $line =~ s/(.{$max_line_length})//)) { # break the word ruthlessly
+ $line =~ s/(.*)//; # otherwise gobble whole line (which is now shorter than max length)
+ }
+ push @lines, $1;
+ }
+ push @lines, $line;
+ }
+ return @lines;
+}
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/EastHants.pm b/perllib/FixMyStreet/SendReport/EastHants.pm
new file mode 100644
index 000000000..681a9d4c4
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/EastHants.pm
@@ -0,0 +1,62 @@
+package FixMyStreet::SendReport::EastHants;
+
+use Moose;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+# export just what we need as error if we use :try
+use Error qw(try otherwise);
+use Encode;
+use mySociety::Web qw(ent);
+use EastHantsWSDL;
+
+sub construct_message {
+ my %h = @_;
+ my $message = '';
+ $message .= "[ This report was also sent to the district council covering the location of the problem, as the user did not categorise it; please ignore if you're not the correct council to deal with the issue. ]\n\n"
+ if $h{multiple};
+ $message .= <<EOF;
+Subject: $h{title}
+
+Details: $h{detail}
+
+$h{fuzzy}, or to provide an update on the problem, please visit the following link:
+
+$h{url}
+
+$h{closest_address}
+EOF
+ return $message;
+}
+
+sub send {
+ return if mySociety::Config::get('STAGING_SITE');
+
+ my ( $self, $row, $h, $to, $template, $recips, $nomail ) = @_;
+
+ # FIXME: should not recreate this each time
+ my $eh_service;
+
+ $h->{category} = 'Customer Services' if $h->{category} eq 'Other';
+ $h->{message} = construct_message( %$h );
+ my $return = 1;
+ $eh_service ||= EastHantsWSDL->on_fault(sub { my($soap, $res) = @_; die ref $res ? $res->faultstring : $soap->transport->status, "\n"; });
+ try {
+ # ServiceName, RemoteCreatedBy, Salutation, FirstName, Name, Email, Telephone, HouseNoName, Street, Town, County, Country, Postcode, Comments, FurtherInfo, ImageURL
+ my $message = ent(encode_utf8($h->{message}));
+ my $name = ent(encode_utf8($h->{name}));
+ my $result = $eh_service->INPUTFEEDBACK(
+ $h->{category}, 'FixMyStreet', '', '', $name, $h->{email}, $h->{phone},
+ '', '', '', '', '', '', $message, 'Yes', $h->{image_url}
+ );
+ $return = 0 if $result eq 'Report received';
+ } otherwise {
+ my $e = shift;
+ print "Caught an error: $e\n";
+ $self->error( "Error sending to East Hants: $e" );
+ };
+ $self->success( !$return );
+ return $return;
+}
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/Email.pm b/perllib/FixMyStreet/SendReport/Email.pm
new file mode 100644
index 000000000..239bee715
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/Email.pm
@@ -0,0 +1,111 @@
+package FixMyStreet::SendReport::Email;
+
+use Moose;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+use mySociety::EmailUtil;
+
+sub build_recipient_list {
+ my $self = shift;
+ my $row = shift;
+ my %recips;
+
+ my $all_confirmed = 1;
+ foreach my $council ( keys %{ $self->councils } ) {
+ my $contact = FixMyStreet::App->model("DB::Contact")->find( {
+ deleted => 0,
+ area_id => $council,
+ category => $row->category
+ } );
+
+ my ($council_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note );
+
+ $council_email = essex_contact($row->latitude, $row->longitude) if $council == 2225;
+ $council_email = oxfordshire_contact($row->latitude, $row->longitude) if $council == 2237 && $council_email eq 'SPECIAL';
+
+ unless ($confirmed) {
+ $all_confirmed = 0;
+ #$note = 'Council ' . $row->council . ' deleted'
+ #unless $note;
+ $council_email = 'N/A' unless $council_email;
+ #$notgot{$council_email}{$row->category}++;
+ #$note{$council_email}{$row->category} = $note;
+ }
+
+ push @{ $self->to }, [ $council_email, $self->councils->{ $council } ];
+ $recips{$council_email} = 1;
+ }
+
+ return () unless $all_confirmed;
+ return keys %recips;
+}
+
+sub send {
+ my $self = shift;
+ my ( $row, $h, $to, $template, $recips, $nomail, $areas_info ) = @_;
+
+ my @recips;
+
+ @recips = $self->build_recipient_list( $row, $areas_info );
+
+ # on a staging server send emails to ourselves rather than the councils
+ if (mySociety::Config::get('STAGING_SITE')) {
+ @recips = ( mySociety::Config::get('CONTACT_EMAIL') );
+ }
+
+ return unless @recips;
+
+ my $result = FixMyStreet::App->send_email_cron(
+ {
+ _template_ => $template,
+ _parameters_ => $h,
+ To => $self->to,
+ From => [ $row->user->email, $row->name ],
+ },
+ mySociety::Config::get('CONTACT_EMAIL'),
+ \@recips,
+ $nomail
+ );
+
+ if ( $result == mySociety::EmailUtil::EMAIL_SUCCESS ) {
+ $self->success(1);
+ } else {
+ $self->error( 'Failed to send email' );
+ }
+
+ return $result;
+}
+
+# Essex has different contact addresses depending upon the district
+# Might be easier if we start storing in the db all areas covered by a point
+# Will do for now :)
+sub essex_contact {
+ my $district = _get_district_for_contact(@_);
+ my $email;
+ $email = 'eastarea' if $district == 2315 || $district == 2312;
+ $email = 'midarea' if $district == 2317 || $district == 2314 || $district == 2316;
+ $email = 'southarea' if $district == 2319 || $district == 2320 || $district == 2310;
+ $email = 'westarea' if $district == 2309 || $district == 2311 || $district == 2318 || $district == 2313;
+ die "Returned district $district which is not in Essex!" unless $email;
+ return "highways.$email\@essexcc.gov.uk";
+}
+
+# Oxfordshire has different contact addresses depending upon the district
+sub oxfordshire_contact {
+ my $district = _get_district_for_contact(@_);
+ my $email;
+ $email = 'northernarea' if $district == 2419 || $district == 2420 || $district == 2421;
+ $email = 'southernarea' if $district == 2417 || $district == 2418;
+ die "Returned district $district which is not in Oxfordshire!" unless $email;
+ return "$email\@oxfordshire.gov.uk";
+}
+
+sub _get_district_for_contact {
+ my ( $lat, $lon ) = @_;
+ my $district =
+ mySociety::MaPit::call( 'point', "4326/$lon,$lat", type => 'DIS' );
+ ($district) = keys %$district;
+ return $district;
+}
+1;
diff --git a/perllib/FixMyStreet/SendReport/EmptyHomes.pm b/perllib/FixMyStreet/SendReport/EmptyHomes.pm
new file mode 100644
index 000000000..9453b4ca5
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/EmptyHomes.pm
@@ -0,0 +1,51 @@
+package FixMyStreet::SendReport::EmptyHomes;
+
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'FixMyStreet::SendReport::Email'; }
+
+sub build_recipient_list {
+ my $self = shift;
+ my $row = shift;
+ my $areas_info = shift;
+ my %recips;
+
+ my $all_confirmed = 1;
+ foreach my $council ( keys %{ $self->councils } ) {
+ my $contact = FixMyStreet::App->model("DB::Contact")->find( {
+ deleted => 0,
+ area_id => $council,
+ category => 'Empty property',
+ } );
+
+ my ($council_email, $confirmed, $note) = ( $contact->email, $contact->confirmed, $contact->note );
+
+ $council_email = essex_contact($row->latitude, $row->longitude) if $council == 2225;
+ $council_email = oxfordshire_contact($row->latitude, $row->longitude) if $council == 2237 && $council_email eq 'SPECIAL';
+
+ unless ($confirmed) {
+ $all_confirmed = 0;
+ #$note = 'Council ' . $row->council . ' deleted'
+ #unless $note;
+ $council_email = 'N/A' unless $council_email;
+ #$notgot{$council_email}{$row->category}++;
+ #$note{$council_email}{$row->category} = $note;
+ }
+
+ push @{ $self->to }, [ $council_email, $self->councils->{ $council } ];
+ $recips{$council_email} = 1;
+
+ my $country = $areas_info->{$council}->{country};
+ if ($country eq 'W') {
+ $recips{ 'shelter@' . mySociety::Config::get('EMAIL_DOMAIN') } = 1;
+ } else {
+ $recips{ 'eha@' . mySociety::Config::get('EMAIL_DOMAIN') } = 1;
+ }
+ }
+
+ return () unless $all_confirmed;
+ return keys %recips;
+}
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/London.pm b/perllib/FixMyStreet/SendReport/London.pm
new file mode 100644
index 000000000..58ecb2375
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/London.pm
@@ -0,0 +1,113 @@
+package FixMyStreet::SendReport::London;
+
+use Moose;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+use Digest::MD5;
+use LWP::UserAgent;
+use LWP::Simple;
+
+use Utils;
+
+sub construct_message {
+ my %h = @_;
+ return <<EOF,
+A user of FixMyStreet has submitted the following report of a local
+problem that they believe might require your attention.
+
+Subject: $h{title}
+
+Details: $h{detail}
+
+$h{fuzzy}, or to provide an update on the problem, please visit the
+following link:
+
+$h{url}
+
+$h{closest_address}
+Yours,
+The FixMyStreet team
+EOF
+}
+
+sub send {
+ return if mySociety::Config::get('STAGING_SITE');
+ my ( $self, $row, $h, $to, $template, $recips, $nomail ) = @_;
+
+ $h->{message} = construct_message( %$h );
+ my $phone = $h->{phone};
+ my $mobile = '';
+ if ($phone && $phone =~ /^\s*07/) {
+ $mobile = $phone;
+ $phone = '';
+ }
+ my ($first, $last) = $h->{name} =~ /^(\S*)(?: (.*))?$/;
+ my %params = (
+ Key => mySociety::Config::get('LONDON_REPORTIT_KEY'),
+ Signature => Digest::MD5::md5_hex( $h->{confirmed} . mySociety::Config::get('LONDON_REPORTIT_SECRET') ),
+ Type => Utils::london_categories()->{$h->{category}},
+ RequestDate => $h->{confirmed},
+ RequestMethod => 'Web',
+ ExternalId => $h->{url},
+ 'Customer.Title' => '',
+ 'Customer.FirstName' => $first,
+ 'Customer.Surname' => $last,
+ 'Customer.Email' => $h->{email},
+ 'Customer.Phone' => $phone,
+ 'Customer.Mobile' => $mobile,
+ 'ProblemDescription' => $h->{message},
+ );
+ if ($h->{used_map}) {
+ $params{'Location.Latitude'} = $h->{latitude};
+ $params{'Location.Longitude'} = $h->{longitude};
+ } elsif (mySociety::PostcodeUtil::is_valid_postcode($h->{query})) {
+ # Didn't use map, and entered postcode, so use that.
+ $params{'Location.Postcode'} = $h->{query};
+ } else {
+ # Otherwise, lat/lon is all we have, even if it's wrong.
+ $params{'Location.Latitude'} = $h->{latitude};
+ $params{'Location.Longitude'} = $h->{longitude};
+ }
+ if ($h->{has_photo}) {
+ $params{'Document1.Name'} = 'Photograph';
+ $params{'Document1.MimeType'} = 'image/jpeg';
+ $params{'Document1.URL'} = $h->{image_url};
+ $params{'Document1.URLPublic'} = 'true';
+ }
+ my $browser = LWP::UserAgent->new;
+ my $response = $browser->post( mySociety::Config::get('LONDON_REPORTIT_URL'), \%params );
+ my $out = $response->content;
+ if ($response->code ne 200) {
+ print "Failed to post $h->{id} to London API, response was " . $response->code . " $out\n";
+ $self->error( "Failed to post $h->{id} to London API, response was " . $response->code . " $out" );
+ return 1;
+ }
+ my ($id) = $out =~ /<caseid>(.*?)<\/caseid>/;
+ my ($org) = $out =~ /<organisation>(.*?)<\/organisation>/;
+ my ($team) = $out =~ /<team>(.*?)<\/team>/;
+
+ $org = london_lookup($org);
+ $row->external_id( $id );
+ $row->external_body( $org );
+ $row->external_team( $team );
+ $self->success(1);
+ return 0;
+}
+
+sub london_lookup {
+ my $org = shift || '';
+ my $str = "Unknown ($org)";
+ open(FP, "$FindBin::Bin/../data/dft.csv");
+ while (<FP>) {
+ /^(.*?),(.*)/;
+ if ($org eq $1) {
+ $str = $2;
+ last;
+ }
+ }
+ close FP;
+ return $str;
+}
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/Open311.pm b/perllib/FixMyStreet/SendReport/Open311.pm
new file mode 100644
index 000000000..845a6295c
--- /dev/null
+++ b/perllib/FixMyStreet/SendReport/Open311.pm
@@ -0,0 +1,125 @@
+package FixMyStreet::SendReport::Open311;
+
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'FixMyStreet::SendReport'; }
+
+use FixMyStreet::App;
+use mySociety::Config;
+use DateTime::Format::W3CDTF;
+use Open311;
+
+sub should_skip {
+ my $self = shift;
+ my $row = shift;
+
+ if ( $row->send_fail_count > 0 ) {
+ if ( bromley_retry_timeout($row) ) {
+ return 1;
+ }
+ }
+}
+
+sub send {
+ my $self = shift;
+ my ( $row, $h, $to, $template, $recips, $nomail ) = @_;
+
+ my $result = -1;
+
+ foreach my $council ( keys %{ $self->councils } ) {
+ my $conf = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => $council, endpoint => { '!=', '' } } )->first;
+
+ my $always_send_latlong = 1;
+ my $send_notpinpointed = 0;
+
+ my $basic_desc = 0;
+
+ # Extra bromley fields
+ if ( $row->council =~ /2482/ ) {
+
+ my $extra = $row->extra;
+ if ( $row->used_map || ( !$row->used_map && !$row->postcode ) ) {
+ push @$extra, { name => 'northing', value => $h->{northing} };
+ push @$extra, { name => 'easting', value => $h->{easting} };
+ }
+ push @$extra, { name => 'report_url', value => $h->{url} };
+ push @$extra, { name => 'service_request_id_ext', value => $row->id };
+ push @$extra, { name => 'report_title', value => $row->title };
+ push @$extra, { name => 'public_anonymity_required', value => $row->anonymous ? 'TRUE' : 'FALSE' };
+ push @$extra, { name => 'email_alerts_requested', value => 'FALSE' }; # always false as can never request them
+ push @$extra, { name => 'requested_datetime', value => DateTime::Format::W3CDTF->format_datetime($row->confirmed_local->set_nanosecond(0)) };
+ push @$extra, { name => 'email', value => $row->user->email };
+ $row->extra( $extra );
+
+ $always_send_latlong = 0;
+ $send_notpinpointed = 1;
+
+ $basic_desc = 1;
+ }
+
+ # FIXME: we've already looked this up before
+ my $contact = FixMyStreet::App->model("DB::Contact")->find( {
+ deleted => 0,
+ area_id => $conf->area_id,
+ category => $row->category
+ } );
+
+ my $open311 = Open311->new(
+ jurisdiction => $conf->jurisdiction,
+ endpoint => $conf->endpoint,
+ api_key => $conf->api_key,
+ always_send_latlong => $always_send_latlong,
+ send_notpinpointed => $send_notpinpointed,
+ basic_description => $basic_desc,
+ );
+
+ # non standard west berks end points
+ if ( $row->council =~ /2619/ ) {
+ $open311->endpoints( { services => 'Services', requests => 'Requests' } );
+ }
+
+ # required to get round issues with CRM constraints
+ if ( $row->council =~ /2218/ ) {
+ $row->user->name( $row->user->id . ' ' . $row->user->name );
+ }
+
+ my $resp = $open311->send_service_request( $row, $h, $contact->email );
+
+ # make sure we don't save user changes from above
+ if ( $row->council =~ /2218/ || $row->council =~ /2482/ ) {
+ $row->discard_changes();
+ }
+
+ if ( $resp ) {
+ $row->external_id( $resp );
+ $result *= 0;
+ $self->success( 1 );
+ } else {
+ $result *= 1;
+ # temporary fix to resolve some issues with west berks
+ if ( $row->council =~ /2619/ ) {
+ $result *= 0;
+ }
+ }
+ }
+
+ $self->error( 'Failed to send over Open311' ) unless $self->success;
+
+ return $result;
+}
+
+sub bromley_retry_timeout {
+ my $row = shift;
+
+ my $tz = DateTime::TimeZone->new( name => 'local' );
+ my $now = DateTime->now( time_zone => $tz );
+ my $diff = $now - $row->send_fail_timestamp;
+ if ( $diff->in_units( 'minutes' ) < 30 ) {
+ return 1;
+ }
+
+ return 0;
+}
+
+1;