aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/Script/TfL/AutoClose.pm
blob: 687a29e7f61234b00742826d69bb3c96cc2221c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package FixMyStreet::Script::TfL::AutoClose;

use v5.14;

use Moo;
use CronFns;
use FixMyStreet;
use FixMyStreet::Cobrand;
use FixMyStreet::DB;
use Types::Standard qw(InstanceOf Maybe);

has commit => ( is => 'ro', default => 0 );

has verbose => ( is => 'ro', default => 0 );

has body => (
    is => 'lazy',
    isa => Maybe[InstanceOf['FixMyStreet::DB::Result::Body']],
    default => sub {
        my $body = FixMyStreet::DB->resultset('Body')->find({ name => 'TfL' });
        return $body;
    }
);

has days => (
    is => 'ro',
    default => 28
);

sub close {
    my $self = shift;

    die "Can't find body\n" unless $self->body;
    warn "DRY RUN: use --commit to close reports\n" unless $self->commit;
    my $categories = $self->categories;
    $self->close_reports($categories);
}

has newest => (
    is => 'lazy',
    isa => InstanceOf['DateTime'],
    default => sub {
        my $self = shift;
        my $days = $self->days * -1;
        my $date = DateTime->now->add( days => $days )->truncate( to => 'day' );
        return $date;
    }
);

# get list of cateories that have a response template for the fixed
# state marked as auto-response.
sub categories {
    my $self = shift;

    my $templates = FixMyStreet::DB->resultset('ResponseTemplate')->search({
        state => 'fixed - council',
        auto_response => 1,
        body_id => $self->body->id,
    });

    my %categories;
    for my $template ( $templates->all ) {
        map { $categories{$_->category} = $template; } $template->contacts->all;
    }

    return \%categories;
}

# find reports in relevant categories that have been set to action
# scheduled for 30 days.
sub close_reports {
    my ($self, $categories) = @_;

    my $dtf = FixMyStreet::DB->schema->storage->datetime_parser;

    my $reports = FixMyStreet::DB->resultset('Problem')->search({
        category => { -in => [ keys %$categories ] },
        'me.state' => 'action scheduled',
        bodies_str => $self->body->id,
        'comments.state' => 'confirmed',
        'comments.problem_state' => 'action scheduled',
    },
    {
        group_by => 'me.id',
        join => [ 'comments' ],
        having => \[ 'MIN(comments.confirmed) < ?', $dtf->format_datetime($self->newest) ]
    });

    my $count = 0;
    for my $r ( $reports->all ) {
        my $comments = FixMyStreet::DB->resultset('Comment')->search(
            { problem_id => $r->id },
            { order_by => 'confirmed' }
        );
        my $earliest;
        while ( my $c = $comments->next ) {
            if ( $c->problem_state ne 'action scheduled' ) {
                $earliest = undef;
                next;
            }
            $earliest = $c->confirmed unless defined $earliest;
        }
        next unless defined $earliest && $earliest < $self->newest;
        if ($self->commit) {
            $r->update({
                state => 'fixed - council',
                lastupdate => \'current_timestamp',
            });
            my $c = FixMyStreet::DB->resultset('Comment')->new(
                {
                    problem => $r,
                    text => $categories->{$r->category}->text,
                    state => 'confirmed',
                    problem_state => 'fixed - council',
                    user => $self->body->comment_user,
                    confirmed => \'current_timestamp'
                }
            );
            $c->insert;
        }
        $count++;
    }

    say "$count reports closed" if $self->verbose;

    return 1;
}

1;