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