CTR: Benutzereingabe in data mit Try::Tiny auffangen
[kivitendo-erp.git] / SL / BackgroundJob / ConvertTimeRecordings.pm
1 package SL::BackgroundJob::ConvertTimeRecordings;
2
3 use strict;
4
5 use parent qw(SL::BackgroundJob::Base);
6
7 use SL::DB::DeliveryOrder;
8 use SL::DB::TimeRecording;
9
10 use SL::Locale::String qw(t8);
11
12 use DateTime;
13 use Try::Tiny;
14
15 sub create_job {
16   $_[0]->create_standard_job('7 3 1 * *'); # every first day of month at 03:07
17 }
18
19
20 #
21 # If job does not throw an error,
22 # success in background_job_histories is 'success'.
23 # It is 'failure' otherwise.
24 #
25 # Return value goes to result in background_job_histories.
26 #
27 sub run {
28   my ($self, $db_obj) = @_;
29
30   my $data;
31   $data = $db_obj->data_as_hash if $db_obj;
32
33   # from/to date from data. Defaults to begining and end of last month.
34   my $from_date;
35   my $to_date;
36   # handle errors with a catch handler
37   try {
38     $from_date   = DateTime->from_kivitendo($data->{from_date}) if $data->{from_date};
39     $to_date     = DateTime->from_kivitendo($data->{to_date})   if $data->{to_date};
40   } catch {
41     die "Cannot convert date from string $data->{from_date} $data->{to_date}\n Details :\n $_"; # not $@
42   };
43   $from_date ||= DateTime->new( day => 1,    month => DateTime->today_local->month, year => DateTime->today_local->year)->subtract(months => 1);
44   $to_date   ||= DateTime->last_day_of_month(month => DateTime->today_local->month, year => DateTime->today_local->year)->subtract(months => 1);
45
46   $to_date->add(days => 1); # to get all from the to_date, because of the time part (15.12.2020 23.59 > 15.12.2020)
47
48   my %customer_where;
49   %customer_where = ('customer.customernumber' => $data->{customernumbers}) if 'ARRAY' eq ref $data->{customernumbers};
50
51   my $time_recordings = SL::DB::Manager::TimeRecording->get_all(where        => [end_time => { ge_lt => [ $from_date, $to_date ]},
52                                                                                  or => [booked => 0, booked => undef],
53                                                                                  %customer_where],
54                                                                 with_objects => ['customer']);
55   my %time_recordings_by_customer_id;
56   push @{ $time_recordings_by_customer_id{$_->customer_id} }, $_ for @$time_recordings;
57
58   my @donumbers;
59   my $has_warnings;
60   foreach my $customer_id (keys %time_recordings_by_customer_id) {
61     my $do;
62     if (!eval {
63       $do = SL::DB::DeliveryOrder->new_from_time_recordings($time_recordings_by_customer_id{$customer_id});
64       1;
65     }) {
66       $::lxdebug->message(LXDebug->WARN(),
67                           "ConvertTimeRecordings: creating delivery order failed ($@) for time recording ids " . join ', ', map { $_->id } @{$time_recordings_by_customer_id{$customer_id}});
68       $has_warnings = 1;
69     }
70
71     if ($do) {
72       if (!SL::DB->client->with_transaction(sub {
73         $do->save;
74         $_->update_attributes(booked => 1) for @{$time_recordings_by_customer_id{$customer_id}};
75         1;
76       })) {
77         $::lxdebug->message(LXDebug->WARN(),
78                             "ConvertTimeRecordings: saving delivery order failed for time recording ids " . join ', ', map { $_->id } @{$time_recordings_by_customer_id{$customer_id}});
79         $has_warnings = 1;
80       } else {
81         push @donumbers, $do->donumber;
82       }
83     }
84   }
85
86   my $msg  = t8('Number of deliveryorders created:');
87   $msg    .= ' ';
88   $msg    .= scalar @donumbers;
89   $msg    .= ' (';
90   $msg    .= join ', ', @donumbers;
91   $msg    .= ').';
92   $msg    .= ' ' . t8('There are Warnings.') if $has_warnings;
93   return $msg;
94 }
95
96 1;
97
98 # possible data
99 # from_date: 01.12.2020
100 # to_date: 15.12.2020
101 # customernumbers: [1,2,3]
102 __END__
103
104 =pod
105
106 =encoding utf8
107
108 =head1 NAME
109
110 SL::BackgroundJob::ConvertTimeRecordings - Convert time recording
111 entries into delivery orders
112
113 =head1 SYNOPSIS
114
115 Get all time recording entries for the given period and customer numbers
116 and create delivery ordes out of that (using
117 C<SL::DB::DeliveryOrder-E<gt>new_from_time_recordings>).
118
119 =head1 CONFIGURATION
120
121 Some data can be provided to configure this backgroung job.
122
123 =over 4
124
125 =item C<from_date>
126
127 The date from which on time recordings should be collected. It defaults
128 to the first day of the previous month.
129
130 Example (format depends on your settings):
131
132 from_date: 01.12.2020
133
134 =item C<to_date>
135
136 The date till which time recordings should be collected. It defaults
137 to the last day of the previous month.
138
139 Example (format depends on your settings):
140
141 to_date: 15.12.2020
142
143 =item C<customernumbers>
144
145 An array with the customer numbers for which time recordings should
146 be collected. If not given, time recordings for customers are
147 collected. This is the default.
148
149 Example (format depends on your settings):
150
151 customernumbers: [c1,22332,334343]
152
153 =back
154
155 =head1 AUTHOR
156
157 Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
158
159 =cut