<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">=head1 NAME

FixMyStreet::Cobrand::Northumberland - code specific to the Northumberland cobrand

=head1 SYNOPSIS

=cut

package FixMyStreet::Cobrand::Northumberland;
use base 'FixMyStreet::Cobrand::UKCouncils';

use strict;
use warnings;
use DateTime::Format::W3CDTF;
use Utils;

=head2 Defaults

=over 4

=cut

use Moo;
with 'FixMyStreet::Roles::Open311Alloy';

sub council_area_id { 2248 }
sub council_area { 'Northumberland' }
sub council_name { 'Northumberland County Council' }
sub council_url { 'northumberland' }

sub disambiguate_location {
    my $self    = shift;
    my $string  = shift;

    return {
        centre =&gt; '55.2426024934787,-2.06541585421059',
        span   =&gt; '1.02929721743568,1.22989513596542',
        bounds =&gt; [ 54.7823703267595, -2.68978494847825, 55.8116675441952, -1.45988981251283 ],
    };
}

sub admin_user_domain { 'northumberland.gov.uk' }

sub is_defect {
    my ($self, $p) = @_;
    return $p-&gt;service eq 'Open311';
}

=item * The default map zoom is a bit more zoomed-in

=cut

sub default_map_zoom { 4 }

=item * The default map view shows closed/fixed reports for 14 days

=cut

sub report_age {
    return {
        closed =&gt; '14 days',
        fixed  =&gt; '14 days',
    };
}

=item * Pins are green if closed/fixed, red if confirmed, orange otherwise

=cut

sub pin_colour {
    my ( $self, $p, $context ) = @_;
    return 'green' if $p-&gt;is_closed || $p-&gt;is_fixed;
    return 'red' if $p-&gt;state eq 'confirmed';
    return 'orange'; # all the other `open_states` like "in progress"
}

sub path_to_pin_icons {
    return '/cobrands/northumberland/images/';
}

=item * Hovering over a pin includes the state as well as the title

=cut

sub pin_hover_title {
    my ($self, $problem, $title) = @_;
    my $state = FixMyStreet::DB-&gt;resultset("State")-&gt;display($problem-&gt;state, 1, 'northumberland');
    return "$state: $title";
}

=item * The cobrand doesn't show reports before 3rd May 2023

=cut

sub cut_off_date { '2023-05-03' }

=item * The contact form is for abuse reports only

=cut

sub abuse_reports_only { 1 }

=item * Only staff can reopen reports

=cut

sub reopening_disallowed {
    my ($self, $problem) = @_;

    # Check if reopening is disallowed by the category
    return 1 if $self-&gt;next::method($problem);

    # Only staff can reopen reports.
    my $c = $self-&gt;{c};
    my $user = $c-&gt;user;
    return 0 if ($c-&gt;user_exists &amp;&amp; $user-&gt;from_body &amp;&amp; $user-&gt;from_body-&gt;cobrand_name eq $self-&gt;council_name);
    return 1;
}

=item * Staff Only - Out Of Hours categories are treated as cleaning categories for National Highways

=cut

sub munge_report_new_contacts {
    my ($self, $contacts) = @_;

    $self-&gt;SUPER::munge_report_new_contacts($contacts);

    foreach (@$contacts) {
        if (grep { $_ eq 'Staff Only - Out Of Hours' } @{$_-&gt;groups}) {
            $_-&gt;set_extra_metadata(nh_council_cleaning =&gt; 1);
        }
    }
}

=item * Fetched reports via Open311 use the service name as their title

=cut

sub open311_title_fetched_report {
    my ($self, $request) = @_;
    return $request-&gt;{service_name};
}

=item * The privacy policy is held on Northumberland's own site

=cut

sub privacy_policy_url {
    return 'https://www.northumberland.gov.uk/NorthumberlandCountyCouncil/media/About-the-Council/information%20governance/Privacy-notice-Fix-My-Street.pdf'
}

=item * The CSV export includes staff user/role, assigned to, and response time

=cut

sub dashboard_export_problems_add_columns {
    my ($self, $csv) = @_;

    $csv-&gt;add_csv_columns(
        staff_user =&gt; 'Staff User',
        staff_role =&gt; 'Staff Role',
        assigned_to =&gt; 'Assigned To',
        response_time =&gt; 'Response Time',
    );

    my $response_time = sub {
        my $hashref = shift;
        if (my $response = ($hashref-&gt;{fixed} || $hashref-&gt;{closed}) ) {
            $response = DateTime::Format::W3CDTF-&gt;parse_datetime($response)-&gt;epoch;
            my $confirmed = DateTime::Format::W3CDTF-&gt;parse_datetime($hashref-&gt;{confirmed})-&gt;epoch;
            return Utils::prettify_duration($response - $confirmed, 'minute');
        }
        return '';
    };

    if ($csv-&gt;dbi) {
        $csv-&gt;csv_extra_data(sub {
            my $report = shift;
            my $hashref = shift;
            return {
                user_name_display =&gt; $report-&gt;{name},
                response_time =&gt; $response_time-&gt;($hashref),
            };
        });
        return; # Rest already covered
    }

    my $user_lookup = $self-&gt;csv_staff_users;
    my $userroles = $self-&gt;csv_staff_roles($user_lookup);
    my $problems_to_user = $self-&gt;csv_active_planned_reports;

    $csv-&gt;csv_extra_data(sub {
        my $report = shift;
        my $hashref = shift;

        my $by = $report-&gt;get_extra_metadata('contributed_by');
        my $staff_user = '';
        my $staff_role = '';
        my $assigned_to = '';
        if ($by) {
            $staff_user = $self-&gt;csv_staff_user_lookup($by, $user_lookup);
            $staff_role = join(',', @{$userroles-&gt;{$by} || []});
        }

        return {
            user_name_display =&gt; $report-&gt;name,
            staff_user =&gt; $staff_user,
            staff_role =&gt; $staff_role,
            assigned_to =&gt; $problems_to_user-&gt;{$report-&gt;id} || '',
            response_time =&gt; $response_time-&gt;($hashref),
        };
    });
}

=item * Updates on reports fetched from Alloy are not sent.

=cut

sub should_skip_sending_update {
    my ($self, $comment) = @_;
    my $p = $comment-&gt;problem;
    return $self-&gt;is_defect($p);
}

=back

=cut

1;
</pre></body></html>