1 #=====================================================================
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
7 #=====================================================================
8 # SQL-Ledger, Accounting
11 # Author: Dieter Simader
12 # Email: dsimader@sql-ledger.org
13 # Web: http://www.sql-ledger.org
16 # This program is free software; you can redistribute it and/or modify
17 # it under the terms of the GNU General Public License as published by
18 # the Free Software Foundation; either version 2 of the License, or
19 # (at your option) any later version.
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 # GNU General Public License for more details.
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
29 #======================================================================
31 # Inventory Control module
33 #======================================================================
35 use POSIX qw(strftime);
36 use List::Util qw(first max);
37 use List::MoreUtils qw(any);
42 use SL::Helper::Flash qw(flash);
44 use SL::ReportGenerator;
52 our ($form, $locale, %myconfig, $lxdebug, $auth);
54 require "bin/mozilla/io.pl";
55 require "bin/mozilla/common.pl";
56 require "bin/mozilla/reportgenerator.pl";
61 # type=submit $locale->text('Add Part')
62 # type=submit $locale->text('Add Service')
63 # type=submit $locale->text('Add Assembly')
64 # type=submit $locale->text('Edit Part')
65 # type=submit $locale->text('Edit Service')
66 # type=submit $locale->text('Edit Assembly')
67 # $locale->text('Parts')
68 # $locale->text('Services')
69 # $locale->text('Inventory quantity must be zero before you can set this part obsolete!')
70 # $locale->text('Inventory quantity must be zero before you can set this assembly obsolete!')
71 # $locale->text('Part Number missing!')
72 # $locale->text('Service Number missing!')
73 # $locale->text('Assembly Number missing!')
74 # $locale->text('ea');
79 $lxdebug->enter_sub();
81 $auth->assert('part_service_assembly_details');
83 $form->{revers} = 0; # switch for backward sorting
84 $form->{lastsort} = ""; # memory for which table was sort at last time
85 $form->{ndxs_counter} = 0; # counter for added entries to top100
87 $form->{title} = (ucfirst $form->{searchitems}) . "s";
88 $form->{title} =~ s/ys$/ies/;
89 $form->{title} = $locale->text($form->{title});
91 $form->{CUSTOM_VARIABLES} = CVar->get_configs('module' => 'IC');
92 ($form->{CUSTOM_VARIABLES_FILTER_CODE},
93 $form->{CUSTOM_VARIABLES_INCLUSION_CODE}) = CVar->render_search_options('variables' => $form->{CUSTOM_VARIABLES},
94 'include_prefix' => 'l_',
95 'include_value' => 'Y');
97 setup_ic_search_action_bar();
100 $form->get_lists('partsgroup' => 'ALL_PARTSGROUPS');
101 print $form->parse_html_template('ic/search');
103 $lxdebug->leave_sub();
107 $::lxdebug->enter_sub();
109 $::auth->assert('part_service_assembly_edit');
111 $::form->{l_soldtotal} = "Y";
112 $::form->{sort} = "soldtotal";
113 $::form->{lastsort} = "soldtotal";
115 $::form->{l_qty} = undef;
116 $::form->{l_linetotal} = undef;
117 $::form->{l_number} = "Y";
118 $::form->{number} = "position";
120 unless ( $::form->{bought}
123 || $::form->{quoted}) {
124 $::form->{bought} = $::form->{sold} = 1;
129 $lxdebug->leave_sub();
134 # Warning, deep magic ahead.
135 # This function parses the requested details, sanity checks them, and converts them into a format thats usable for IC->all_parts
137 # flags coming from the form:
139 # searchitems=part revers=0 lastsort=''
142 # partnumber ean description partsgroup classification serialnumber make model drawing microfiche
143 # transdatefrom transdateto
146 # itemstatus = active | onhand | short | obsolete | orphaned
147 # action = continue | top100
150 # bought sold onorder ordered rfq quoted
151 # l_partnumber l_description l_serialnumber l_unit l_listprice l_sellprice l_lastcost
152 # l_linetotal l_priceupdate l_bin l_rop l_weight l_image l_drawing l_microfiche
153 # l_partsgroup l_subtotal l_soldtotal l_deliverydate l_pricegroups
156 # nextsub revers lastsort sort ndxs_counter
158 sub generate_report {
159 $lxdebug->enter_sub();
161 $auth->assert('part_service_assembly_details');
163 my ($revers, $lastsort, $description);
165 my $cvar_configs = CVar->get_configs('module' => 'IC');
167 $form->{title} = $locale->text('Articles');
170 'bin' => { 'text' => $locale->text('Bin'), },
171 'deliverydate' => { 'text' => $locale->text('deliverydate'), },
172 'description' => { 'text' => $locale->text('Part Description'), },
173 'notes' => { 'text' => $locale->text('Notes'), },
174 'drawing' => { 'text' => $locale->text('Drawing'), },
175 'ean' => { 'text' => $locale->text('EAN'), },
176 'image' => { 'text' => $locale->text('Image'), },
177 'insertdate' => { 'text' => $locale->text('Insert Date'), },
178 'invnumber' => { 'text' => $locale->text('Invoice Number'), },
179 'lastcost' => { 'text' => $locale->text('Last Cost'), },
180 'linetotallastcost' => { 'text' => $locale->text('Extended'), },
181 'linetotallistprice' => { 'text' => $locale->text('Extended'), },
182 'linetotalsellprice' => { 'text' => $locale->text('Extended'), },
183 'listprice' => { 'text' => $locale->text('List Price'), },
184 'microfiche' => { 'text' => $locale->text('Microfiche'), },
185 'name' => { 'text' => $locale->text('Name'), },
186 'onhand' => { 'text' => $locale->text('Stocked Qty'), },
187 'ordnumber' => { 'text' => $locale->text('Order Number'), },
188 'partnumber' => { 'text' => $locale->text('Part Number'), },
189 'partsgroup' => { 'text' => $locale->text('Partsgroup'), },
190 'priceupdate' => { 'text' => $locale->text('Updated'), },
191 'quonumber' => { 'text' => $locale->text('Quotation'), },
192 'rop' => { 'text' => $locale->text('ROP'), },
193 'sellprice' => { 'text' => $locale->text('Sell Price'), },
194 'serialnumber' => { 'text' => $locale->text('Serial Number'), },
195 'soldtotal' => { 'text' => $locale->text('Qty in Selected Records'), },
196 'name' => { 'text' => $locale->text('Name in Selected Records'), },
197 'transdate' => { 'text' => $locale->text('Transdate'), },
198 'unit' => { 'text' => $locale->text('Unit'), },
199 'weight' => { 'text' => $locale->text('Weight'), },
200 'shop' => { 'text' => $locale->text('Shop article'), },
201 'type_and_classific' => { 'text' => $locale->text('Type'), },
202 'projectnumber' => { 'text' => $locale->text('Project Number'), },
203 'projectdescription' => { 'text' => $locale->text('Project Description'), },
206 $revers = $form->{revers};
207 $lastsort = $form->{lastsort};
209 # sorting and direction of sorting
210 # ToDO: change this to the simpler field+direction method
211 if (($form->{lastsort} eq "") && ($form->{sort} eq undef)) {
213 $form->{lastsort} = "partnumber";
214 $form->{sort} = "partnumber";
216 if ($form->{lastsort} eq $form->{sort}) {
217 $form->{revers} = 1 - $form->{revers};
220 $form->{lastsort} = $form->{sort};
224 # special case if we have a serialnumber limit search
225 # serialnumbers are only given in invoices and orders,
226 # so they can only pop up in bought, sold, rfq, and quoted stuff
227 $form->{no_sn_joins} = 'Y' if ( !$form->{bought} && !$form->{sold}
228 && !$form->{rfq} && !$form->{quoted}
229 && ($form->{l_serialnumber} || $form->{serialnumber}));
231 # special case for any checkbox of bought | sold | onorder | ordered | rfq | quoted.
232 # if any of these are ticked the behavior changes slightly for lastcost
233 # since all those are aggregation checks for the legder tables this is an internal switch
234 # refered to as ledgerchecks
235 $form->{ledgerchecks} = 'Y' if ( $form->{bought} || $form->{sold} || $form->{onorder}
236 || $form->{ordered} || $form->{rfq} || $form->{quoted});
238 # if something should be activated if something else is active, enter it here
240 onhand => [ qw(l_onhand) ],
241 short => [ qw(l_onhand) ],
242 onorder => [ qw(l_ordnumber) ],
243 ordered => [ qw(l_ordnumber) ],
244 rfq => [ qw(l_quonumber) ],
245 quoted => [ qw(l_quonumber) ],
246 bought => [ qw(l_invnumber) ],
247 sold => [ qw(l_invnumber) ],
248 ledgerchecks => [ qw(l_name) ],
249 serialnumber => [ qw(l_serialnumber) ],
250 no_sn_joins => [ qw(bought sold) ],
253 # get name of partsgroup if id is given
255 if ($form->{partsgroup_id}) {
256 my $pg = SL::DB::PartsGroup->new(id => $form->{partsgroup_id})->load;
257 $pg_name = $pg->{'partsgroup'};
260 # these strings get displayed at the top of the results to indicate the user which switches were used
262 active => $locale->text('Active'),
263 obsolete => $locale->text('Obsolete'),
264 orphaned => $locale->text('Orphaned'),
265 onhand => $locale->text('On Hand'),
266 short => $locale->text('Short'),
267 onorder => $locale->text('On Order'),
268 ordered => $locale->text('Ordered'),
269 rfq => $locale->text('RFQ'),
270 quoted => $locale->text('Quoted'),
271 bought => $locale->text('Bought'),
272 sold => $locale->text('Sold'),
273 transdatefrom => $locale->text('From') . " " . $locale->date(\%myconfig, $form->{transdatefrom}, 1),
274 transdateto => $locale->text('To (time)') . " " . $locale->date(\%myconfig, $form->{transdateto}, 1),
275 partnumber => $locale->text('Part Number') . ": '$form->{partnumber}'",
276 partsgroup => $locale->text('Partsgroup') . ": '$form->{partsgroup}'",
277 partsgroup_id => $locale->text('Partsgroup') . ": '$pg_name'",
278 serialnumber => $locale->text('Serial Number') . ": '$form->{serialnumber}'",
279 description => $locale->text('Part Description') . ": '$form->{description}'",
280 make => $locale->text('Make') . ": '$form->{make}'",
281 model => $locale->text('Model') . ": '$form->{model}'",
282 drawing => $locale->text('Drawing') . ": '$form->{drawing}'",
283 microfiche => $locale->text('Microfiche') . ": '$form->{microfiche}'",
284 l_soldtotal => $locale->text('Qty in Selected Records'),
285 ean => $locale->text('EAN') . ": '$form->{ean}'",
286 insertdatefrom => $locale->text('Insert Date') . ": " . $locale->text('From') . " " . $locale->date(\%myconfig, $form->{insertdatefrom}, 1),
287 insertdateto => $locale->text('Insert Date') . ": " . $locale->text('To (time)') . " " . $locale->date(\%myconfig, $form->{insertdateto}, 1),
290 my @itemstatus_keys = qw(active obsolete orphaned onhand short);
291 my @callback_keys = qw(onorder ordered rfq quoted bought sold partnumber partsgroup partsgroup_id serialnumber description make model
292 drawing microfiche l_soldtotal l_deliverydate transdatefrom transdateto insertdatefrom insertdateto ean shop all);
294 # calculate dependencies
295 for (@itemstatus_keys, @callback_keys) {
296 next if ($form->{itemstatus} ne $_ && !$form->{$_});
297 map { $form->{$_} = 'Y' } @{ $dependencies{$_} } if $dependencies{$_};
300 # generate callback and optionstrings
302 for my $key (@itemstatus_keys, @callback_keys) {
303 next if ($form->{itemstatus} ne $key && !$form->{$key});
304 push @options, $optiontexts{$key};
307 # special case for lastcost
308 if ($form->{ledgerchecks}){
309 # ledgerchecks don't know about sellprice or lastcost. they just return a
310 # price. so rename sellprice to price, and drop lastcost.
311 $column_defs{sellprice}{text} = $locale->text('Price');
312 $form->{l_lastcost} = ""
315 if ($form->{description}) {
316 $description = $form->{description};
317 $description =~ s/\n/<br>/g;
320 if ($form->{l_linetotal}) {
321 $form->{l_qty} = "Y";
322 $form->{l_linetotalsellprice} = "Y" if $form->{l_sellprice};
323 $form->{l_linetotallastcost} = $form->{searchitems} eq 'assembly' && !$form->{bom} ? "" : 'Y' if $form->{l_lastcost};
324 $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
326 $form->{"l_type_and_classific"} = "Y";
328 if ($form->{l_service} && !$form->{l_assembly} && !$form->{l_part}) {
330 # remove bin, weight and rop from list
331 map { $form->{"l_$_"} = "" } qw(bin weight rop);
333 $form->{l_onhand} = "";
335 # qty is irrelevant unless bought or sold
341 || $form->{quoted}) {
342 # $form->{l_onhand} = "Y";
344 $form->{l_linetotalsellprice} = "";
345 $form->{l_linetotallastcost} = "";
349 # soldtotal doesn't make sense with more than one bsooqr option.
350 # so reset it to sold (the most common option), and issue a warning
352 # also it doesn't make sense without bsooqr. disable and issue a warning too
353 my @bsooqr = qw(sold bought onorder ordered rfq quoted);
354 my $bsooqr_mode = grep { $form->{$_} } @bsooqr;
355 if ($form->{l_subtotal} && 1 < $bsooqr_mode) {
356 my $enabled = first { $form->{$_} } @bsooqr;
357 $form->{$_} = '' for @bsooqr;
358 $form->{$enabled} = 'Y';
360 push @options, $::locale->text('Subtotal cannot distinguish betweens record types. Only one of the selected record types will be displayed: #1', $optiontexts{$enabled});
362 if ($form->{l_soldtotal} && !$bsooqr_mode) {
363 delete $form->{l_soldtotal};
365 flash('warning', $::locale->text('Soldtotal does not make sense without any bsooqr options'));
367 if ($form->{l_name} && !$bsooqr_mode) {
368 delete $form->{l_name};
370 flash('warning', $::locale->text('Name does not make sense without any bsooqr options'));
372 IC->all_parts(\%myconfig, \%$form);
375 partnumber type_and_classific description notes partsgroup bin onhand rop soldtotal unit listprice
376 linetotallistprice sellprice linetotalsellprice lastcost linetotallastcost
377 priceupdate weight image drawing microfiche invnumber ordnumber quonumber
378 transdate name serialnumber deliverydate ean projectnumber projectdescription
382 my $pricegroups = SL::DB::Manager::Pricegroup->get_all_sorted;
383 my @pricegroup_columns;
384 my %column_defs_pricegroups;
385 if ($form->{l_pricegroups}) {
386 @pricegroup_columns = map { "pricegroup_" . $_->id } @{ $pricegroups };
387 %column_defs_pricegroups = map {
388 "pricegroup_" . $_->id => {
389 text => $::locale->text('Pricegroup') . ' ' . $_->pricegroup,
394 push @columns, @pricegroup_columns;
396 my @includeable_custom_variables = grep { $_->{includeable} } @{ $cvar_configs };
397 my @searchable_custom_variables = grep { $_->{searchable} } @{ $cvar_configs };
398 my %column_defs_cvars = map { +"cvar_$_->{name}" => { 'text' => $_->{description} } } @includeable_custom_variables;
400 push @columns, map { "cvar_$_->{name}" } @includeable_custom_variables;
402 %column_defs = (%column_defs, %column_defs_cvars, %column_defs_pricegroups);
403 map { $column_defs{$_}->{visible} ||= $form->{"l_$_"} ? 1 : 0 } @columns;
404 map { $column_defs{$_}->{align} = 'right' } qw(onhand sellprice listprice lastcost linetotalsellprice linetotallastcost linetotallistprice rop weight soldtotal shop), @pricegroup_columns;
406 my @hidden_variables = (
407 qw(l_subtotal l_linetotal searchitems itemstatus bom l_pricegroups insertdatefrom insertdateto),
408 qw(l_type_and_classific classification_id),
411 map({ "cvar_$_->{name}" } @searchable_custom_variables),
412 map({'cvar_'. $_->{name} .'_qtyop'} grep({$_->{type} eq 'number'} @searchable_custom_variables)),
413 map({ "l_$_" } @columns),
416 my $callback = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
418 my @sort_full = qw(partnumber description onhand soldtotal deliverydate insertdate shop);
419 my @sort_no_revers = qw(partsgroup bin priceupdate invnumber ordnumber quonumber name image drawing serialnumber);
421 foreach my $col (@sort_full) {
422 $column_defs{$col}->{link} = join '&', $callback, "sort=$col", map { "$_=" . E($form->{$_}) } qw(revers lastsort);
424 map { $column_defs{$_}->{link} = "${callback}&sort=$_" } @sort_no_revers;
426 # add order to callback
427 $form->{callback} = join '&', ($callback, map { "${_}=" . E($form->{$_}) } qw(sort revers));
429 my $report = SL::ReportGenerator->new(\%myconfig, $form);
431 my %attachment_basenames = (
432 'part' => $locale->text('part_list'),
433 'service' => $locale->text('service_list'),
434 'assembly' => $locale->text('assembly_list'),
435 'article' => $locale->text('article_list'),
438 $report->set_options('raw_top_info_text' => $form->parse_html_template('ic/generate_report_top', { options => \@options }),
439 'raw_bottom_info_text' => $form->parse_html_template('ic/generate_report_bottom' ,
440 { PART_CLASSIFICATIONS => SL::DB::Manager::PartClassification->get_all_sorted }),
441 'output_format' => 'HTML',
442 'title' => $form->{title},
443 'attachment_basename' => 'article_list' . strftime('_%Y%m%d', localtime time),
445 $report->set_options_from_form();
446 $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
448 $report->set_columns(%column_defs);
449 $report->set_column_order(@columns);
451 $report->set_export_options('generate_report', @hidden_variables, qw(sort revers));
453 $report->set_sort_indicator($form->{sort}, $form->{revers} ? 0 : 1);
455 CVar->add_custom_variables_to_report('module' => 'IC',
456 'trans_id_field' => 'id',
457 'configs' => $cvar_configs,
458 'column_defs' => \%column_defs,
459 'data' => $form->{parts});
461 CVar->add_custom_variables_to_report('module' => 'IC',
462 'sub_module' => sub { $_[0]->{ioi} },
463 'trans_id_field' => 'ioi_id',
464 'configs' => $cvar_configs,
465 'column_defs' => \%column_defs,
466 'data' => $form->{parts});
468 my @subtotal_columns = qw(sellprice listprice lastcost);
469 my %subtotals = map { $_ => 0 } ('onhand', @subtotal_columns);
470 my %totals = map { $_ => 0 } @subtotal_columns;
472 my $same_item = @{ $form->{parts} } ? $form->{parts}[0]{ $form->{sort} } : undef;
474 my $defaults = AM->get_defaults();
477 foreach my $ref (@{ $form->{parts} }) {
479 # fresh row, for inserting later
480 my $row = { map { $_ => { 'data' => $ref->{$_} } } @columns };
482 $ref->{exchangerate} ||= 1;
483 $ref->{price_factor} ||= 1;
484 $ref->{sellprice} *= $ref->{exchangerate} / $ref->{price_factor};
485 $ref->{listprice} *= $ref->{exchangerate} / $ref->{price_factor};
486 $ref->{lastcost} *= $ref->{exchangerate} / $ref->{price_factor};
488 # use this for assemblies
489 my $soldtotal = $bsooqr_mode ? $ref->{soldtotal} : $ref->{onhand};
491 if ($ref->{assemblyitem}) {
492 $row->{partnumber}{align} = 'right';
493 $row->{soldtotal}{data} = 0;
494 $soldtotal = 0 if ($form->{sold});
497 my $edit_link = build_std_url('script=controller.pl', 'action=Part/edit', 'part.id=' . E($ref->{id}), 'callback');
498 $row->{partnumber}->{link} = $edit_link;
499 $row->{description}->{link} = $edit_link;
501 foreach (qw(sellprice listprice lastcost)) {
502 $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{$_}, 2);
503 $row->{"linetotal$_"}{data} = $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{$_}, 2);
505 foreach ( @pricegroup_columns ) {
506 $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{"$_"}, 2);
510 map { $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{$_}); } qw(onhand rop weight soldtotal);
512 $row->{weight}->{data} .= ' ' . $defaults->{weightunit};
514 # 'yes' and 'no' for boolean value shop
515 if ($form->{l_shop}) {
516 $row->{shop}{data} = $row->{shop}{data}? $::locale->text('yes') : $::locale->text('no');
519 if (!$ref->{assemblyitem}) {
520 foreach my $col (@subtotal_columns) {
521 $totals{$col} += $soldtotal * $ref->{$col};
522 $subtotals{$col} += $soldtotal * $ref->{$col};
525 $subtotals{soldtotal} += $soldtotal;
529 if ($ref->{module} eq 'oe') {
530 # für oe gibt es vier fälle, jeweils nach kunde oder lieferant unterschiedlich:
532 # | ist bestellt | Von Kunden bestellt | -> edit_oe_ord_link
533 # | Anfrage | Angebot | -> edit_oe_quo_link
535 my $edit_oe_ord_link = build_std_url("script=oe.pl", 'action=edit', 'type=' . E($ref->{cv} eq 'vendor' ? 'purchase_order' : 'sales_order'), 'id=' . E($ref->{trans_id}), 'callback');
536 my $edit_oe_quo_link = build_std_url("script=oe.pl", 'action=edit', 'type=' . E($ref->{cv} eq 'vendor' ? 'request_quotation' : 'sales_quotation'), 'id=' . E($ref->{trans_id}), 'callback');
538 $row->{ordnumber}{link} = $edit_oe_ord_link;
539 $row->{quonumber}{link} = $edit_oe_quo_link if (!$ref->{ordnumber});
542 $row->{invnumber}{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'type=invoice', 'id=' . E($ref->{trans_id}), 'callback') if ($ref->{invnumber});
545 # set properties of images
546 if ($ref->{image} && (lc $report->{options}->{output_format} eq 'html')) {
547 $row->{image}{data} = '';
548 $row->{image}{raw_data} = '<a href="' . H($ref->{image}) . '"><img src="' . H($ref->{image}) . '" height="32" border="0"></a>';
550 map { $row->{$_}{link} = $ref->{$_} } qw(drawing microfiche);
552 $row->{notes}{data} = SL::HTML::Util->strip($ref->{notes});
553 $row->{type_and_classific}{data} = $::request->presenter->type_abbreviation($ref->{part_type}).
554 $::request->presenter->classification_abbreviation($ref->{classification_id});
556 $report->add_data($row);
558 my $next_ref = $form->{parts}[$idx + 1];
560 # insert subtotal rows
561 if (($form->{l_subtotal} eq 'Y') &&
563 (!$next_ref->{assemblyitem} && ($same_item ne $next_ref->{ $form->{sort} })))) {
564 my $row = { map { $_ => { 'class' => 'listsubtotal', } } @columns };
566 if ( !$form->{l_assembly} || !$form->{bom}) {
567 $row->{soldtotal}->{data} = $form->format_amount(\%myconfig, $subtotals{soldtotal});
570 map { $row->{"linetotal$_"}->{data} = $form->format_amount(\%myconfig, $subtotals{$_}, 2) } @subtotal_columns;
571 map { $subtotals{$_} = 0 } ('soldtotal', @subtotal_columns);
573 $report->add_data($row);
575 $same_item = $next_ref->{ $form->{sort} };
581 if ($form->{"l_linetotal"} && !$form->{report_generator_csv_options_for_import}) {
582 my $row = { map { $_ => { 'class' => 'listtotal', } } @columns };
584 map { $row->{"linetotal$_"}->{data} = $form->format_amount(\%myconfig, $totals{$_}, 2) } @subtotal_columns;
586 $report->add_separator();
587 $report->add_data($row);
590 setup_ic_generate_report_action_bar();
591 $report->generate_with_headers();
593 $lxdebug->leave_sub();
594 } #end generate_report
596 sub setup_ic_search_action_bar {
599 for my $bar ($::request->layout->get('actionbar')) {
603 submit => [ '#form', { action => 'generate_report' } ],
604 accesskey => 'enter',
609 submit => [ '#form', { action => 'top100' } ],
615 sub setup_ic_generate_report_action_bar {
618 for my $bar ($::request->layout->get('actionbar')) {
626 submit => [ '#new_form', { action => 'Part/add_part' } ],
627 accesskey => 'enter',
631 submit => [ '#new_form', { action => 'Part/add_service' } ],
635 submit => [ '#new_form', { action => 'Part/add_assembly' } ],
638 t8('Add Assortment'),
639 submit => [ '#new_form', { action => 'Part/add_assortment' } ],
641 ], # end of combobox "Add part"