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., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #======================================================================
30 # Inventory Control module
32 #======================================================================
34 use POSIX qw(strftime);
35 use List::Util qw(max);
36 use List::MoreUtils qw(any);
41 use SL::ReportGenerator;
49 our ($form, $locale, %myconfig, $lxdebug, $auth);
51 require "bin/mozilla/io.pl";
52 require "bin/mozilla/invoice_io.pl";
53 require "bin/mozilla/common.pl";
54 require "bin/mozilla/reportgenerator.pl";
59 # type=submit $locale->text('Add Part')
60 # type=submit $locale->text('Add Service')
61 # type=submit $locale->text('Add Assembly')
62 # type=submit $locale->text('Edit Part')
63 # type=submit $locale->text('Edit Service')
64 # type=submit $locale->text('Edit Assembly')
65 # $locale->text('Parts')
66 # $locale->text('Services')
67 # $locale->text('Inventory quantity must be zero before you can set this part obsolete!')
68 # $locale->text('Inventory quantity must be zero before you can set this assembly obsolete!')
69 # $locale->text('Part Number missing!')
70 # $locale->text('Service Number missing!')
71 # $locale->text('Assembly Number missing!')
72 # $locale->text('ea');
77 $lxdebug->enter_sub();
79 $auth->assert('part_service_assembly_edit');
81 $form->{title} = $locale->text('Add ' . ucfirst $form->{item});
82 $form->{callback} = "$form->{script}?action=add&item=$form->{item}" unless $form->{callback};
83 $form->{unit_changeable} = 1;
85 IC->get_pricegroups(\%myconfig, \%$form);
89 $lxdebug->leave_sub();
93 $lxdebug->enter_sub();
95 $auth->assert('part_service_assembly_edit');
97 $form->{revers} = 0; # switch for backward sorting
98 $form->{lastsort} = ""; # memory for which table was sort at last time
99 $form->{ndxs_counter} = 0; # counter for added entries to top100
101 my %is_xyz = map { +"is_$_" => ($form->{searchitems} eq $_) } qw(part service assembly);
103 $form->{title} = (ucfirst $form->{searchitems}) . "s";
104 $form->{title} = $locale->text($form->{title});
105 $form->{title} = $locale->text('Assemblies') if ($is_xyz{is_assembly});
107 $form->{jsscript} = 1;
109 $form->{CUSTOM_VARIABLES} = CVar->get_configs('module' => 'IC');
110 ($form->{CUSTOM_VARIABLES_FILTER_CODE},
111 $form->{CUSTOM_VARIABLES_INCLUSION_CODE}) = CVar->render_search_options('variables' => $form->{CUSTOM_VARIABLES},
112 'include_prefix' => 'l_',
113 'include_value' => 'Y');
117 print $form->parse_html_template('ic/search', { %is_xyz,
118 dateformat => $myconfig{dateformat}, });
120 $lxdebug->leave_sub();
123 sub search_update_prices {
124 $lxdebug->enter_sub();
126 $auth->assert('part_service_assembly_edit');
128 my $pricegroups = IC->get_pricegroups(\%myconfig, \%$form);
132 print $form->parse_html_template('ic/search_update_prices', { PRICE_ROWS => $pricegroups });
134 $lxdebug->leave_sub();
137 sub confirm_price_update {
138 $lxdebug->enter_sub();
140 $auth->assert('part_service_assembly_edit');
143 my $value_found = undef;
145 foreach my $idx (qw(sellprice listprice), (1..$form->{price_rows})) {
146 my $name = $idx =~ m/\d/ ? $form->{"pricegroup_${idx}"} : $idx eq 'sellprice' ? $locale->text('Sell Price') : $locale->text('List Price');
147 my $type = $idx =~ m/\d/ ? $form->{"pricegroup_type_${idx}"} : $form->{"${idx}_type"};
148 my $value_idx = $idx =~ m/\d/ ? "price_${idx}" : $idx;
149 my $value = $form->parse_amount(\%myconfig, $form->{$value_idx});
151 if ((0 > $value) && ($type eq 'percent')) {
152 push @errors, $locale->text('You cannot adjust the price for pricegroup "#1" by a negative percentage.', $name);
154 } elsif (!$value && ($form->{$value_idx} ne '')) {
155 push @errors, $locale->text('No valid number entered for pricegroup "#1".', $name);
157 } elsif (0 < $value) {
162 push @errors, $locale->text('No prices will be updated because no prices have been entered.') if (!$value_found);
164 my $num_matches = IC->get_num_matches_for_priceupdate();
169 $form->show_generic_error(join('<br>', @errors), 'back_button' => 1);
172 $form->{nextsub} = "update_prices";
174 map { delete $form->{$_} } qw(action header);
176 print $form->parse_html_template('ic/confirm_price_update', { HIDDENS => [ map { name => $_, value => $form->{$_} }, keys %$form ],
177 num_matches => $num_matches });
179 $lxdebug->leave_sub();
183 $lxdebug->enter_sub();
185 $auth->assert('part_service_assembly_edit');
187 my $num_updated = IC->update_prices(\%myconfig, \%$form);
189 if (-1 != $num_updated) {
190 $form->redirect($locale->text('#1 prices were updated.', $num_updated));
192 $form->error($locale->text('Could not update prices!'));
195 $lxdebug->leave_sub();
199 # $lxdebug->enter_sub();
201 # $auth->assert('part_service_assembly_edit');
203 # our ($j, $lastndx);
206 # $form->{title} = $locale->text('Top 100 hinzufuegen');
210 # push @custom_hiddens, qw(searchitems title bom titel revers lastsort sort ndxs_counter extras);
211 # push @custom_hiddens, qw(itemstatus l_linetotal l_partnumber l_description l_onhand l_unit l_sellprice l_linetotalsellprice);
213 # +{ name => 'row', value => $j },
214 # +{ name => 'nextsub', value => 'item_selected' },
215 # +{ name => 'test', value => 'item_selected' },
216 # +{ name => 'lastndx', value => $lastndx },
217 # map(+{ name => $_, value => $form->{$_} }, @custom_hiddens),
220 # my ($partnumber, $description, $unit, $sellprice, $soldtotal);
221 # # if choice set data
222 ## if ($form->{ndx}) {
223 ## for my $i (0 .. $form->{ndxs_counter}) {
225 ## # insert data into top100
226 ## push @{ $form->{parts} },
228 ## partnumber => $form->{"totop100_partnumber_$j"},
229 ## description => $form->{"totop100_description_$j"},
230 ## unit => $form->{"totop100_unit_$j"},
231 ## sellprice => $form->{"totop100_sellprice_$j"},
232 ## soldtotal => $form->{"totop100_soldtotal_$j"},
239 # # set data for next page
240 # for my $i (1 .. $form->{ndxs_counter}) {
241 # $partnumber = $form->{"totop100_partnumber_$i"};
242 # $description = $form->{"totop100_description_$i"};
243 # $unit = $form->{"totop100_unit_$i"};
244 # $sellprice = $form->{"totop100_sellprice_$i"};
245 # $soldtotal = $form->{"totop100_soldtotal_$i"};
248 # totop100_partnumber => $form->{"totop100_partnumber_$i"},
249 # totop100_description => $form->{"totop100_description_$i"},
250 # totop100_unit => $form->{"totop100_unit_$i"},
251 # totop100_sellprice => $form->{"totop100_sellprice_$i"},
252 # totop100_soldtotal => $form->{"totop100_soldtotal_$i"},
256 ##<input type=hidden name=totop100_partnumber_$i value=$form->{"totop100_partnumber_$i"}>
257 ##<input type=hidden name=totop100_description_$i value=$form->{"totop100_description_$i"}>
258 ##<input type=hidden name=totop100_unit_$i value=$form->{"totop100_unit_$i"}>
259 ##<input type=hidden name=totop100_sellprice_$i value=$form->{"totop100_sellprice_$i"}>
260 ##<input type=hidden name=totop100_soldtotal_$i value=$form->{"totop100_soldtotal_$i"}>
264 # print $form->parse_html_template('ic/choice', +{ HIDDENS => \@HIDDENS, PARTS => \@PARTS });
266 # $lxdebug->leave_sub();
270 # $lxdebug->enter_sub();
272 # $auth->assert('part_service_assembly_edit');
275 # our ($partnumber, $description, $unit, $sellprice, $soldtotal);
277 # my @sortorders = ("", "partnumber", "description", "all");
278 # my $sortorder = $sortorders[($form->{description} ? 2 : 0) + ($form->{partnumber} ? 1 : 0)];
279 # IC->get_parts(\%myconfig, \%$form, $sortorder);
281 # $form->{title} = $locale->text('Top 100 hinzufuegen');
287 # <form method=post action=ic.pl>
290 # <th class=listtop colspan=6>| . $locale->text('choice part') . qq|</th>
292 # <tr height="5"></tr>
293 # <tr class=listheading>
295 # <th class=listheading>| . $locale->text('Part Number') . qq|</th>
296 # <th class=listheading>| . $locale->text('Part Description') . qq|</th>
297 # <th class=listheading>| . $locale->text('Unit of measure') . qq|</th>
298 # <th class=listheading>| . $locale->text('Sell Price') . qq|</th>
299 # <th class=listheading>| . $locale->text('soldtotal') . qq|</th>
303 # my $i = $form->{rows};
305 # for ($j = 1; $j <= $i; $j++) {
308 # <tr class=listrow| . ($j % 2) . qq|>|;
311 # <td><input name=ndx class=radio type=radio value=$j checked></td>|;
314 # <td><input name=ndx class=radio type=radio value=$j></td>|;
317 # <td><input name="new_partnumber_$j" type=hidden value="$form->{"partnumber_$j"}">$form->{"partnumber_$j"}</td>
318 # <td><input name="new_description_$j" type=hidden value="$form->{"description_$j"}">$form->{"description_$j"}</td>
319 # <td><input name="new_unit_$j" type=hidden value="$form->{"unit_$j"}">$form->{"unit_$j"}</td>
320 # <td><input name="new_sellprice_$j" type=hidden value="$form->{"sellprice_$j"}">$form->{"sellprice_$j"}</td>
321 # <td><input name="new_soldtotal_$j" type=hidden value="$form->{"soldtotal_$j"}">$form->{"soldtotal_$j"}</td>
324 # <input name="new_id_$j" type=hidden value="$form->{"id_$j"}">|;
334 #<input type=hidden name=itemstatus value="$form->{itemstatus}">
335 #<input type=hidden name=l_linetotal value="$form->{l_linetotal}">
336 #<input type=hidden name=l_partnumber value="$form->{l_partnumber}">
337 #<input type=hidden name=l_description value="$form->{l_description}">
338 #<input type=hidden name=l_onhand value="$form->{l_onhand}">
339 #<input type=hidden name=l_unit value="$form->{l_unit}">
340 #<input type=hidden name=l_sellprice value="$form->{l_sellprice}">
341 #<input type=hidden name=l_linetotalsellprice value="$form->{l_linetotalsellprice}">
342 #<input type=hidden name=sort value="$form->{sort}">
343 #<input type=hidden name=revers value="$form->{revers}">
344 #<input type=hidden name=lastsort value="$form->{lastsort}">
346 #<input type=hidden name=bom value="$form->{bom}">
347 #<input type=hidden name=titel value="$form->{titel}">
348 #<input type=hidden name=searchitems value="$form->{searchitems}">
350 #<input type=hidden name=row value=$j>
352 #<input type=hidden name=nextsub value=item_selected>
354 #<input name=lastndx type=hidden value=$lastndx>
356 #<input name=ndxs_counter type=hidden value=$form->{ndxs_counter}>|;
360 # if (($form->{ndxs_counter}) > 0) {
361 # for ($i = 1; ($i < $form->{ndxs_counter} + 1); $i++) {
363 # $partnumber = $form->{"totop100_partnumber_$i"};
364 # $description = $form->{"totop100_description_$i"};
365 # $unit = $form->{"totop100_unit_$i"};
366 # $sellprice = $form->{"totop100_sellprice_$i"};
367 # $soldtotal = $form->{"totop100_soldtotal_$i"};
370 #<input type=hidden name=totop100_partnumber_$i value=$form->{"totop100_partnumber_$i"}>
371 #<input type=hidden name=totop100_description_$i value=$form->{"totop100_description_$i"}>
372 #<input type=hidden name=totop100_unit_$i value=$form->{"totop100_unit_$i"}>
373 #<input type=hidden name=totop100_sellprice_$i value=$form->{"totop100_sellprice_$i"}>
374 #<input type=hidden name=totop100_soldtotal_$i value=$form->{"totop100_soldtotal_$i"}>
382 #<input class=submit type=submit name=action value="|
383 # . $locale->text('TOP100') . qq|">
389 # $lxdebug->leave_sub();
393 $lxdebug->enter_sub();
395 $auth->assert('part_service_assembly_edit');
398 $form->{ndxs_counter}++;
400 if ($form->{ndxs_counter} > 0) {
402 my $index = $form->{ndx};
404 $form->{"totop100_partnumber_$form->{ndxs_counter}"} = $form->{"new_partnumber_$index"};
405 $form->{"totop100_description_$form->{ndxs_counter}"} = $form->{"new_description_$index"};
406 $form->{"totop100_unit_$form->{ndxs_counter}"} = $form->{"new_unit_$index"};
407 $form->{"totop100_sellprice_$form->{ndxs_counter}"} = $form->{"new_sellprice_$index"};
408 $form->{"totop100_soldtotal_$form->{ndxs_counter}"} = $form->{"new_soldtotal_$index"};
412 $lxdebug->leave_sub();
416 $lxdebug->enter_sub();
418 $auth->assert('part_service_assembly_edit');
420 my ($revers, $lastsort, $callback, $option, $description, $sameitem,
421 $partnumber, $unit, $sellprice, $soldtotal, $totop100, $onhand, $align);
422 my (@column_index, %column_header, %column_data);
423 my ($totalsellprice, $totallastcost, $totallistprice, $subtotalonhand, $subtotalsellprice, $subtotallastcost, $subtotallistprice);
425 $form->{top100} = "top100";
426 $form->{l_soldtotal} = "Y";
427 $form->{soldtotal} = "soldtotal";
428 $form->{sort} = "soldtotal";
429 $form->{l_qty} = "N";
430 $form->{l_linetotal} = "";
432 $form->{number} = "position";
433 $form->{l_number} = "Y";
437 $form->{title} = $locale->text('Top 100');
439 $revers = $form->{revers};
440 $lastsort = $form->{lastsort};
442 if (($form->{lastsort} eq "") && ($form->{sort} eq undef)) {
444 $form->{lastsort} = "partnumber";
445 $form->{sort} = "partnumber";
449 "$form->{script}?action=top100&searchitems=$form->{searchitems}&itemstatus=$form->{itemstatus}&bom=$form->{bom}&l_linetotal=$form->{l_linetotal}&title="
450 . $form->escape($form->{title}, 1);
452 # if we have a serialnumber limit search
453 if ($form->{serialnumber} || $form->{l_serialnumber}) {
454 $form->{l_serialnumber} = "Y";
455 unless ( $form->{bought}
458 || $form->{quoted}) {
459 $form->{bought} = $form->{sold} = 1;
462 IC->all_parts(\%myconfig, \%$form);
464 if ($form->{itemstatus} eq 'active') {
465 $option .= $locale->text('Active') . " : ";
467 if ($form->{itemstatus} eq 'obsolete') {
468 $option .= $locale->text('Obsolete') . " : ";
470 if ($form->{itemstatus} eq 'orphaned') {
471 $option .= $locale->text('Orphaned') . " : ";
473 if ($form->{itemstatus} eq 'onhand') {
474 $option .= $locale->text('On Hand') . " : ";
475 $form->{l_onhand} = "Y";
477 if ($form->{itemstatus} eq 'short') {
478 $option .= $locale->text('Short') . " : ";
479 $form->{l_onhand} = "Y";
481 if ($form->{onorder}) {
482 $form->{l_ordnumber} = "Y";
483 $callback .= "&onorder=$form->{onorder}";
484 $option .= $locale->text('On Order') . " : ";
486 if ($form->{ordered}) {
487 $form->{l_ordnumber} = "Y";
488 $callback .= "&ordered=$form->{ordered}";
489 $option .= $locale->text('Ordered') . " : ";
492 $form->{l_quonumber} = "Y";
493 $callback .= "&rfq=$form->{rfq}";
494 $option .= $locale->text('RFQ') . " : ";
496 if ($form->{quoted}) {
497 $form->{l_quonumber} = "Y";
498 $callback .= ""ed=$form->{quoted}";
499 $option .= $locale->text('Quoted') . " : ";
501 if ($form->{bought}) {
502 $form->{l_invnumber} = "Y";
503 $callback .= "&bought=$form->{bought}";
504 $option .= $locale->text('Bought') . " : ";
507 $form->{l_invnumber} = "Y";
508 $callback .= "&sold=$form->{sold}";
509 $option .= $locale->text('Sold') . " : ";
516 || $form->{quoted}) {
518 $form->{l_lastcost} = "";
519 $form->{l_name} = "Y";
520 if ($form->{transdatefrom}) {
521 $callback .= "&transdatefrom=$form->{transdatefrom}";
523 . $locale->text('From')
525 . $locale->date(\%myconfig, $form->{transdatefrom}, 1);
527 if ($form->{transdateto}) {
528 $callback .= "&transdateto=$form->{transdateto}";
530 . $locale->text('To')
532 . $locale->date(\%myconfig, $form->{transdateto}, 1);
538 if ($form->{partnumber}) {
539 $callback .= "&partnumber=$form->{partnumber}";
540 $option .= $locale->text('Part Number') . qq| : $form->{partnumber}<br>|;
543 $callback .= "&partnumber=$form->{ean}";
544 $option .= $locale->text('EAN') . qq| : $form->{ean}<br>|;
546 if ($form->{partsgroup}) {
547 $callback .= "&partsgroup=$form->{partsgroup}";
548 $option .= $locale->text('Group') . qq| : $form->{partsgroup}<br>|;
550 if ($form->{serialnumber}) {
551 $callback .= "&serialnumber=$form->{serialnumber}";
552 $option .= $locale->text('Serial Number') . qq| : $form->{serialnumber}<br>|;
554 if ($form->{description}) {
555 $callback .= "&description=$form->{description}";
556 $description = $form->{description};
557 $description =~ s/\n/<br>/g;
558 $option .= $locale->text('Part Description') . qq| : $form->{description}<br>|;
561 $callback .= "&make=$form->{make}";
562 $option .= $locale->text('Make') . qq| : $form->{make}<br>|;
564 if ($form->{model}) {
565 $callback .= "&model=$form->{model}";
566 $option .= $locale->text('Model') . qq| : $form->{model}<br>|;
568 if ($form->{drawing}) {
569 $callback .= "&drawing=$form->{drawing}";
570 $option .= $locale->text('Drawing') . qq| : $form->{drawing}<br>|;
572 if ($form->{microfiche}) {
573 $callback .= "µfiche=$form->{microfiche}";
574 $option .= $locale->text('Microfiche') . qq| : $form->{microfiche}<br>|;
576 if ($form->{l_soldtotal}) {
577 $callback .= "&soldtotal=$form->{soldtotal}";
578 $option .= $locale->text('soldtotal') . qq| : $form->{soldtotal}<br>|;
581 my @columns = $form->sort_columns(
582 qw(number partnumber ean description partsgroup bin onhand rop unit listprice linetotallistprice sellprice linetotalsellprice lastcost linetotallastcost priceupdate weight image drawing microfiche invnumber ordnumber quonumber name serialnumber soldtotal)
585 if ($form->{l_linetotal}) {
586 $form->{l_onhand} = "Y";
587 $form->{l_linetotalsellprice} = "Y" if $form->{l_sellprice};
588 if ($form->{l_lastcost}) {
589 $form->{l_linetotallastcost} = "Y";
590 if (($form->{searchitems} eq 'assembly') && !$form->{bom}) {
591 $form->{l_linetotallastcost} = "";
594 $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
597 if ($form->{searchitems} eq 'service') {
599 # remove bin, weight and rop from list
600 map { $form->{"l_$_"} = "" } qw(bin weight rop);
602 $form->{l_onhand} = "";
604 # qty is irrelevant unless bought or sold
610 || $form->{quoted}) {
611 $form->{l_onhand} = "Y";
613 $form->{l_linetotalsellprice} = "";
614 $form->{l_linetotallastcost} = "";
618 foreach my $item (@columns) {
619 if ($form->{"l_$item"} eq "Y") {
620 push @column_index, $item;
622 # add column to callback
623 $callback .= "&l_$item=Y";
627 if ($form->{l_subtotal} eq 'Y') {
628 $callback .= "&l_subtotal=Y";
631 $column_header{number} =
632 qq|<th class=listheading nowrap>| . $locale->text('number') . qq|</th>|;
633 $column_header{partnumber} =
634 qq|<th nowrap><a class=listheading href=$callback&sort=partnumber&revers=$form->{revers}&lastsort=$form->{lastsort}>|
635 . $locale->text('Part Number')
637 $column_header{description} =
638 qq|<th nowrap><a class=listheading href=$callback&sort=description&revers=$form->{revers}&lastsort=$form->{lastsort}>|
639 . $locale->text('Part Description')
641 $column_header{partsgroup} =
642 qq|<th nowrap><a class=listheading href=$callback&sort=partsgroup>|
643 . $locale->text('Group')
645 $column_header{bin} =
646 qq|<th><a class=listheading href=$callback&sort=bin>|
647 . $locale->text('Bin')
649 $column_header{priceupdate} =
650 qq|<th nowrap><a class=listheading href=$callback&sort=priceupdate>|
651 . $locale->text('Updated')
653 $column_header{onhand} =
654 qq|<th nowrap><a class=listheading href=$callback&sort=onhand&revers=$form->{revers}&lastsort=$form->{lastsort}>|
655 . $locale->text('Qty')
657 $column_header{unit} =
658 qq|<th class=listheading nowrap>| . $locale->text('Unit') . qq|</th>|;
659 $column_header{listprice} =
660 qq|<th class=listheading nowrap>|
661 . $locale->text('List Price')
663 $column_header{lastcost} =
664 qq|<th class=listheading nowrap>| . $locale->text('Last Cost') . qq|</th>|;
665 $column_header{rop} =
666 qq|<th class=listheading nowrap>| . $locale->text('ROP') . qq|</th>|;
667 $column_header{weight} =
668 qq|<th class=listheading nowrap>| . $locale->text('Weight') . qq|</th>|;
670 $column_header{invnumber} =
671 qq|<th nowrap><a class=listheading href=$callback&sort=invnumber>|
672 . $locale->text('Invoice Number')
674 $column_header{ordnumber} =
675 qq|<th nowrap><a class=listheading href=$callback&sort=ordnumber>|
676 . $locale->text('Order Number')
678 $column_header{quonumber} =
679 qq|<th nowrap><a class=listheading href=$callback&sort=quonumber>|
680 . $locale->text('Quotation')
683 $column_header{name} =
684 qq|<th nowrap><a class=listheading href=$callback&sort=name>|
685 . $locale->text('Name')
688 $column_header{sellprice} =
689 qq|<th class=listheading nowrap>|
690 . $locale->text('Sell Price')
692 $column_header{linetotalsellprice} =
693 qq|<th class=listheading nowrap>| . $locale->text('Extended') . qq|</th>|;
694 $column_header{linetotallastcost} =
695 qq|<th class=listheading nowrap>| . $locale->text('Extended') . qq|</th>|;
696 $column_header{linetotallistprice} =
697 qq|<th class=listheading nowrap>| . $locale->text('Extended') . qq|</th>|;
699 $column_header{image} =
700 qq|<th class=listheading nowrap>| . $locale->text('Image') . qq|</a></th>|;
701 $column_header{drawing} =
702 qq|<th nowrap><a class=listheading href=$callback&sort=drawing>|
703 . $locale->text('Drawing')
705 $column_header{microfiche} =
706 qq|<th nowrap><a class=listheading href=$callback&sort=microfiche>|
707 . $locale->text('Microfiche')
710 $column_header{serialnumber} =
711 qq|<th nowrap><a class=listheading href=$callback&sort=serialnumber>|
712 . $locale->text('Serial Number')
714 $column_header{soldtotal} =
715 qq|<th nowrap><a class=listheading href=$callback&sort=soldtotal&revers=$form->{revers}&lastsort=$form->{lastsort}>|
716 . $locale->text('soldtotal')
720 my $colspan = $#column_index + 1;
727 <th class=listtop colspan=$colspan>$form->{title}</th>
731 <tr><td colspan=$colspan>$option</td></tr>
733 <tr class=listheading>
736 map { print "\n$column_header{$_}" } @column_index;
742 # add order to callback
743 $form->{callback} = $callback .= "&sort=$form->{sort}";
745 # escape callback for href
746 $callback = $form->escape($callback);
748 if (@{ $form->{parts} }) {
749 $sameitem = $form->{parts}->[0]->{ $form->{sort} };
752 # insert numbers for top100
754 foreach my $ref (@{ $form->{parts} }) {
759 # if avaible -> insert choice here
760 if (($form->{ndxs_counter}) > 0) {
761 for (my $i = 1; ($i < $form->{ndxs_counter} + 1); $i++) {
762 $partnumber = $form->{"totop100_partnumber_$i"};
763 $description = $form->{"totop100_description_$i"};
764 $unit = $form->{"totop100_unit_$i"};
765 $sellprice = $form->{"totop100_sellprice_$i"};
766 $soldtotal = $form->{"totop100_soldtotal_$i"};
769 <input type=hidden name=totop100_partnumber_$i value=$form->{"totop100_partnumber_$i"}>
770 <input type=hidden name=totop100_description_$i value=$form->{"totop100_description_$i"}>
771 <input type=hidden name=totop100_unit_$i value=$form->{"totop100_unit_$i"}>
772 <input type=hidden name=totop100_sellprice_$i value=$form->{"totop100_sellprice_$i"}>
773 <input type=hidden name=totop100_soldtotal_$i value=$form->{"totop100_soldtotal_$i"}>
777 push @{ $form->{parts} },
779 partnumber => "$partnumber",
780 description => "$description",
782 sellprice => "$sellprice",
783 soldtotal => "$soldtotal" };
786 # build data for columns
788 foreach my $ref (@{ $form->{parts} }) {
790 if ($form->{l_subtotal} eq 'Y' && !$ref->{assemblyitem}) {
791 if ($sameitem ne $ref->{ $form->{sort} }) {
793 $sameitem = $ref->{ $form->{sort} };
797 $ref->{exchangerate} = 1 unless $ref->{exchangerate};
798 $ref->{sellprice} *= $ref->{exchangerate};
799 $ref->{listprice} *= $ref->{exchangerate};
800 $ref->{lastcost} *= $ref->{exchangerate};
802 # use this for assemblies
803 $onhand = $ref->{onhand};
806 if ($ref->{assemblyitem}) {
808 $onhand = 0 if ($form->{sold});
811 $ref->{description} =~ s/\n/<br>/g;
813 $column_data{number} =
815 . $form->format_amount(\%myconfig, $ref->{number})
817 $column_data{partnumber} =
818 "<td align=$align>$ref->{partnumber} </a></td>";
819 $column_data{description} = "<td>$ref->{description} </td>";
820 $column_data{partsgroup} = "<td>$ref->{partsgroup} </td>";
822 $column_data{onhand} =
824 . $form->format_amount(\%myconfig, $ref->{onhand})
826 $column_data{sellprice} =
828 . $form->format_amount(\%myconfig, $ref->{sellprice})
830 $column_data{listprice} =
832 . $form->format_amount(\%myconfig, $ref->{listprice})
834 $column_data{lastcost} =
836 . $form->format_amount(\%myconfig, $ref->{lastcost})
839 $column_data{linetotalsellprice} = "<td align=right>"
840 . $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{sellprice}, 2)
842 $column_data{linetotallastcost} = "<td align=right>"
843 . $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{lastcost}, 2)
845 $column_data{linetotallistprice} = "<td align=right>"
846 . $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{listprice}, 2)
849 if (!$ref->{assemblyitem}) {
850 $totalsellprice += $onhand * $ref->{sellprice};
851 $totallastcost += $onhand * $ref->{lastcost};
852 $totallistprice += $onhand * $ref->{listprice};
854 $subtotalonhand += $onhand;
855 $subtotalsellprice += $onhand * $ref->{sellprice};
856 $subtotallastcost += $onhand * $ref->{lastcost};
857 $subtotallistprice += $onhand * $ref->{listprice};
862 . $form->format_amount(\%myconfig, $ref->{rop}) . "</td>";
863 $column_data{weight} =
865 . $form->format_amount(\%myconfig, $ref->{weight})
867 $column_data{unit} = "<td>$ref->{unit} </td>";
868 $column_data{bin} = "<td>$ref->{bin} </td>";
869 $column_data{priceupdate} = "<td>$ref->{priceupdate} </td>";
871 $column_data{invnumber} =
872 ($ref->{module} ne 'oe')
873 ? "<td><a href=$ref->{module}.pl?action=edit&type=invoice&id=$ref->{trans_id}&callback=$callback>$ref->{invnumber}</a></td>"
874 : "<td>$ref->{invnumber}</td>";
875 $column_data{ordnumber} =
876 ($ref->{module} eq 'oe')
877 ? "<td><a href=$ref->{module}.pl?action=edit&type=$ref->{type}&id=$ref->{trans_id}&callback=$callback>$ref->{ordnumber}</a></td>"
878 : "<td>$ref->{ordnumber}</td>";
879 $column_data{quonumber} =
880 ($ref->{module} eq 'oe' && !$ref->{ordnumber})
881 ? "<td><a href=$ref->{module}.pl?action=edit&type=$ref->{type}&id=$ref->{trans_id}&callback=$callback>$ref->{quonumber}</a></td>"
882 : "<td>$ref->{quonumber}</td>";
884 $column_data{name} = "<td>$ref->{name}</td>";
886 $column_data{image} =
888 ? "<td><a href=$ref->{image}><img src=$ref->{image} height=32 border=0></a></td>"
890 $column_data{drawing} =
892 ? "<td><a href=$ref->{drawing}>$ref->{drawing}</a></td>"
894 $column_data{microfiche} =
896 ? "<td><a href=$ref->{microfiche}>$ref->{microfiche}</a></td>"
899 $column_data{serialnumber} = "<td>$ref->{serialnumber}</td>";
901 $column_data{soldtotal} = "<td align=right>$ref->{soldtotal}</td>";
905 print "<tr class=listrow$i>";
907 map { print "\n$column_data{$_}" } @column_index;
914 if ($form->{l_subtotal} eq 'Y') {
918 if ($form->{"l_linetotal"}) {
919 map { $column_data{$_} = "<td> </td>" } @column_index;
920 $column_data{linetotalsellprice} =
921 "<th class=listtotal align=right>"
922 . $form->format_amount(\%myconfig, $totalsellprice, 2)
924 $column_data{linetotallastcost} =
925 "<th class=listtotal align=right>"
926 . $form->format_amount(\%myconfig, $totallastcost, 2)
928 $column_data{linetotallistprice} =
929 "<th class=listtotal align=right>"
930 . $form->format_amount(\%myconfig, $totallistprice, 2)
933 print "<tr class=listtotal>";
935 map { print "\n$column_data{$_}" } @column_index;
942 <tr><td colspan=$colspan><hr size=3 noshade></td></tr>
951 <form method=post action=$form->{script}>
953 <input type=hidden name=itemstatus value="$form->{itemstatus}">
954 <input type=hidden name=l_linetotal value="$form->{l_linetotal}">
955 <input type=hidden name=l_partnumber value="$form->{l_partnumber}">
956 <input type=hidden name=l_description value="$form->{l_description}">
957 <input type=hidden name=l_onhand value="$form->{l_onhand}">
958 <input type=hidden name=l_unit value="$form->{l_unit}">
959 <input type=hidden name=l_sellprice value="$form->{l_sellprice}">
960 <input type=hidden name=l_linetotalsellprice value="$form->{l_linetotalsellprice}">
961 <input type=hidden name=sort value="$form->{sort}">
962 <input type=hidden name=revers value="$form->{revers}">
963 <input type=hidden name=lastsort value="$form->{lastsort}">
964 <input type=hidden name=parts value="$form->{parts}">
966 <input type=hidden name=bom value="$form->{bom}">
967 <input type=hidden name=titel value="$form->{titel}">
968 <input type=hidden name=searchitems value="$form->{searchitems}">|;
973 <!-- <input type=hidden name=ndxs_counter value="$form->{ndxs_counter}">-->
975 <input class=submit type=submit name=action value="|
976 . $locale->text('choice') . qq|">
984 $lxdebug->leave_sub();
989 # Warning, deep magic ahead.
990 # This function parses the requested details, sanity checks them, and converts them into a format thats usable for IC->all_parts
992 # flags coming from the form:
994 # searchitems=part revers=0 lastsort=''
997 # partnumber ean description partsgroup serialnumber make model drawing microfiche
998 # transdatefrom transdateto
1001 # itemstatus = active | onhand | short | obsolete | orphaned
1002 # action = continue | top100
1005 # bought sold onorder ordered rfq quoted
1006 # l_partnumber l_description l_serialnumber l_unit l_listprice l_sellprice l_lastcost
1007 # l_linetotal l_priceupdate l_bin l_rop l_weight l_image l_drawing l_microfiche
1008 # l_partsgroup l_subtotal l_soldtotal l_deliverydate
1011 # nextsub revers lastsort sort ndxs_counter
1013 sub generate_report {
1014 $lxdebug->enter_sub();
1016 $auth->assert('part_service_assembly_edit');
1018 my ($revers, $lastsort, $description);
1020 my $cvar_configs = CVar->get_configs('module' => 'IC');
1022 $form->{title} = (ucfirst $form->{searchitems}) . "s";
1023 $form->{title} =~ s/ys$/ies/;
1024 $form->{title} = $locale->text($form->{title});
1026 $revers = $form->{revers};
1027 $lastsort = $form->{lastsort};
1029 # sorting and direction of sorting
1030 # ToDO: change this to the simpler field+direction method
1031 if (($form->{lastsort} eq "") && ($form->{sort} eq undef)) {
1032 $form->{revers} = 0;
1033 $form->{lastsort} = "partnumber";
1034 $form->{sort} = "partnumber";
1036 if ($form->{lastsort} eq $form->{sort}) {
1037 $form->{revers} = 1 - $form->{revers};
1039 $form->{revers} = 0;
1040 $form->{lastsort} = $form->{sort};
1044 # special case if we have a serialnumber limit search
1045 # serialnumbers are only given in invoices and orders,
1046 # so they can only pop up in bought, sold, rfq, and quoted stuff
1047 $form->{no_sn_joins} = 'Y' if ( !$form->{bought} && !$form->{sold}
1048 && !$form->{rfq} && !$form->{quoted}
1049 && ($form->{l_serialnumber} || $form->{serialnumber}));
1051 # special case for any checkbox of bought | sold | onorder | ordered | rfq | quoted.
1052 # if any of these are ticked the behavior changes slightly for lastcost
1053 # since all those are aggregation checks for the legder tables this is an internal switch
1054 # refered to as ledgerchecks
1055 $form->{ledgerchecks} = 'Y' if ( $form->{bought} || $form->{sold} || $form->{onorder}
1056 || $form->{ordered} || $form->{rfq} || $form->{quoted});
1058 # if something should be activated if something else is active, enter it here
1059 my %dependencies = (
1060 onhand => [ qw(l_onhand) ],
1061 short => [ qw(l_onhand) ],
1062 onorder => [ qw(l_ordnumber) ],
1063 ordered => [ qw(l_ordnumber) ],
1064 rfq => [ qw(l_quonumber) ],
1065 quoted => [ qw(l_quonumber) ],
1066 bought => [ qw(l_invnumber) ],
1067 sold => [ qw(l_invnumber) ],
1068 ledgerchecks => [ qw(l_name) ],
1069 serialnumber => [ qw(l_serialnumber) ],
1070 no_sn_joins => [ qw(bought sold) ],
1073 # these strings get displayed at the top of the results to indicate the user which switches were used
1075 active => $locale->text('Active'),
1076 obsolete => $locale->text('Obsolete'),
1077 orphaned => $locale->text('Orphaned'),
1078 onhand => $locale->text('On Hand'),
1079 short => $locale->text('Short'),
1080 onorder => $locale->text('On Order'),
1081 ordered => $locale->text('Ordered'),
1082 rfq => $locale->text('RFQ'),
1083 quoted => $locale->text('Quoted'),
1084 bought => $locale->text('Bought'),
1085 sold => $locale->text('Sold'),
1086 transdatefrom => $locale->text('From') . " " . $locale->date(\%myconfig, $form->{transdatefrom}, 1),
1087 transdateto => $locale->text('To (time)') . " " . $locale->date(\%myconfig, $form->{transdateto}, 1),
1088 partnumber => $locale->text('Part Number') . ": '$form->{partnumber}'",
1089 partsgroup => $locale->text('Group') . ": '$form->{partsgroup}'",
1090 serialnumber => $locale->text('Serial Number') . ": '$form->{serialnumber}'",
1091 description => $locale->text('Part Description') . ": '$form->{description}'",
1092 make => $locale->text('Make') . ": '$form->{make}'",
1093 model => $locale->text('Model') . ": '$form->{model}'",
1094 drawing => $locale->text('Drawing') . ": '$form->{drawing}'",
1095 microfiche => $locale->text('Microfiche') . ": '$form->{microfiche}'",
1096 l_soldtotal => $locale->text('soldtotal'),
1099 my @itemstatus_keys = qw(active obsolete orphaned onhand short);
1100 my @callback_keys = qw(onorder ordered rfq quoted bought sold partnumber partsgroup serialnumber description make model
1101 drawing microfiche l_soldtotal l_deliverydate transdatefrom transdateto ean);
1103 # calculate dependencies
1104 for (@itemstatus_keys, @callback_keys) {
1105 next if ($form->{itemstatus} ne $_ && !$form->{$_});
1106 map { $form->{$_} = 'Y' } @{ $dependencies{$_} } if $dependencies{$_};
1109 # generate callback and optionstrings
1111 for my $key (@itemstatus_keys, @callback_keys) {
1112 next if ($form->{itemstatus} ne $key && !$form->{$key});
1113 push @options, $optiontexts{$key};
1116 # special case for lastcost
1117 $form->{l_lastcost} = "" if $form->{ledgerchecks};
1119 if ($form->{description}) {
1120 $description = $form->{description};
1121 $description =~ s/\n/<br>/g;
1124 if ($form->{l_linetotal}) {
1125 $form->{l_onhand} = "Y";
1126 $form->{l_linetotalsellprice} = "Y" if $form->{l_sellprice};
1127 $form->{l_linetotallastcost} = $form->{searchitems} eq 'assembly' && !$form->{bom} ? "" : 'Y' if $form->{l_lastcost};
1128 $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
1131 if ($form->{searchitems} eq 'service') {
1133 # remove bin, weight and rop from list
1134 map { $form->{"l_$_"} = "" } qw(bin weight rop);
1136 $form->{l_onhand} = "";
1138 # qty is irrelevant unless bought or sold
1139 if ( $form->{bought}
1144 || $form->{quoted}) {
1145 $form->{l_onhand} = "Y";
1147 $form->{l_linetotalsellprice} = "";
1148 $form->{l_linetotallastcost} = "";
1152 IC->all_parts(\%myconfig, \%$form);
1155 partnumber description partsgroup bin onhand rop unit listprice
1156 linetotallistprice sellprice linetotalsellprice lastcost linetotallastcost
1157 priceupdate weight image drawing microfiche invnumber ordnumber quonumber
1158 transdate name serialnumber soldtotal deliverydate
1161 my @includeable_custom_variables = grep { $_->{includeable} } @{ $cvar_configs };
1162 my @searchable_custom_variables = grep { $_->{searchable} } @{ $cvar_configs };
1163 my %column_defs_cvars = map { +"cvar_$_->{name}" => { 'text' => $_->{description} } } @includeable_custom_variables;
1165 push @columns, map { "cvar_$_->{name}" } @includeable_custom_variables;
1168 'bin' => { 'text' => $locale->text('Bin'), },
1169 'deliverydate' => { 'text' => $locale->text('deliverydate'), },
1170 'description' => { 'text' => $locale->text('Part Description'), },
1171 'drawing' => { 'text' => $locale->text('Drawing'), },
1172 'image' => { 'text' => $locale->text('Image'), },
1173 'invnumber' => { 'text' => $locale->text('Invoice Number'), },
1174 'lastcost' => { 'text' => $locale->text('Last Cost'), },
1175 'linetotallastcost' => { 'text' => $locale->text('Extended'), },
1176 'linetotallistprice' => { 'text' => $locale->text('Extended'), },
1177 'linetotalsellprice' => { 'text' => $locale->text('Extended'), },
1178 'listprice' => { 'text' => $locale->text('List Price'), },
1179 'microfiche' => { 'text' => $locale->text('Microfiche'), },
1180 'name' => { 'text' => $locale->text('Name'), },
1181 'onhand' => { 'text' => $locale->text('Qty'), },
1182 'ordnumber' => { 'text' => $locale->text('Order Number'), },
1183 'partnumber' => { 'text' => $locale->text('Part Number'), },
1184 'partsgroup' => { 'text' => $locale->text('Group'), },
1185 'priceupdate' => { 'text' => $locale->text('Updated'), },
1186 'quonumber' => { 'text' => $locale->text('Quotation'), },
1187 'rop' => { 'text' => $locale->text('ROP'), },
1188 'sellprice' => { 'text' => $locale->text('Sell Price'), },
1189 'serialnumber' => { 'text' => $locale->text('Serial Number'), },
1190 'soldtotal' => { 'text' => $locale->text('soldtotal'), },
1191 'transdate' => { 'text' => $locale->text('Transdate'), },
1192 'unit' => { 'text' => $locale->text('Unit'), },
1193 'weight' => { 'text' => $locale->text('Weight'), },
1197 map { $column_defs{$_}->{visible} = $form->{"l_$_"} ? 1 : 0 } @columns;
1198 map { $column_defs{$_}->{align} = 'right' } qw(onhand sellprice listprice lastcost linetotalsellprice linetotallastcost linetotallistprice rop weight soldtotal);
1200 my @hidden_variables = (qw(l_subtotal l_linetotal searchitems itemstatus bom), @itemstatus_keys, @callback_keys, @searchable_custom_variables, map { "l_$_" } @columns);
1201 my $callback = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
1203 my @sort_full = qw(partnumber description onhand soldtotal deliverydate);
1204 my @sort_no_revers = qw(partsgroup bin priceupdate invnumber ordnumber quonumber name image drawing serialnumber);
1206 foreach my $col (@sort_full) {
1207 $column_defs{$col}->{link} = join '&', $callback, "sort=$col", map { "$_=" . E($form->{$_}) } qw(revers lastsort);
1209 map { $column_defs{$_}->{link} = "${callback}&sort=$_" } @sort_no_revers;
1211 # add order to callback
1212 $form->{callback} = join '&', ($callback, map { "${_}=" . E($form->{$_}) } qw(sort revers));
1214 my $report = SL::ReportGenerator->new(\%myconfig, $form);
1216 my %attachment_basenames = (
1217 'part' => $locale->text('part_list'),
1218 'service' => $locale->text('service_list'),
1219 'assembly' => $locale->text('assembly_list'),
1222 $report->set_options('top_info_text' => $locale->text('Options') . ': ' . join(', ', grep $_, @options),
1223 'raw_bottom_info_text' => $form->parse_html_template('ic/generate_report_bottom'),
1224 'output_format' => 'HTML',
1225 'title' => $form->{title},
1226 'attachment_basename' => $attachment_basenames{$form->{searchitems}} . strftime('_%Y%m%d', localtime time),
1228 $report->set_options_from_form();
1230 $report->set_columns(%column_defs);
1231 $report->set_column_order(@columns);
1233 $report->set_export_options('generate_report', @hidden_variables, qw(sort revers));
1235 $report->set_sort_indicator($form->{sort}, $form->{revers} ? 0 : 1);
1237 CVar->add_custom_variables_to_report('module' => 'IC',
1238 'trans_id_field' => 'id',
1239 'configs' => $cvar_configs,
1240 'column_defs' => \%column_defs,
1241 'data' => $form->{parts});
1243 CVar->add_custom_variables_to_report('module' => 'IC',
1244 'sub_module' => sub { $_[0]->{ioi} },
1245 'trans_id_field' => 'ioi_id',
1246 'configs' => $cvar_configs,
1247 'column_defs' => \%column_defs,
1248 'data' => $form->{parts});
1250 my @subtotal_columns = qw(sellprice listprice lastcost);
1251 my %subtotals = map { $_ => 0 } ('onhand', @subtotal_columns);
1252 my %totals = map { $_ => 0 } @subtotal_columns;
1254 my $same_item = $form->{parts}[0]{ $form->{sort} } if (scalar @{ $form->{parts} });
1256 my $defaults = AM->get_defaults();
1259 foreach my $ref (@{ $form->{parts} }) {
1261 # fresh row, for inserting later
1262 my $row = { map { $_ => { 'data' => $ref->{$_} } } @columns };
1264 $ref->{exchangerate} ||= 1;
1265 $ref->{price_factor} ||= 1;
1266 $ref->{sellprice} *= $ref->{exchangerate} / $ref->{price_factor};
1267 $ref->{listprice} *= $ref->{exchangerate} / $ref->{price_factor};
1268 $ref->{lastcost} *= $ref->{exchangerate} / $ref->{price_factor};
1270 # use this for assemblies
1271 my $onhand = $ref->{onhand};
1273 if ($ref->{assemblyitem}) {
1274 $row->{partnumber}{align} = 'right';
1275 $row->{onhand}{data} = 0;
1276 $onhand = 0 if ($form->{sold});
1279 my $edit_link = build_std_url('action=edit', 'id=' . E($ref->{id}), 'callback');
1280 $row->{partnumber}->{link} = $edit_link;
1281 $row->{description}->{link} = $edit_link;
1283 foreach (qw(sellprice listprice lastcost)) {
1284 $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{$_}, -2);
1285 $row->{"linetotal$_"}{data} = $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{$_}, 2);
1288 map { $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{$_}); } qw(onhand rop weight soldtotal);
1290 $row->{weight}->{data} .= ' ' . $defaults->{weightunit};
1292 if (!$ref->{assemblyitem}) {
1293 foreach my $col (@subtotal_columns) {
1294 $totals{$col} += $onhand * $ref->{$col};
1295 $subtotals{$col} += $onhand * $ref->{$col};
1298 $subtotals{onhand} += $onhand;
1302 if ($ref->{module} eq 'oe') {
1303 my $edit_oe_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');
1304 $row->{ordnumber}{link} = $edit_oe_link;
1305 $row->{quonumber}{link} = $edit_oe_link if (!$ref->{ordnumber});
1308 $row->{invnumber}{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'type=invoice', 'id=' . E($ref->{trans_id}), 'callback');
1311 # set properties of images
1312 if ($ref->{image} && (lc $report->{options}->{output_format} eq 'html')) {
1313 $row->{image}{data} = '';
1314 $row->{image}{raw_data} = '<a href="' . H($ref->{image}) . '"><img src="' . H($ref->{image}) . '" height="32" border="0"></a>';
1316 map { $row->{$_}{link} = $ref->{$_} } qw(drawing microfiche);
1318 $report->add_data($row);
1320 my $next_ref = $form->{parts}[$idx + 1];
1322 # insert subtotal rows
1323 if (($form->{l_subtotal} eq 'Y') &&
1325 (!$next_ref->{assemblyitem} && ($same_item ne $next_ref->{ $form->{sort} })))) {
1326 my $row = { map { $_ => { 'class' => 'listsubtotal', } } @columns };
1328 if (($form->{searchitems} ne 'assembly') || !$form->{bom}) {
1329 $row->{onhand}->{data} = $form->format_amount(\%myconfig, $subtotals{onhand});
1332 map { $row->{"linetotal$_"}->{data} = $form->format_amount(\%myconfig, $subtotals{$_}, 2) } @subtotal_columns;
1333 map { $subtotals{$_} = 0 } ('onhand', @subtotal_columns);
1335 $report->add_data($row);
1337 $same_item = $next_ref->{ $form->{sort} };
1343 if ($form->{"l_linetotal"}) {
1344 my $row = { map { $_ => { 'class' => 'listtotal', } } @columns };
1346 map { $row->{"linetotal$_"}->{data} = $form->format_amount(\%myconfig, $totals{$_}, 2) } @subtotal_columns;
1348 $report->add_separator();
1349 $report->add_data($row);
1352 $report->generate_with_headers();
1354 $lxdebug->leave_sub();
1355 } #end generate_report
1357 sub parts_subtotal {
1358 $lxdebug->enter_sub();
1360 $auth->assert('part_service_assembly_edit');
1363 our (%column_data, @column_index);
1364 our ($subtotalonhand, $totalsellprice, $totallastcost, $totallistprice, $subtotalsellprice, $subtotallastcost, $subtotallistprice);
1366 map { $column_data{$_} = "<td> </td>" } @column_index;
1367 $subtotalonhand = 0 if ($form->{searchitems} eq 'assembly' && $form->{bom});
1369 $column_data{onhand} =
1370 "<th class=listsubtotal align=right>"
1371 . $form->format_amount(\%myconfig, $subtotalonhand)
1374 $column_data{linetotalsellprice} =
1375 "<th class=listsubtotal align=right>"
1376 . $form->format_amount(\%myconfig, $subtotalsellprice, 2)
1378 $column_data{linetotallistprice} =
1379 "<th class=listsubtotal align=right>"
1380 . $form->format_amount(\%myconfig, $subtotallistprice, 2)
1382 $column_data{linetotallastcost} =
1383 "<th class=listsubtotal align=right>"
1384 . $form->format_amount(\%myconfig, $subtotallastcost, 2)
1387 $subtotalonhand = 0;
1388 $subtotalsellprice = 0;
1389 $subtotallistprice = 0;
1390 $subtotallastcost = 0;
1392 print "<tr class=listsubtotal>";
1394 map { print "\n$column_data{$_}" } @column_index;
1400 $lxdebug->leave_sub();
1404 $lxdebug->enter_sub();
1406 $auth->assert('part_service_assembly_edit');
1408 # show history button
1409 $form->{javascript} = qq|<script type="text/javascript" src="js/show_history.js"></script>|;
1410 #/show hhistory button
1411 IC->get_part(\%myconfig, \%$form);
1413 $form->{"original_partnumber"} = $form->{"partnumber"};
1415 $form->{title} = $locale->text('Edit ' . ucfirst $form->{item});
1420 $lxdebug->leave_sub();
1424 $lxdebug->enter_sub();
1426 $auth->assert('part_service_assembly_edit');
1428 IC->create_links("IC", \%myconfig, \%$form);
1431 map({ $form->{selectcurrency} .= "<option>$_\n" }
1432 split(/:/, $form->{currencies}));
1434 # parts and assemblies have the same links
1435 my $item = $form->{item};
1436 if ($form->{item} eq 'assembly') {
1440 # build the popup menus
1441 $form->{taxaccounts} = "";
1442 foreach my $key (keys %{ $form->{IC_links} }) {
1443 foreach my $ref (@{ $form->{IC_links}{$key} }) {
1445 # if this is a tax field
1446 if ($key =~ /IC_tax/) {
1447 if ($key =~ /\Q$item\E/) {
1448 $form->{taxaccounts} .= "$ref->{accno} ";
1449 $form->{"IC_tax_$ref->{accno}_description"} =
1450 "$ref->{accno}--$ref->{description}";
1453 if ($form->{amount}{ $ref->{accno} }) {
1454 $form->{"IC_tax_$ref->{accno}"} = "checked";
1457 $form->{"IC_tax_$ref->{accno}"} = "checked";
1462 $form->{"select$key"} .=
1463 "<option $ref->{selected}>$ref->{accno}--$ref->{description}\n";
1464 if ($form->{amount}{$key} eq $ref->{accno}) {
1465 $form->{$key} = "$ref->{accno}--$ref->{description}";
1471 chop $form->{taxaccounts};
1473 if (($form->{item} eq "part") || ($form->{item} eq "assembly")) {
1474 $form->{selectIC_income} = $form->{selectIC_sale};
1475 $form->{selectIC_expense} = $form->{selectIC_cogs};
1476 $form->{IC_income} = $form->{IC_sale};
1477 $form->{IC_expense} = $form->{IC_cogs};
1480 delete $form->{IC_links};
1481 delete $form->{amount};
1483 $form->get_partsgroup(\%myconfig, { all => 1 });
1485 $form->{partsgroup} = "$form->{partsgroup}--$form->{partsgroup_id}";
1487 if (@{ $form->{all_partsgroup} }) {
1488 $form->{selectpartsgroup} = qq|<option>\n|;
1489 map { $form->{selectpartsgroup} .= qq|<option value="$_->{partsgroup}--$_->{id}">$_->{partsgroup}\n| } @{ $form->{all_partsgroup} };
1492 if ($form->{item} eq 'assembly') {
1494 foreach my $i (1 .. $form->{assembly_rows}) {
1495 if ($form->{"partsgroup_id_$i"}) {
1496 $form->{"partsgroup_$i"} =
1497 qq|$form->{"partsgroup_$i"}--$form->{"partsgroup_id_$i"}|;
1500 $form->get_partsgroup(\%myconfig);
1502 if (@{ $form->{all_partsgroup} }) {
1503 $form->{selectassemblypartsgroup} = qq|<option>\n|;
1506 $form->{selectassemblypartsgroup} .=
1507 qq|<option value="$_->{partsgroup}--$_->{id}">$_->{partsgroup}\n|
1508 } @{ $form->{all_partsgroup} };
1511 $lxdebug->leave_sub();
1515 $lxdebug->enter_sub();
1517 $auth->assert('part_service_assembly_edit');
1519 $form->{eur} = $main::eur; # config dumps into namespace - yuck
1520 $form->{pg_keys} = sub { "$_[0]->{partsgroup}--$_[0]->{id}" };
1521 $form->{description_area} = ($form->{rows} = $form->numtextrows($form->{description}, 40)) > 1;
1522 $form->{notes_rows} = max 4, $form->numtextrows($form->{notes}, 40), $form->numtextrows($form->{formel}, 40);
1524 map { $form->{"is_$_"} = ($form->{item} eq $_) } qw(part service assembly);
1525 map { $form->{$_} =~ s/"/"/g; } qw(unit);
1527 $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS',
1528 'partsgroup' => 'all_partsgroup',
1529 'vendors' => 'ALL_VENDORS',);
1532 IC->retrieve_buchungsgruppen(\%myconfig, $form);
1533 @{ $form->{BUCHUNGSGRUPPEN} } = grep { $_->{id} eq $form->{buchungsgruppen_id} || ($form->{id} && $form->{orphaned}) || !$form->{id} } @{ $form->{BUCHUNGSGRUPPEN} };
1535 # use JavaScript Calendar or not (yes!)
1536 $form->{jsscript} = 1;
1538 my $units = AM->retrieve_units(\%myconfig, $form);
1539 $form->{ALL_UNITS} = [ map +{ name => $_ }, sort { $units->{$a}{sortkey} <=> $units->{$b}{sortkey} } keys %$units ];
1541 $form->{defaults} = AM->get_defaults();
1543 $form->{fokus} = "ic.partnumber";
1545 $form->{CUSTOM_VARIABLES} = CVar->get_custom_variables('module' => 'IC', 'trans_id' => $form->{id});
1547 CVar->render_inputs('variables' => $form->{CUSTOM_VARIABLES}, show_disabled_message => 1)
1548 if (scalar @{ $form->{CUSTOM_VARIABLES} });
1551 #print $form->parse_html_template('ic/form_header', { ALL_PRICE_FACTORS => $form->{ALL_PRICE_FACTORS},
1552 # ALL_UNITS => $form->{ALL_UNITS},
1553 # BUCHUNGSGRUPPEN => $form->{BUCHUNGSGRUPPEN},
1554 # payment_terms => $form->{payment_terms},
1555 # all_partsgroup => $form->{all_partsgroup}});
1556 print $form->parse_html_template('ic/form_header');
1557 $lxdebug->leave_sub();
1561 $lxdebug->enter_sub();
1563 $auth->assert('part_service_assembly_edit');
1565 print $form->parse_html_template('ic/form_footer');
1567 $lxdebug->leave_sub();
1571 $lxdebug->enter_sub();
1574 my @mm_data = grep { any { $_ ne '' } @$_{qw(make model)} } map +{ make => $form->{"make_$_"}, model => $form->{"model_$_"} }, 1 .. $numrows;
1575 delete @{$form}{grep { m/^make_\d+/ || m/^model_\d+/ } keys %{ $form }};
1576 print $form->parse_html_template('ic/makemodel', { MM_DATA => [ @mm_data, {} ], mm_rows => scalar @mm_data + 1 });
1578 $lxdebug->leave_sub();
1582 $lxdebug->enter_sub();
1585 my ($nochange, $callback, $previousform, $linetotal, $line_purchase_price, $href);
1587 our ($deliverydate); # ToDO: check if this indeed comes from global context
1589 @column_index = qw(runningnumber qty unit bom partnumber description partsgroup lastcost total);
1591 if ($form->{previousform}) {
1593 @column_index = qw(qty unit bom partnumber description partsgroup total);
1597 $form->{old_callback} = $form->{callback};
1598 $callback = $form->{callback};
1599 $form->{callback} = "$form->{script}?action=display_form";
1602 map { delete $form->{$_} } qw(action header);
1604 # save form variables in a previousform variable
1605 $previousform = $form->escape($form->escape(join '&', map {
1606 sprintf "%s=%s", Q($_), /^listprice|lastcost|sellprice$/ ? $form->format_amount(\%myconfig, $form->{$_}) : $form->{$_}
1607 } grep { ref $form->{$_} eq '' && $form->{$_} } grep { !/^select/ } sort keys %$form ));
1609 $form->{callback} = $callback;
1610 $form->{assemblytotal} = 0;
1611 $form->{assembly_purchase_price_total} = 0;
1612 $form->{weight} = 0;
1616 runningnumber => { text => $locale->text('No.'), nowrap => 1, width => '5%' },
1617 qty => { text => $locale->text('Qty'), nowrap => 1, width => '10%' },
1618 unit => { text => $locale->text('Unit'), nowrap => 1, width => '5%' },
1619 partnumber => { text => $locale->text('Part Number'), nowrap => 1, width => '20%' },
1620 description => { text => $locale->text('Part Description'), nowrap => 1, width => '50%' },
1621 lastcost => { text => $locale->text('Purchase Prices'), nowrap => 1, width => '50%' },
1622 total => { text => $locale->text('Sale Prices'), nowrap => 1, },
1623 bom => { text => $locale->text('BOM'), },
1624 partsgroup => { text => $locale->text('Group'), },
1629 for my $i (1 .. $numrows) {
1630 my (%row, @row_hiddens);
1632 $form->{"partnumber_$i"} =~ s/\"/"/g;
1634 $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / ($form->{"price_factor_$i"} || 1), 4);
1635 $line_purchase_price = $form->round_amount($form->{"lastcost_$i"} * $form->{"qty_$i"} / ($form->{"price_factor_$i"} || 1), 4);
1636 $form->{assemblytotal} += $linetotal;
1637 $form->{assembly_purchase_price_total} += $line_purchase_price;
1638 $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
1639 $linetotal = $form->format_amount(\%myconfig, $linetotal, 2);
1640 $line_purchase_price = $form->format_amount(\%myconfig, $line_purchase_price, 2);
1641 $href = qq|$form->{script}?action=edit&id=$form->{"id_$i"}&rowcount=$i&previousform=$previousform|;
1642 map { $row{$_}{data} = "" } qw(qty unit partnumber description bom partsgroup runningnumber);
1645 if (($i >= 1) && ($i == $numrows)) {
1646 if (!$form->{previousform}) {
1647 $row{partnumber}{data} = qq|<input name="partnumber_$i" size=15 value="$form->{"partnumber_$i"}">|;
1648 $row{qty}{data} = qq|<input name="qty_$i" size=5 value="$form->{"qty_$i"}">|;
1649 $row{description}{data} = qq|<input name="description_$i" size=40 value="$form->{"description_$i"}">|;
1650 $row{partsgroup}{data} = qq|<input name="partsgroup_$i" size=10 value="$form->{"partsgroup_$i"}">|;
1654 if ($form->{previousform}) {
1655 push @row_hiddens, qw(qty bom);
1656 $row{partnumber}{data} = $form->{"partnumber_$i"};
1657 $row{qty}{data} = $form->{"qty_$i"};
1658 $row{bom}{data} = $form->{"bom_$i"} ? "x" : " ";
1659 $row{qty}{align} = 'right';
1661 $row{partnumber}{data} = qq|<a href=$href>$form->{"partnumber_$i"}</a>|;
1662 $row{qty}{data} = qq|<input name="qty_$i" size=5 value="$form->{"qty_$i"}">|;
1663 $row{runningnumber}{data} = qq|<input name="runningnumber_$i" size=3 value="$i">|;
1664 $row{bom}{data} = sprintf qq|<input name="bom_$i" type=checkbox class=checkbox value=1 %s>|,
1665 $form->{"bom_$i"} ? 'checked' : '';
1667 push @row_hiddens, qw(unit description partnumber partsgroup);
1668 $row{unit}{data} = $form->{"unit_$i"};
1669 $row{description}{data} = $form->{"description_$i"};
1670 $row{partsgroup}{data} = $form->{"partsgroup_$i"};
1671 $row{bom}{align} = 'center';
1674 $row{lastcost}{data} = $line_purchase_price;
1675 $row{total}{data} = $linetotal;
1676 $row{deliverydate}{data} = $deliverydate;
1677 $row{lastcost}{align} = 'right';
1678 $row{total}{align} = 'right';
1679 $row{deliverydate}{align} = 'right';
1681 push @row_hiddens, qw(id sellprice lastcost weight price_factor_id price_factor);
1682 $row{hiddens} = [ map +{ name => "${_}_$i", value => $form->{"${_}_$i"} }, @row_hiddens ];
1687 print $form->parse_html_template('ic/assembly_row', { COLUMNS => \@column_index, ROWS => \@ROWS, HEADER => \%header });
1689 $lxdebug->leave_sub();
1693 $lxdebug->enter_sub();
1695 # parse pricegroups. and no, don't rely on check_form for this...
1696 map { $form->{"price_$_"} = $form->parse_amount(\%myconfig, $form->{"price_$_"}) } 1 .. $form->{price_rows};
1698 if ($form->{item} eq "assembly") {
1699 my $i = $form->{assembly_rows};
1701 # if last row is empty check the form otherwise retrieve item
1702 if ( ($form->{"partnumber_$i"} eq "")
1703 && ($form->{"description_$i"} eq "")
1704 && ($form->{"partsgroup_$i"} eq "")) {
1710 IC->assembly_item(\%myconfig, \%$form);
1712 my $rows = scalar @{ $form->{item_list} };
1715 $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
1718 $form->{makemodel_rows}--;
1722 map { $form->{item_list}[$i]{$_} =~ s/\"/"/g }
1723 qw(partnumber description unit partsgroup);
1724 map { $form->{"${_}_$i"} = $form->{item_list}[0]{$_} }
1725 keys %{ $form->{item_list}[0] };
1726 $form->{"runningnumber_$i"} = $form->{assembly_rows};
1727 $form->{assembly_rows}++;
1735 $form->{rowcount} = $i;
1736 $form->{assembly_rows}++;
1743 } elsif (($form->{item} eq 'part') || ($form->{item} eq 'service')) {
1747 $lxdebug->leave_sub();
1751 $lxdebug->enter_sub();
1753 $auth->assert('part_service_assembly_edit');
1755 my ($parts_id, %newform, $previousform, $amount, $callback);
1757 # check if there is a part number - commented out, cause there is an automatic allocation of numbers
1758 # $form->isblank("partnumber", $locale->text(ucfirst $form->{item}." Part Number missing!"));
1760 # check if there is a description
1761 $form->isblank("description", $locale->text("Part Description missing!"));
1763 $form->error($locale->text("Inventory quantity must be zero before you can set this $form->{item} obsolete!"))
1764 if $form->{obsolete} && $form->{onhand} * 1 && $form->{item} ne 'service';
1766 if (!$form->{buchungsgruppen_id}) {
1767 $form->error($locale->text("Parts must have an entry type.") . " " .
1768 $locale->text("If you see this message, you most likely just setup your LX-Office and haven't added any entry types. If this is the case, the option is accessible for administrators in the System menu.")
1772 $form->error($locale->text('Description must not be empty!')) unless $form->{description};
1773 $form->error($locale->text('Partnumber must not be set to empty!')) if $form->{id} && !$form->{partnumber};
1776 $lxdebug->message($LXDebug::DEBUG1, "ic.pl: sellprice in save = $form->{sellprice}\n");
1777 if (IC->save(\%myconfig, \%$form) == 3) {
1778 $form->error($locale->text('Partnumber not unique!'));
1780 # saving the history
1781 if(!exists $form->{addition}) {
1782 $form->{snumbers} = qq|partnumber_| . $form->{partnumber};
1783 $form->{addition} = "SAVED";
1784 $form->save_history($form->dbconnect(\%myconfig));
1786 # /saving the history
1787 $parts_id = $form->{id};
1790 # load previous variables
1791 if ($form->{previousform}) {
1793 # save the new form variables before splitting previousform
1794 map { $newform{$_} = $form->{$_} } keys %$form;
1796 $previousform = $form->unescape($form->{previousform});
1798 # don't trample on previous variables
1799 map { delete $form->{$_} } keys %newform;
1801 my $ic_cvar_configs = CVar->get_configs(module => 'IC');
1802 my @ic_cvar_fields = map { "cvar_$_->{name}" } @{ $ic_cvar_configs };
1804 # now take it apart and restore original values
1805 foreach my $item (split /&/, $previousform) {
1806 my ($key, $value) = split m/=/, $item, 2;
1807 $value =~ s/%26/&/g;
1808 $form->{$key} = $value;
1810 $form->{taxaccounts} = $newform{taxaccount2};
1812 if ($form->{item} eq 'assembly') {
1814 # undo number formatting
1815 map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) }
1816 qw(weight listprice sellprice rop);
1818 $form->{assembly_rows}--;
1819 $i = $newform{rowcount};
1820 $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
1822 $form->{sellprice} -= $form->{"sellprice_$i"} * $form->{"qty_$i"};
1823 $form->{weight} -= $form->{"weight_$i"} * $form->{"qty_$i"};
1825 # change/add values for assembly item
1826 map { $form->{"${_}_$i"} = $newform{$_} } qw(partnumber description bin unit weight listprice sellprice inventory_accno income_accno expense_accno price_factor_id);
1827 map { $form->{"ic_${_}_$i"} = $newform{$_} } @ic_cvar_fields;
1829 # das ist __voll__ bekloppt, dass so auszurechnen jb 22.5.09
1830 #$form->{sellprice} += $form->{"sellprice_$i"} * $form->{"qty_$i"};
1831 $form->{weight} += $form->{"weight_$i"} * $form->{"qty_$i"};
1835 # set values for last invoice/order item
1836 $i = $form->{rowcount};
1837 $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
1839 map { $form->{"${_}_$i"} = $newform{$_} } qw(partnumber description bin unit listprice inventory_accno income_accno expense_accno sellprice lastcost price_factor_id);
1840 map { $form->{"ic_${_}_$i"} = $newform{$_} } @ic_cvar_fields;
1842 $form->{"longdescription_$i"} = $newform{notes};
1844 $form->{"sellprice_$i"} = $newform{lastcost} if ($form->{vendor_id});
1846 if ($form->{exchangerate} != 0) {
1847 $form->{"sellprice_$i"} /= $form->{exchangerate};
1850 $lxdebug->message($LXDebug::DEBUG1, qq|sellprice_$i in previousform 2 = | . $form->{"sellprice_$i"} . qq|\n|);
1852 map { $form->{"taxaccounts_$i"} .= "$_ " } split / /, $newform{taxaccount};
1853 chop $form->{"taxaccounts_$i"};
1854 foreach my $item (qw(description rate taxnumber)) {
1855 my $index = $form->{"taxaccounts_$i"} . "_$item";
1856 $form->{$index} = $newform{$index};
1859 # credit remaining calculation
1860 $amount = $form->{"sellprice_$i"} * (1 - $form->{"discount_$i"} / 100) * $form->{"qty_$i"};
1862 map { $form->{"${_}_base"} += $amount } (split / /, $form->{"taxaccounts_$i"});
1863 map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded};
1865 $form->{creditremaining} -= $amount;
1867 # redo number formatting, because invoice parse them!
1868 map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}) } qw(weight listprice sellprice rop);
1871 $form->{"id_$i"} = $parts_id;
1873 # Get the actual price factor (not just the ID) for the marge calculation.
1874 $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
1875 foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
1876 next if ($pfac->{id} != $newform{price_factor_id});
1877 $form->{"marge_price_factor_$i"} = $pfac->{factor};
1880 delete $form->{ALL_PRICE_FACTORS};
1882 delete $form->{action};
1884 # restore original callback
1885 $callback = $form->unescape($form->{callback});
1886 $form->{callback} = $form->unescape($form->{old_callback});
1887 delete $form->{old_callback};
1889 $form->{makemodel_rows}--;
1891 # put callback together
1892 foreach my $key (keys %$form) {
1894 # do single escape for Apache 2.0
1895 my $value = $form->escape($form->{$key}, 1);
1896 $callback .= qq|&$key=$value|;
1898 $form->{callback} = $callback;
1900 $lxdebug->message($LXDebug::DEBUG1, qq|ic.pl: sellprice_$i nach sub save = | . $form->{"sellprice_$i"} . qq|\n|);
1905 $lxdebug->leave_sub();
1909 $lxdebug->enter_sub();
1911 $auth->assert('part_service_assembly_edit');
1913 # saving the history
1914 if(!exists $form->{addition}) {
1915 $form->{snumbers} = qq|partnumber_| . $form->{partnumber};
1916 $form->{addition} = "SAVED AS NEW";
1917 $form->save_history($form->dbconnect(\%myconfig));
1919 # /saving the history
1921 if ($form->{"original_partnumber"} &&
1922 ($form->{"partnumber"} eq $form->{"original_partnumber"})) {
1923 $form->{partnumber} = "";
1926 $lxdebug->leave_sub();
1930 $lxdebug->enter_sub();
1932 $auth->assert('part_service_assembly_edit');
1934 # saving the history
1935 if(!exists $form->{addition}) {
1936 $form->{snumbers} = qq|partnumber_| . $form->{partnumber};
1937 $form->{addition} = "DELETED";
1938 $form->save_history($form->dbconnect(\%myconfig));
1940 # /saving the history
1941 my $rc = IC->delete(\%myconfig, \%$form);
1944 $form->redirect($locale->text('Item deleted!')) if ($rc > 0);
1945 $form->error($locale->text('Cannot delete item!'));
1947 $lxdebug->leave_sub();
1951 $lxdebug->enter_sub();
1953 $auth->assert('part_service_assembly_edit');
1958 pricegroup => $form->{"pricegroup_$_"},
1959 pricegroup_id => $form->{"pricegroup_id_$_"},
1960 price => $form->{"price_$_"},
1963 print $form->parse_html_template('ic/price_row', { PRICES => \@PRICES });
1965 $lxdebug->leave_sub();
1968 sub parts_language_selection {
1969 $lxdebug->enter_sub();
1971 $auth->assert('part_service_assembly_edit');
1973 our ($onload, $callback);
1975 my $languages = IC->retrieve_languages(\%myconfig, $form);
1977 if ($form->{language_values} ne "") {
1978 foreach my $item (split(/---\+\+\+---/, $form->{language_values})) {
1979 my ($language_id, $translation, $longdescription) = split(/--\+\+--/, $item);
1981 foreach my $language (@{ $languages }) {
1982 next unless ($language->{id} == $language_id);
1984 $language->{translation} = $translation;
1985 $language->{longdescription} = $longdescription;
1991 my @header_sort = qw(name longdescription);
1992 my %header_title = ( "name" => $locale->text("Name"),
1993 "longdescription" => $locale->text("Long Description"),
1997 map(+{ "column_title" => $header_title{$_},
1999 "callback" => $callback,
2003 $form->{"title"} = $locale->text("Language Values");
2005 print $form->parse_html_template("ic/parts_language_selection", { "HEADER" => \@header,
2006 "LANGUAGES" => $languages,
2007 "onload" => $onload });
2009 $lxdebug->leave_sub();
2012 sub ajax_autocomplete {
2013 $main::lxdebug->enter_sub();
2015 my $form = $main::form;
2016 my %myconfig = %main::myconfig;
2018 $form->{column} = 'description' unless $form->{column} =~ /^partnumber|description$/;
2019 $form->{$form->{column}} = $form->{q} || '';
2020 $form->{limit} = ($form->{limit} * 1) || 10;
2021 $form->{searchitems} ||= '';
2023 my @results = IC->all_parts(\%myconfig, $form);
2025 print $form->ajax_response_header(),
2026 $form->parse_html_template('ic/ajax_autocomplete');
2028 $main::lxdebug->leave_sub();
2031 sub continue { call_sub($form->{"nextsub"}); }