Periodische Rechnungen: find_template-Aufruf gefit
[kivitendo-erp.git] / SL / BackgroundJob / MassRecordCreationAndPrinting.pm
1 package SL::BackgroundJob::MassRecordCreationAndPrinting;
2
3 use strict;
4 use warnings;
5
6 use parent qw(SL::BackgroundJob::Base);
7
8 use SL::DB::DeliveryOrder;
9 use SL::DB::Order;  # origin order to delivery_order
10 use SL::DB::Invoice;
11 use SL::DB::Printer;
12 use SL::SessionFile;
13 use SL::Template;
14 use SL::Locale::String qw(t8);
15 use SL::Helper::MassPrintCreatePDF qw(:all);
16 use SL::Helper::CreatePDF qw(:all);
17 use SL::Helper::File qw(store_pdf append_general_pdf_attachments);
18 use SL::Webdav;
19
20 use constant WAITING_FOR_EXECUTION       => 0;
21 use constant CONVERTING_DELIVERY_ORDERS  => 1;
22 use constant PRINTING_INVOICES           => 2;
23 use constant DONE                        => 3;
24
25 # Data format:
26 # my $data             = {
27 #   record_ids          => [ 123, 124, 127, ],
28 #   printer_id         => 4711,
29 #   copy_printer_id    => 4711,
30 #   transdate          => $today || $custom_transdate,
31 #   num_created        => 0,
32 #   num_printed        => 0,
33 #   invoice_ids        => [ 234, 235, ],
34 #   conversion_errors  => [ { id => 124, number => 'A981723', message => "Stuff went boom" }, ],
35 #   print_errors       => [ { id => 234, number => 'L87123123', message => "Printer is out of coffee" }, ],
36 #   pdf_file_name      => 'qweqwe.pdf',
37 #   session_id         => $::auth->get_session_id,
38 # };
39
40 sub create_invoices {
41   my ($self)  = @_;
42
43   my $job_obj = $self->{job_obj};
44   my $db      = $job_obj->db;
45
46   $job_obj->set_data(status => CONVERTING_DELIVERY_ORDERS())->save;
47
48   foreach my $delivery_order_id (@{ $job_obj->data_as_hash->{record_ids} }) {
49     my $number = $delivery_order_id;
50     my $data   = $job_obj->data_as_hash;
51
52     eval {
53       my $invoice;
54       my $sales_delivery_order = SL::DB::DeliveryOrder->new(id => $delivery_order_id)->load;
55       $number                  = $sales_delivery_order->donumber;
56
57       if (!$db->with_transaction(sub {
58         $invoice = $sales_delivery_order->convert_to_invoice(sub { $data->{transdate} ? ('attributes' => { transdate => $data->{transdate} }) :
59                                                                          undef }->() ) || die $db->error;
60         1;
61       })) {
62         die $db->error;
63       }
64
65       $data->{num_created}++;
66       push @{ $data->{invoice_ids} }, $invoice->id;
67       push @{ $self->{invoices}    }, $invoice;
68
69       1;
70     } or do {
71       push @{ $data->{conversion_errors} }, { id => $delivery_order_id, number => $number, message => $@ };
72     };
73
74     $job_obj->update_attributes(data_as_hash => $data);
75   }
76 }
77
78 sub convert_invoices_to_pdf {
79   my ($self) = @_;
80
81   return if !@{ $self->{invoices} };
82
83   my $job_obj = $self->{job_obj};
84   my $db      = $job_obj->db;
85
86   $job_obj->set_data(status => PRINTING_INVOICES())->save;
87   my $data = $job_obj->data_as_hash;
88
89   my $printer_id = $data->{printer_id};
90   if ( $data->{media} ne 'printer' ) {
91       undef $printer_id;
92       $data->{media} = 'file';
93   }
94   my %variables  = (
95     type         => 'invoice',
96     formname     => 'invoice',
97     format       => 'pdf',
98     media        => $printer_id ? 'printer' : 'file',
99     printer_id   => $printer_id,
100   );
101
102   my @pdf_file_names;
103
104   foreach my $invoice (@{ $self->{invoices} }) {
105
106     eval {
107       my %params = (
108         variables => \%variables,
109         return    => 'file_name',
110         document  => $invoice,
111       );
112       push @pdf_file_names, $self->create_massprint_pdf(%params);
113
114       $data->{num_printed}++;
115
116       # OLD WebDAV Code, may be deleted:
117       # copy file to webdav folder
118       if ($::instance_conf->get_webdav_documents) {
119         my $webdav = SL::Webdav->new(
120           type     => 'invoice',
121           number   => $invoice->invnumber,
122         );
123         my $webdav_file = SL::Webdav::File->new(
124           webdav   => $webdav,
125           filename => t8('Invoice') . '_' . $invoice->invnumber . '.pdf',
126         );
127         eval {
128           $webdav_file->store(file => $pdf_file_names[-1]);
129           1;
130         } or do {
131           push @{ $data->{print_errors} }, { id => $invoice->id, number => $invoice->invnumber, message => $@ };
132         }
133       }
134
135       1;
136
137     } or do {
138       push @{ $data->{print_errors} }, { id => $invoice->id, number => $invoice->invnumber, message => $@ };
139     };
140
141     $job_obj->update_attributes(data_as_hash => $data);
142   }
143
144   $self->merge_massprint_pdf(file_names => \@pdf_file_names, type => 'invoice' ) if scalar(@pdf_file_names) > 0;
145 }
146
147 sub run {
148   my ($self, $job_obj) = @_;
149
150   $self->{job_obj}         = $job_obj;
151   $self->{invoices} = [];
152
153   $self->create_invoices;
154   $self->convert_invoices_to_pdf;
155   $self->print_pdfs;
156
157   $job_obj->set_data(status => DONE())->save;
158
159   return 1;
160 }
161
162 1;
163
164 __END__
165
166 =pod
167
168 =encoding utf8
169
170 =head1 NAME
171
172 SL::BackgroundJob::MassRecordCreationAndPrinting
173
174 =head1 SYNOPSIS
175
176 In controller:
177
178 use SL::BackgroundJob::MassRecordCreationAndPrinting
179
180 my $job              = SL::DB::BackgroundJob->new(
181     type               => 'once',
182     active             => 1,
183     package_name       => 'MassRecordCreationAndPrinting',
184
185   )->set_data(
186     record_ids         => [ map { $_->id } @records[0..$num - 1] ],
187     printer_id         => $::form->{printer_id},
188     copy_printer_id    => $::form->{copy_printer_id},
189     transdate          => $::form->{transdate} || undef,
190     status             => SL::BackgroundJob::MassRecordCreationAndPrinting->WAITING_FOR_EXECUTION(),
191     num_created        => 0,
192     num_printed        => 0,
193     invoice_ids        => [ ],
194     conversion_errors  => [ ],
195     print_errors       => [ ],
196
197   )->update_next_run_at;
198   SL::System::TaskServer->new->wake_up;
199
200 =head1 OVERVIEW
201
202 This background job has 4 states which are described by the four constants above.
203
204 =over 2
205
206 =item * WAITING_FOR_EXECUTION
207   Background has been initialised and needs to be picked up by the task_server
208
209 =item * CONVERTING_DELIVERY_ORDERS
210    Object conversion
211
212 =item * PRINTING_INVOICES
213   Printing, if done via print command
214
215 =item * DONE
216   To release the process and for the user information
217
218 =back
219
220 =head1 FUNCTIONS
221
222 =over 2
223
224 =item C<create_invoices>
225
226 Converts the source objects (DeliveryOrder) to destination objects (Invoice).
227 On success objects will be saved.
228 If param C<data->{transdate}> is set, this will be the transdate. No safety checks are done.
229 The original conversion from order to delivery order had a post_save_sanity_check
230 C<$delivery_order-E<gt>post_save_sanity_check; # just a hint at e8521eee (#90 od)>
231 The params of convert_to_invoice are created on the fly with a anonym sub, as a alternative check
232  perlsecret Enterprise ()x!!
233
234 =item C<convert_invoices_to_pdf>
235
236 Takes the new destination objects and merges them via print template in one pdf.
237
238 =item C<print_pdfs>
239
240 Sent the pdf to the printer command.
241 If param C<data->{copy_printer_id}> is set, the pdf will be sent to a second printer command.
242
243 =back
244
245 =head1 BUGS
246
247 Currently the calculation from the gui (form) differs from the calculation via convert (PTC).
248 Furthermore mass conversion with foreign currencies could lead to problems (daily rate check).
249
250 =head1 TODO
251
252 It would be great to extend this Job for general background printing. The original project
253 code converted sales order to delivery orders (84e7c540) this could be merged in unstable.
254 The states should be CONVERTING_SOURCE_RECORDS, PRINTING_DESTINATION_RECORDS etc
255
256 =head1 AUTHOR
257
258 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
259
260 Jan Büren E<lt>jan@kivitendo-premium.deE<gt>
261
262 =cut