Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 907818a6

Von Bernd Bleßmann vor mehr als 2 Jahren hinzugefügt

  • ID 907818a6e4953fefc56372ca3dac441d507be315
  • Vorgänger 635b7adc
  • Nachfolger 1570b866

Hintergrund-Job: Erinnerung an WV verschicken

Unterschiede anzeigen:

SL/BackgroundJob/SendFollowUpReminder.pm
1
package SL::BackgroundJob::SendFollowUpReminder;
2

  
3
use strict;
4

  
5
use parent qw(SL::BackgroundJob::Base);
6

  
7
use SL::DB::AuthUser;
8
use SL::DB::FollowUp;
9
use SL::Locale::String qw(t8);
10
use SL::Mailer;
11
use SL::Presenter;
12
use SL::Util qw(trim);
13

  
14
use DateTime;
15
use File::Slurp qw(slurp);
16
use List::Util qw(any);
17
use Try::Tiny;
18
use URI;
19

  
20
sub create_job {
21
  $_[0]->create_standard_job('7 6 1-5 * *'); # every workday at 06:07
22
}
23

  
24
use Rose::Object::MakeMethods::Generic (
25
 'scalar' => [ qw(params) ],
26
);
27

  
28
#
29
# If job does not throw an error,
30
# success in background_job_histories is 'success'.
31
# It is 'failure' otherwise.
32
#
33
# Return value goes to result in background_job_histories.
34
#
35
sub run {
36
  my ($self, $db_obj) = @_;
37

  
38
  $self->{$_} = [] for qw(job_errors);
39

  
40
  $self->initialize_params($db_obj->data_as_hash) if $db_obj;
41

  
42
  my   @follow_up_date_where = ();
43
  push @follow_up_date_where, (follow_up_date => { ge    => [ $self->params->{from_date} ]}) if $self->params->{from_date};
44
  push @follow_up_date_where, (follow_up_date => { le    => [ $self->params->{to_date}   ]}) if $self->params->{to_date};
45

  
46
  my $follow_ups = SL::DB::Manager::FollowUp->get_all(where        => ['done.id' => undef,
47
                                                                       @follow_up_date_where, ],
48
                                                      with_objects => ['done'],
49
                                                      sort_by      => ['follow_up_date']);
50

  
51
  # Collect follow ups for users with e-mail-address.
52
  my $mail_to_by_employee_id;
53
  foreach my $follow_up (@$follow_ups) {
54

  
55
    # add link
56
    $follow_up->{link} = URI->new_abs('fu.pl?action=edit&id=' . $follow_up->id, $::form->_get_request_uri);
57

  
58
    foreach my $employee (@{ $follow_up->created_for_employees }) {
59
      next if $employee->deleted;
60

  
61
      if (!exists $mail_to_by_employee_id->{$employee->id}) {
62
        my $user = SL::DB::Manager::AuthUser->find_by(login => $employee->login);
63
        if ($user) {
64
          my $mail_to = trim($user->get_config_value('email'));
65

  
66
          next if !$mail_to;
67

  
68
          $mail_to_by_employee_id->{$employee->id}->{mail_to} = $mail_to;
69
        }
70
      }
71

  
72
      if (exists $mail_to_by_employee_id->{$employee->id}) {
73
        push @{ $mail_to_by_employee_id->{$employee->id}->{follow_ups} }, $follow_up;
74
      }
75
    }
76
  }
77

  
78
  foreach (keys %$mail_to_by_employee_id) {
79
    my ($message, $content_type) = $self->generate_message($mail_to_by_employee_id->{$_}->{follow_ups});
80

  
81
    my $mail              = Mailer->new;
82
    $mail->{from}         = $self->params->{email_from};
83
    $mail->{to}           = $mail_to_by_employee_id->{$_}->{mail_to};
84
    $mail->{bcc}          = SL::DB::Default->get->global_bcc;
85
    $mail->{subject}      = $self->params->{email_subject};
86
    $mail->{message}      = $message;
87
    $mail->{content_type} = $content_type;
88

  
89
    my $error = $mail->send;
90

  
91
    if ($error) {
92
      push @{ $self->{job_errors} }, $error;
93
    }
94
  }
95

  
96
  my $msg = t8('Follow ups reminder sent.');
97

  
98
  # die if errors exists
99
  if (@{ $self->{job_errors} }) {
100
    $msg .= t8('The following errors occurred:');
101
    $msg .= join "\n", @{ $self->{job_errors} };
102
    die $msg . "\n";
103
  }
104

  
105
  return $msg;
106
}
107

  
108
# helper
109
sub initialize_params {
110
  my ($self, $data) = @_;
111

  
112
  # valid parameters with default values
113
  my %valid_params = (
114
    from_date      => undef,
115
    to_date        => DateTime->today_local->to_kivitendo,
116
    email_from     => $::lx_office_conf{follow_up_reminder}->{email_from},
117
    email_subject  => $::lx_office_conf{follow_up_reminder}->{email_subject},
118
    email_template => $::lx_office_conf{follow_up_reminder}->{email_template},
119
  );
120

  
121
  # check user input param names
122
  foreach my $param (keys %$data) {
123
    die "Not a valid parameter: $param" unless exists $valid_params{$param};
124
  }
125

  
126
  # set defaults
127
  $self->params(
128
    { map { ($_ => $data->{$_} // $valid_params{$_}) } keys %valid_params }
129
  );
130

  
131
  # convert date from string to object
132
  my ($from_date, $to_date);
133
  try {
134
    if ($self->params->{from_date}) {
135
      $from_date = DateTime->from_kivitendo($self->params->{from_date});
136
      # Not undef and no other type.
137
      die unless ref $from_date eq 'DateTime';
138
    }
139
    if ($self->params->{to_date}) {
140
      $to_date = DateTime->from_kivitendo($self->params->{to_date});
141
      # Not undef and no other type.
142
      die unless ref $to_date eq 'DateTime';
143
    }
144
  } catch {
145
    die t8("Cannot convert date.") ."\n" .
146
        t8("Input from string: #1", $self->params->{from_date}) . "\n" .
147
        t8("Input to string: #1",   $self->params->{to_date})   . "\n" .
148
        t8("Details: #1", $_);
149
  };
150

  
151
  $self->params->{from_date} = $from_date;
152
  $self->params->{to_date}   = $to_date;
153

  
154
  $self->params->{email_from} = trim($self->params->{email_from});
155
  die t8('No email sender address given.') if !$self->params->{email_from};
156

  
157
  return $self->params;
158
}
159

  
160
sub generate_message {
161
  my ($self, $follow_ups) = @_;
162

  
163
  # Force scripts/locales.pl to parse this template:
164
  # parse_html_template('fu/follow_up_reminder_mail')
165
  my $email_template = $self->params->{email_template};
166
  my $template       = 'fu/follow_up_reminder_mail';
167
  my $content_type   = 'text/html';
168
  my $render_type    = 'html';
169

  
170
  if ($email_template) {
171
    my $content;
172
    try {
173
      $content = slurp $email_template;
174

  
175
    } catch {
176
      $::lxdebug->message(LXDebug->WARN(), 'Cannot read template file. Error: ' . $_);
177
    };
178

  
179
    return $self->generate_message_simple_text($follow_ups) if !$content;
180

  
181
    $template     = \$content;
182
    $content_type = $email_template =~ m/.html$/ ? 'text/html' : 'text/plain';
183
    $render_type  = $email_template =~ m/.html$/ ? 'html'      : 'text';
184
  }
185

  
186
  my $output = SL::Presenter->get->render($template,
187
                                          {type => $render_type},
188
                                          follow_ups => $follow_ups);
189

  
190
  return ($output, $content_type);
191
}
192

  
193
sub generate_message_simple_text {
194
  my ($self, $follow_ups) = @_;
195

  
196
  my $output = t8('Unfinished follow-ups') . ":\n";
197
  foreach my $follow_up (@$follow_ups) {
198
    $output .= t8('Follow-Up Date') . ': ' . $follow_up->follow_up_date_as_date;
199
    $output .= ': ' . $follow_up->note->subject;
200
    $output .= ': (' . t8('by') . ' ' . $follow_up->created_by_employee->safe_name . ')';
201
    $output .= ' (' . $follow_up->{link} . ')';
202
    $output .= "\n";
203
  }
204

  
205
  $output .= "\n\n";
206

  
207
  return ($output, 'text/plain');
208
}
209

  
210
1;
211

  
212
__END__
213

  
214
=pod
215

  
216
=encoding utf8
217

  
218
=head1 NAME
219

  
220
SL::BackgroundJob::SendFollowUpReminder - Send emails to employees to
221
remind them of due follow ups
222

  
223
=head1 SYNOPSIS
224

  
225
Get all due follow ups. This are the ones that are not done yet and have a
226
follow up date until today (configurable, see below).
227
For each employee addreesed by this follow ups, an email is send (if the
228
employees email address is configured).
229

  
230
=head1 CONFIGURATION
231

  
232
In the kivitendo configuration file (C<config/kivitendo.conf>) in the section
233
"follow_up_reminder" some settings can be made:
234

  
235
=over 4
236

  
237
=item C<email_from>
238

  
239
The senders email address. This information can be overwriten by
240
data provided to the background job.
241

  
242
=item C<email_subject>
243

  
244
The subject of the emails. This information can be overwriten by
245
data provided to the background job.
246

  
247
=item C<email_template>
248

  
249
A template file used to generate the emails content. It will be given an
250
array of the follow ups in the template variable C<follow_ups>.
251
You can provide a text or a html template.
252
If not given, it defaults to C<fu/follow_up_reminder_mail.html> in the
253
webpages directory.
254
If given, but not found, a simple text version will be generated as
255
content.
256
This information can be overwriten by data provided to the background job.
257

  
258
=back
259

  
260
Also some data can be provided to configure this backgroung job.
261
If there is data provided and it cannot be validated the background job
262
fails.
263

  
264
Example:
265

  
266
  from_date: 01.01.2022
267
  to_date: 01.07.2022
268
  email_subject: To-Do
269

  
270
=over 4
271

  
272
=item C<from_date>
273

  
274
The date from which on follow ups not done yet should be collected. It defaults
275
undef which means from the beginning on.
276

  
277
Example (format depends on your settings):
278

  
279
from_date: 01.01.2022
280

  
281
=item C<to_date>
282

  
283
The date till which follow ups not done yet should be collected. It defaults
284
to today.
285

  
286
Example (format depends on your settings):
287

  
288
to_date: 01.07.2022
289

  
290
=item C<email_from>
291

  
292
The senders email address. It defaults to the one given in the kivitendo
293
configuration file (see above). This information must be provided some
294
how.
295

  
296
Example:
297

  
298
email_from: bernd@kivitendo.de
299

  
300
=item C<email_subject>
301

  
302
The subject of the emails.
303
It defaults to the one given in the kvitendo configuration file (see above).
304

  
305
email_subject: To-Do
306

  
307
=item C<email_template>
308

  
309
A template file used to generate the emails content. It will be given an
310
array of the follow ups in the template variable C<follow_ups>. You can
311
provide a text or a html template.
312
It defaults to the one given in the kvitendo configuration file (see above).
313

  
314
email_template: templates/my_templates/my_reminder_template.txt
315

  
316
=back
317

  
318
=head1 AUTHOR
319

  
320
Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
321

  
322
=cut
config/kivitendo.conf.default
256 256
# template. currently txt and html templates are recognized and correctly mime send.
257 257
email_template = templates/mail/self_test/status_mail.txt
258 258

  
259
[follow_up_reminder]
260
# Email notifications for due follow ups.
261
# The "From:" header for said email.
262
email_from     = kivitendo Daemon <root@localhost>
263
# The subject for said email.
264
email_subject  = kivitendo: fällige Wiedervorlagen
265
# The template file used for the email's body.
266
# If empty fu/follow_up_reminder_mail.html will be used.
267
email_template =
268

  
259 269
[console]
260 270
# Automatic login will only work if both "client" and "login" are
261 271
# given.  "client" can be a client's database ID or its name. "login"
doc/changelog
23 23
   die Information weiterer Positionen lässt sich aus- und einklappen.
24 24
 - Wiedervorlagen können für mehrere Benutzer angelegt werden. Zudem können
25 25
   die Benutzer aus den Benutzergruppen gewählt werden.
26
 - Erinnerungen an fällige Wiedervorlagen können an Benutzer gemailt werden.
27
   Dazu gibt es einen Hintergrund-Job (SendFollowUpReminder), der angelegt und
28
   aktiviert werden kann.
26 29

  
27 30
Kleinere neue Features und Detailverbesserungen:
28 31

  
locale/de/all
1594 1594
  'Fixed value'                 => 'Fester Wert',
1595 1595
  'Focus position after update' => 'Eingabe-Fokus-Position nach Erneuern',
1596 1596
  'Folgekonto'                  => 'Folgekonto',
1597
  'Follow ups reminder sent.'   => 'Erinnerung an Wiedervorlagen versendet.',
1597 1598
  'Follow-Up'                   => 'Wiedervorlage',
1598 1599
  'Follow-Up Date'              => 'Wiedervorlagedatum',
1599 1600
  'Follow-Up On'                => 'Wiedervorlage am',
......
2251 2252
  'No email for current user #1 defined.' => 'Keine E-Mail-Adresse für den angemeldeten Benutzer #1 definiert.',
2252 2253
  'No email for user with login #1 defined.' => 'Keine E-Mail-Adresse für den Benutzer mit dem Login #1 definiert.',
2253 2254
  'No email recipient for customer #1 defined.' => 'Keine E-Mail-Adresse (Rechnungs- oder global) für den Kunden #1 definiert.',
2255
  'No email sender address given.' => 'Es ist keine E-Mail-Absender-Adresse angegeben.',
2254 2256
  'No end date given, setting to today' => 'Kein Enddatum gegeben, setze Enddatum auf heute',
2255 2257
  'No entries can be imported.' => 'Es können keine Einträge importiert werden.',
2256 2258
  'No entries have been imported yet.' => 'Es wurden noch keine Einträge importiert.',
locale/en/all
1594 1594
  'Fixed value'                 => '',
1595 1595
  'Focus position after update' => '',
1596 1596
  'Folgekonto'                  => '',
1597
  'Follow ups reminder sent.'   => '',
1597 1598
  'Follow-Up'                   => '',
1598 1599
  'Follow-Up Date'              => '',
1599 1600
  'Follow-Up On'                => '',
......
2251 2252
  'No email for current user #1 defined.' => '',
2252 2253
  'No email for user with login #1 defined.' => '',
2253 2254
  'No email recipient for customer #1 defined.' => '',
2255
  'No email sender address given.' => '',
2254 2256
  'No end date given, setting to today' => '',
2255 2257
  'No entries can be imported.' => '',
2256 2258
  'No entries have been imported yet.' => '',
templates/webpages/fu/follow_up_reminder_mail.html
1
[%- USE T8 %]
2
[%- USE HTML %]
3
<!DOCTYPE HTML>
4
<html>
5
 <head>
6
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
7
 </head>
8

  
9
 <body>
10
  <h2>[% 'Unfinished follow-ups' | $T8 %]</h2>
11

  
12
  <table>
13
   <tr>
14
    <th>[% 'Follow-Up Date' | $T8 %]</th>
15
    <th>[% 'Subject' | $T8 %]</th>
16
    <th>[% 'Created by' | $T8 %]</th>
17
   </tr>
18

  
19
   [%- FOREACH fu = follow_ups %]
20
   <tr>
21
    <td>[% HTML.escape(fu.follow_up_date_as_date) %]</td>
22
    <td><a href="[% fu.link %]">[% HTML.escape(fu.note.subject) %]</a></td>
23
    <td>[% HTML.escape(fu.created_by_employee.safe_name) %]</td>
24
   </tr>
25
   [%- END %]
26
  </table>
27
 </body>
28
</html>

Auch abrufbar als: Unified diff