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