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