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