Merge branch 'b-3.6.1' of ../kivitendo-erp_20220811
[kivitendo-erp.git] / SL / Controller / MassDeliveryOrderPrint.pm
1 package SL::Controller::MassDeliveryOrderPrint;
2
3 use strict;
4
5 use parent qw(SL::Controller::Base);
6
7 use File::Slurp ();
8 use File::Copy;
9 use List::MoreUtils qw(uniq);
10 use List::Util qw(first);
11
12 use SL::Controller::Helper::GetModels;
13 use SL::BackgroundJob::MassDeliveryOrderPrinting;
14 use SL::DB::Customer;
15 use SL::DB::DeliveryOrder;
16 use SL::DB::Order;
17 use SL::DB::Part;
18 use SL::DB::Printer;
19 use SL::Helper::MassPrintCreatePDF qw(:all);
20 use SL::Helper::CreatePDF qw(:all);
21 use SL::Helper::File qw(store_pdf append_general_pdf_attachments doc_storage_enabled);
22 use SL::Helper::PrintOptions;
23 use SL::Helper::Flash;
24 use SL::Locale::String;
25 use SL::SessionFile;
26 use SL::System::TaskServer;
27
28 use Rose::Object::MakeMethods::Generic
29 (
30   'scalar --get_set_init' => [ qw(delivery_order_models delivery_order_ids printers filter_summary temp_files) ],
31 );
32
33 __PACKAGE__->run_before('setup');
34
35 #
36 # actions
37 #
38 sub action_list_delivery_orders {
39   my ($self) = @_;
40
41   my $show = ($::form->{noshow}?0:1);
42   delete $::form->{noshow};
43
44   if ($::form->{ids}) {
45     my $key = 'MassDeliveryOrderPrint::ids-' . $::form->{ids};
46     $self->delivery_order_ids($::auth->get_session_value($key) || []);
47     $self->delivery_order_models->add_additional_url_params(ids => $::form->{ids});
48   }
49
50   my %selected_ids = map { +($_ => 1) } @{ $self->delivery_order_ids };
51
52   my $pr = SL::DB::Manager::Printer->find_by(
53       printer_description => $::locale->text("sales_delivery_order_printer"));
54   if ($pr ) {
55       $::form->{printer_id} = $pr->id;
56   }
57   $self->render('mass_delivery_order_print/list_delivery_orders',
58                 title        => $::locale->text('Print delivery orders'),
59                 nowshow      => $show,
60                 print_opt    => $self->print_options(hide_language_id => 1),
61                 selected_ids => \%selected_ids);
62 }
63
64 sub action_mass_mdo_download {
65   my ($self) = @_;
66   my $job    = SL::DB::BackgroundJob->new(id => $::form->{job_id})->load;
67
68   my $sfile  = SL::SessionFile->new($job->data_as_hash->{pdf_file_name}, mode => 'r');
69   die $! if !$sfile->fh;
70
71   my $merged_pdf = do { local $/; my $fh = $sfile->fh; <$fh> };
72   $sfile->fh->close;
73
74   my $file_name =  t8('Sales Delivery Orders') . '-' . DateTime->now_local->strftime('%Y%m%d%H%M%S') . '.pdf';
75   $file_name    =~ s{[^\w\.]+}{_}g;
76
77   return $self->send_file(
78     \$merged_pdf,
79     type => 'application/pdf',
80     name => $file_name,
81   );
82 }
83
84 sub action_mass_mdo_status {
85   my ($self) = @_;
86   $::lxdebug->enter_sub();
87   eval {
88     my $job = SL::DB::BackgroundJob->new(id => $::form->{job_id})->load;
89     my $html = $self->render('mass_delivery_order_print/_print_status', { output => 0 }, job => $job);
90
91     $self->js->html('#mass_print_dialog', $html);
92     if ( $job->data_as_hash->{status} == SL::BackgroundJob::MassDeliveryOrderPrinting->DONE() ) {
93       foreach my $dorder_id (@{$job->data_as_hash->{record_ids}}) {
94         $self->js->prop('#multi_id_id_'.$dorder_id,'checked',0);
95       }
96       $self->js->prop('#multi_all','checked',0);
97       $self->js->run('kivi.MassDeliveryOrderPrint.massConversionFinished');
98     }
99     1;
100   } or do {
101     $self->js->run('kivi.MassDeliveryOrderPrint.massConversionFinished')
102       ->run('kivi.MassDeliveryOrderPrint.massConversionFinishProcess')
103       ->flash('error', t8('No such job #1 in the database.',$::form->{job_id}));
104   };
105   $self->js->render;
106
107   $::lxdebug->leave_sub();
108 }
109
110 sub action_mass_mdo_print {
111   my ($self) = @_;
112   $::lxdebug->enter_sub();
113
114   eval {
115     my @do_ids = @{ $::form->{id} || [] };
116     push @do_ids, map { $::form->{"trans_id_$_"} } grep { $::form->{"multi_id_$_"} } (1..$::form->{rowcount});
117
118     my @delivery_orders = map { SL::DB::DeliveryOrder->new(id => $_)->load } @do_ids;
119
120     if (!@delivery_orders) {
121       $self->js->flash('error', t8('No delivery orders have been selected.'));
122     } else {
123       my $job              = SL::DB::BackgroundJob->new(
124         type               => 'once',
125         active             => 1,
126         package_name       => 'MassDeliveryOrderPrinting',
127
128       )->set_data(
129         record_ids         => [ @do_ids ],
130         printer_id         => $::form->{printer_id},
131         formname           => $::form->{formname},
132         format             => $::form->{format},
133         media              => $::form->{media},
134         bothsided          => ($::form->{bothsided}?1:0),
135         copies             => $::form->{copies},
136         status             => SL::BackgroundJob::MassDeliveryOrderPrinting->WAITING_FOR_EXECUTION(),
137         num_created        => 0,
138         num_printed        => 0,
139         printed_ids        => [ ],
140         conversion_errors  => [ ],
141         print_errors       => [ ],
142         session_id         => $::auth->get_session_id,
143
144       )->update_next_run_at;
145
146       SL::System::TaskServer->new->wake_up;
147       my $html = $self->render('mass_delivery_order_print/_print_status', { output => 0 }, job => $job);
148
149       $self->js
150         ->html('#mass_print_dialog', $html)
151         ->run('kivi.MassDeliveryOrderPrint.massConversionPopup')
152         ->run('kivi.MassDeliveryOrderPrint.massConversionStarted');
153     }
154     1;
155   } or do {
156     my $errstr = $@;
157     my $htmlstr = $errstr;
158     $htmlstr =~ s/\n/<br>/g;
159     $self->js->flash('error', t8('Document generating failed. Please check Templates an LateX !'));
160     $self->js->flash_detail('error', $htmlstr);
161   };
162   $self->js->render;
163   $::lxdebug->leave_sub();
164 }
165
166 sub action_downloadpdf {
167   my ($self) = @_;
168   $::lxdebug->enter_sub();
169   if ( $::form->{filename} ) {
170     my $content = scalar File::Slurp::read_file($::form->{filename});
171     my $file_name = $::form->get_formname_translation($::form->{formname}) .
172       '-' . DateTime->now_local->strftime('%Y%m%d%H%M%S') . '.pdf';
173     $file_name    =~ s{[^\w\.]+}{_}g;
174
175     unlink($::form->{filename});
176
177     return $self->send_file(
178       \$content,
179       type => 'application/pdf',
180       name => $file_name,
181     );
182   } else {
183     flash('error', t8('No filename exists!'));
184   }
185   $::lxdebug->leave_sub();
186 }
187
188 #
189 # filters
190 #
191
192 sub init_printers { SL::DB::Manager::Printer->get_all_sorted }
193 sub init_delivery_order_ids { [] }
194 sub init_temp_files { [] }
195
196 sub init_delivery_order_models {
197   my ($self)             = @_;
198   my @delivery_order_ids = @{ $self->delivery_order_ids };
199
200   SL::Controller::Helper::GetModels->new(
201     controller   => $_[0],
202     model        => 'DeliveryOrder',
203     (paginated   => 0,) x !!@delivery_order_ids,
204     sorted       => {
205       _default     => {
206         by           => 'reqdate',
207         dir          => 0,
208       },
209       customer     => t8('Customer'),
210       donumber     => t8('Delivery Order Number'),
211       employee     => t8('Employee'),
212       ordnumber    => t8('Order Number'),
213       reqdate      => t8('Delivery Date'),
214       transdate    => t8('Date'),
215     },
216     with_objects => [ qw(customer employee) ],
217     query        => [
218       '!customer_id' => undef,
219       or             => [ closed    => undef, closed    => 0 ],
220       (id            => \@delivery_order_ids) x !!@delivery_order_ids,
221     ],
222   );
223 }
224
225 sub init_filter_summary {
226   my ($self) =@_;
227   my $filter = $::form->{filter} || { customer => {}, shipto => {}, };
228
229   my @filters;
230   push @filters, t8('Customer')                              . ' ' . $filter->{customer}->{'name:substr::ilike'}     if $filter->{customer}->{'name:substr::ilike'};
231   push @filters, t8('Shipping address (name)')               . ' ' . $filter->{shipto}->{'shiptoname:substr::ilike'} if $filter->{shipto}->{'shiptoname:substr::ilike'};
232   push @filters, t8('Delivery Date') . ' ' . t8('From Date') . ' ' . $filter->{'reqdate:date::ge'}                   if $filter->{'reqdate:date::ge'};
233   push @filters, t8('Delivery Date') . ' ' . t8('To Date')   . ' ' . $filter->{'reqdate:date::le'}                   if $filter->{'reqdate:date::le'};
234
235   return join ', ', @filters;
236 }
237
238 sub setup {
239   my ($self) = @_;
240   $::auth->assert('sales_delivery_order_edit');
241   $::request->layout->use_javascript("${_}.js")  for qw(kivi.MassDeliveryOrderPrint);
242 }
243
244
245 sub generate_documents {
246   my ($self, @delivery_orders) = @_;
247
248   my %pdf_params = (
249     'documents'       => \@delivery_orders ,
250     'variables'       => {
251       'type'            => $::form->{type},
252       'formname'        => $::form->{formname},
253       'language_id'     => '',
254       'format'          => 'pdf',
255       'media'           => 'file',
256       'printer_id'      => $::form->{printer_id},
257     });
258
259   my ($temp_fh, $outname) = File::Temp::tempfile(
260     'kivitendo-outfileXXXXXX',
261     SUFFIX => '.pdf',
262     DIR    => $::lx_office_conf{paths}->{userspath},
263     UNLINK => 0,
264   );
265   close $temp_fh;
266
267   my @pdf_file_names = $self->create_pdfs(%pdf_params);
268   my $fcount = scalar(@pdf_file_names);
269   if ( $fcount < 2 ) {
270     copy($pdf_file_names[0],$outname);
271   } else {
272     if ( !$self->merge_pdfs(file_names => \@pdf_file_names, out_path => $outname, bothsided => $::form->{bothsided} )) {
273       $::lxdebug->leave_sub();
274       return 0;
275     }
276   }
277   foreach my $dorder (@delivery_orders) {
278     $self->js->prop('#multi_id_id_'.$dorder->id,'checked',0);
279   }
280   $self->js->prop('#multi_all','checked',0);
281   return $outname;
282 }
283
284 1;