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);
130 $form->{title} = $locale->text('Update Prices');
134 print $form->parse_html_template('ic/search_update_prices', { PRICE_ROWS => $pricegroups });
136 $lxdebug->leave_sub();
139 sub confirm_price_update {
140 $lxdebug->enter_sub();
142 $auth->assert('part_service_assembly_edit');
145 my $value_found = undef;
147 foreach my $idx (qw(sellprice listprice), (1..$form->{price_rows})) {
148 my $name = $idx =~ m/\d/ ? $form->{"pricegroup_${idx}"} : $idx eq 'sellprice' ? $locale->text('Sell Price') : $locale->text('List Price');
149 my $type = $idx =~ m/\d/ ? $form->{"pricegroup_type_${idx}"} : $form->{"${idx}_type"};
150 my $value_idx = $idx =~ m/\d/ ? "price_${idx}" : $idx;
151 my $value = $form->parse_amount(\%myconfig, $form->{$value_idx});
153 if ((0 > $value) && ($type eq 'percent')) {
154 push @errors, $locale->text('You cannot adjust the price for pricegroup "#1" by a negative percentage.', $name);
156 } elsif (!$value && ($form->{$value_idx} ne '')) {
157 push @errors, $locale->text('No valid number entered for pricegroup "#1".', $name);
159 } elsif (0 < $value) {
164 push @errors, $locale->text('No prices will be updated because no prices have been entered.') if (!$value_found);
166 my $num_matches = IC->get_num_matches_for_priceupdate();
171 $form->show_generic_error(join('<br>', @errors), 'back_button' => 1);
174 $form->{nextsub} = "update_prices";
176 map { delete $form->{$_} } qw(action header);
178 print $form->parse_html_template('ic/confirm_price_update', { HIDDENS => [ map { name => $_, value => $form->{$_} }, keys %$form ],
179 num_matches => $num_matches });
181 $lxdebug->leave_sub();
185 $lxdebug->enter_sub();
187 $auth->assert('part_service_assembly_edit');
189 my $num_updated = IC->update_prices(\%myconfig, \%$form);
191 if (-1 != $num_updated) {
192 $form->redirect($locale->text('#1 prices were updated.', $num_updated));
194 $form->error($locale->text('Could not update prices!'));
197 $lxdebug->leave_sub();
201 # $lxdebug->enter_sub();
203 # $auth->assert('part_service_assembly_edit');
205 # our ($j, $lastndx);
208 # $form->{title} = $locale->text('Top 100 hinzufuegen');
212 # push @custom_hiddens, qw(searchitems title bom titel revers lastsort sort ndxs_counter extras);
213 # push @custom_hiddens, qw(itemstatus l_linetotal l_partnumber l_description l_onhand l_unit l_sellprice l_linetotalsellprice);
215 # +{ name => 'row', value => $j },
216 # +{ name => 'nextsub', value => 'item_selected' },
217 # +{ name => 'test', value => 'item_selected' },
218 # +{ name => 'lastndx', value => $lastndx },
219 # map(+{ name => $_, value => $form->{$_} }, @custom_hiddens),
222 # my ($partnumber, $description, $unit, $sellprice, $soldtotal);
223 # # if choice set data
224 ## if ($form->{ndx}) {
225 ## for my $i (0 .. $form->{ndxs_counter}) {
227 ## # insert data into top100
228 ## push @{ $form->{parts} },
230 ## partnumber => $form->{"totop100_partnumber_$j"},
231 ## description => $form->{"totop100_description_$j"},
232 ## unit => $form->{"totop100_unit_$j"},
233 ## sellprice => $form->{"totop100_sellprice_$j"},
234 ## soldtotal => $form->{"totop100_soldtotal_$j"},
241 # # set data for next page
242 # for my $i (1 .. $form->{ndxs_counter}) {
243 # $partnumber = $form->{"totop100_partnumber_$i"};
244 # $description = $form->{"totop100_description_$i"};
245 # $unit = $form->{"totop100_unit_$i"};
246 # $sellprice = $form->{"totop100_sellprice_$i"};
247 # $soldtotal = $form->{"totop100_soldtotal_$i"};
250 # totop100_partnumber => $form->{"totop100_partnumber_$i"},
251 # totop100_description => $form->{"totop100_description_$i"},
252 # totop100_unit => $form->{"totop100_unit_$i"},
253 # totop100_sellprice => $form->{"totop100_sellprice_$i"},
254 # totop100_soldtotal => $form->{"totop100_soldtotal_$i"},
258 ##<input type=hidden name=totop100_partnumber_$i value=$form->{"totop100_partnumber_$i"}>
259 ##<input type=hidden name=totop100_description_$i value=$form->{"totop100_description_$i"}>
260 ##<input type=hidden name=totop100_unit_$i value=$form->{"totop100_unit_$i"}>
261 ##<input type=hidden name=totop100_sellprice_$i value=$form->{"totop100_sellprice_$i"}>
262 ##<input type=hidden name=totop100_soldtotal_$i value=$form->{"totop100_soldtotal_$i"}>
266 # print $form->parse_html_template('ic/choice', +{ HIDDENS => \@HIDDENS, PARTS => \@PARTS });
268 # $lxdebug->leave_sub();
272 # $lxdebug->enter_sub();
274 # $auth->assert('part_service_assembly_edit');
277 # our ($partnumber, $description, $unit, $sellprice, $soldtotal);
279 # my @sortorders = ("", "partnumber", "description", "all");
280 # my $sortorder = $sortorders[($form->{description} ? 2 : 0) + ($form->{partnumber} ? 1 : 0)];
281 # IC->get_parts(\%myconfig, \%$form, $sortorder);
283 # $form->{title} = $locale->text('Top 100 hinzufuegen');
289 # <form method=post action=ic.pl>
292 # <th class=listtop colspan=6>| . $locale->text('choice part') . qq|</th>
294 # <tr height="5"></tr>
295 # <tr class=listheading>
297 # <th class=listheading>| . $locale->text('Part Number') . qq|</th>
298 # <th class=listheading>| . $locale->text('Part Description') . qq|</th>
299 # <th class=listheading>| . $locale->text('Unit of measure') . qq|</th>
300 # <th class=listheading>| . $locale->text('Sell Price') . qq|</th>
301 # <th class=listheading>| . $locale->text('soldtotal') . qq|</th>
305 # my $i = $form->{rows};
307 # for ($j = 1; $j <= $i; $j++) {
310 # <tr class=listrow| . ($j % 2) . qq|>|;
313 # <td><input name=ndx class=radio type=radio value=$j checked></td>|;
316 # <td><input name=ndx class=radio type=radio value=$j></td>|;
319 # <td><input name="new_partnumber_$j" type=hidden value="$form->{"partnumber_$j"}">$form->{"partnumber_$j"}</td>
320 # <td><input name="new_description_$j" type=hidden value="$form->{"description_$j"}">$form->{"description_$j"}</td>
321 # <td><input name="new_unit_$j" type=hidden value="$form->{"unit_$j"}">$form->{"unit_$j"}</td>
322 # <td><input name="new_sellprice_$j" type=hidden value="$form->{"sellprice_$j"}">$form->{"sellprice_$j"}</td>
323 # <td><input name="new_soldtotal_$j" type=hidden value="$form->{"soldtotal_$j"}">$form->{"soldtotal_$j"}</td>
326 # <input name="new_id_$j" type=hidden value="$form->{"id_$j"}">|;
336 #<input type=hidden name=itemstatus value="$form->{itemstatus}">
337 #<input type=hidden name=l_linetotal value="$form->{l_linetotal}">
338 #<input type=hidden name=l_partnumber value="$form->{l_partnumber}">
339 #<input type=hidden name=l_description value="$form->{l_description}">
340 #<input type=hidden name=l_onhand value="$form->{l_onhand}">
341 #<input type=hidden name=l_unit value="$form->{l_unit}">
342 #<input type=hidden name=l_sellprice value="$form->{l_sellprice}">
343 #<input type=hidden name=l_linetotalsellprice value="$form->{l_linetotalsellprice}">
344 #<input type=hidden name=sort value="$form->{sort}">
345 #<input type=hidden name=revers value="$form->{revers}">
346 #<input type=hidden name=lastsort value="$form->{lastsort}">
348 #<input type=hidden name=bom value="$form->{bom}">
349 #<input type=hidden name=titel value="$form->{titel}">
350 #<input type=hidden name=searchitems value="$form->{searchitems}">
352 #<input type=hidden name=row value=$j>
354 #<input type=hidden name=nextsub value=item_selected>
356 #<input name=lastndx type=hidden value=$lastndx>
358 #<input name=ndxs_counter type=hidden value=$form->{ndxs_counter}>|;
362 # if (($form->{ndxs_counter}) > 0) {
363 # for ($i = 1; ($i < $form->{ndxs_counter} + 1); $i++) {
365 # $partnumber = $form->{"totop100_partnumber_$i"};
366 # $description = $form->{"totop100_description_$i"};
367 # $unit = $form->{"totop100_unit_$i"};
368 # $sellprice = $form->{"totop100_sellprice_$i"};
369 # $soldtotal = $form->{"totop100_soldtotal_$i"};
372 #<input type=hidden name=totop100_partnumber_$i value=$form->{"totop100_partnumber_$i"}>
373 #<input type=hidden name=totop100_description_$i value=$form->{"totop100_description_$i"}>
374 #<input type=hidden name=totop100_unit_$i value=$form->{"totop100_unit_$i"}>
375 #<input type=hidden name=totop100_sellprice_$i value=$form->{"totop100_sellprice_$i"}>
376 #<input type=hidden name=totop100_soldtotal_$i value=$form->{"totop100_soldtotal_$i"}>
384 #<input class=submit type=submit name=action value="|
385 # . $locale->text('TOP100') . qq|">
391 # $lxdebug->leave_sub();
395 $lxdebug->enter_sub();
397 $auth->assert('part_service_assembly_edit');
400 $form->{ndxs_counter}++;
402 if ($form->{ndxs_counter} > 0) {
404 my $index = $form->{ndx};
406 $form->{"totop100_partnumber_$form->{ndxs_counter}"} = $form->{"new_partnumber_$index"};
407 $form->{"totop100_description_$form->{ndxs_counter}"} = $form->{"new_description_$index"};
408 $form->{"totop100_unit_$form->{ndxs_counter}"} = $form->{"new_unit_$index"};
409 $form->{"totop100_sellprice_$form->{ndxs_counter}"} = $form->{"new_sellprice_$index"};
410 $form->{"totop100_soldtotal_$form->{ndxs_counter}"} = $form->{"new_soldtotal_$index"};
414 $lxdebug->leave_sub();
418 $lxdebug->enter_sub();
420 $auth->assert('part_service_assembly_edit');
422 my ($revers, $lastsort, $callback, $option, $description, $sameitem,
423 $partnumber, $unit, $sellprice, $soldtotal, $totop100, $onhand, $align);
424 my (@column_index, %column_header, %column_data);
425 my ($totalsellprice, $totallastcost, $totallistprice, $subtotalonhand, $subtotalsellprice, $subtotallastcost, $subtotallistprice);
427 $form->{top100} = "top100";
428 $form->{l_soldtotal} = "Y";
429 $form->{soldtotal} = "soldtotal";
430 $form->{sort} = "soldtotal";
431 $form->{l_qty} = "N";
432 $form->{l_linetotal} = "";
434 $form->{number} = "position";
435 $form->{l_number} = "Y";
439 $form->{title} = $locale->text('Top 100');
441 $revers = $form->{revers};
442 $lastsort = $form->{lastsort};
444 if (($form->{lastsort} eq "") && ($form->{sort} eq undef)) {
446 $form->{lastsort} = "partnumber";
447 $form->{sort} = "partnumber";
451 "$form->{script}?action=top100&searchitems=$form->{searchitems}&itemstatus=$form->{itemstatus}&bom=$form->{bom}&l_linetotal=$form->{l_linetotal}&title="
452 . $form->escape($form->{title}, 1);
454 # if we have a serialnumber limit search
455 if ($form->{serialnumber} || $form->{l_serialnumber}) {
456 $form->{l_serialnumber} = "Y";
457 unless ( $form->{bought}
460 || $form->{quoted}) {
461 $form->{bought} = $form->{sold} = 1;
464 IC->all_parts(\%myconfig, \%$form);
466 if ($form->{itemstatus} eq 'active') {
467 $option .= $locale->text('Active') . " : ";
469 if ($form->{itemstatus} eq 'obsolete') {
470 $option .= $locale->text('Obsolete') . " : ";
472 if ($form->{itemstatus} eq 'orphaned') {
473 $option .= $locale->text('Orphaned') . " : ";
475 if ($form->{itemstatus} eq 'onhand') {
476 $option .= $locale->text('On Hand') . " : ";
477 $form->{l_onhand} = "Y";
479 if ($form->{itemstatus} eq 'short') {
480 $option .= $locale->text('Short') . " : ";
481 $form->{l_onhand} = "Y";
483 if ($form->{onorder}) {
484 $form->{l_ordnumber} = "Y";
485 $callback .= "&onorder=$form->{onorder}";
486 $option .= $locale->text('On Order') . " : ";
488 if ($form->{ordered}) {
489 $form->{l_ordnumber} = "Y";
490 $callback .= "&ordered=$form->{ordered}";
491 $option .= $locale->text('Ordered') . " : ";
494 $form->{l_quonumber} = "Y";
495 $callback .= "&rfq=$form->{rfq}";
496 $option .= $locale->text('RFQ') . " : ";
498 if ($form->{quoted}) {
499 $form->{l_quonumber} = "Y";
500 $callback .= ""ed=$form->{quoted}";
501 $option .= $locale->text('Quoted') . " : ";
503 if ($form->{bought}) {
504 $form->{l_invnumber} = "Y";
505 $callback .= "&bought=$form->{bought}";
506 $option .= $locale->text('Bought') . " : ";
509 $form->{l_invnumber} = "Y";
510 $callback .= "&sold=$form->{sold}";
511 $option .= $locale->text('Sold') . " : ";
518 || $form->{quoted}) {
520 $form->{l_lastcost} = "";
521 $form->{l_name} = "Y";
522 if ($form->{transdatefrom}) {
523 $callback .= "&transdatefrom=$form->{transdatefrom}";
525 . $locale->text('From')
527 . $locale->date(\%myconfig, $form->{transdatefrom}, 1);
529 if ($form->{transdateto}) {
530 $callback .= "&transdateto=$form->{transdateto}";
532 . $locale->text('To')
534 . $locale->date(\%myconfig, $form->{transdateto}, 1);
540 if ($form->{partnumber}) {
541 $callback .= "&partnumber=$form->{partnumber}";
542 $option .= $locale->text('Part Number') . qq| : $form->{partnumber}<br>|;
545 $callback .= "&partnumber=$form->{ean}";
546 $option .= $locale->text('EAN') . qq| : $form->{ean}<br>|;
548 if ($form->{partsgroup}) {
549 $callback .= "&partsgroup=$form->{partsgroup}";
550 $option .= $locale->text('Group') . qq| : $form->{partsgroup}<br>|;
552 if ($form->{serialnumber}) {
553 $callback .= "&serialnumber=$form->{serialnumber}";
554 $option .= $locale->text('Serial Number') . qq| : $form->{serialnumber}<br>|;
556 if ($form->{description}) {
557 $callback .= "&description=$form->{description}";
558 $description = $form->{description};
559 $description =~ s/\n/<br>/g;
560 $option .= $locale->text('Part Description') . qq| : $form->{description}<br>|;
563 $callback .= "&make=$form->{make}";
564 $option .= $locale->text('Make') . qq| : $form->{make}<br>|;
566 if ($form->{model}) {
567 $callback .= "&model=$form->{model}";
568 $option .= $locale->text('Model') . qq| : $form->{model}<br>|;
570 if ($form->{drawing}) {
571 $callback .= "&drawing=$form->{drawing}";
572 $option .= $locale->text('Drawing') . qq| : $form->{drawing}<br>|;
574 if ($form->{microfiche}) {
575 $callback .= "µfiche=$form->{microfiche}";
576 $option .= $locale->text('Microfiche') . qq| : $form->{microfiche}<br>|;
578 if ($form->{l_soldtotal}) {
579 $callback .= "&soldtotal=$form->{soldtotal}";
580 $option .= $locale->text('soldtotal') . qq| : $form->{soldtotal}<br>|;
583 my @columns = $form->sort_columns(
584 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)
587 if ($form->{l_linetotal}) {
588 $form->{l_onhand} = "Y";
589 $form->{l_linetotalsellprice} = "Y" if $form->{l_sellprice};
590 if ($form->{l_lastcost}) {
591 $form->{l_linetotallastcost} = "Y";
592 if (($form->{searchitems} eq 'assembly') && !$form->{bom}) {
593 $form->{l_linetotallastcost} = "";
596 $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
599 if ($form->{searchitems} eq 'service') {
601 # remove bin, weight and rop from list
602 map { $form->{"l_$_"} = "" } qw(bin weight rop);
604 $form->{l_onhand} = "";
606 # qty is irrelevant unless bought or sold
612 || $form->{quoted}) {
613 $form->{l_onhand} = "Y";
615 $form->{l_linetotalsellprice} = "";
616 $form->{l_linetotallastcost} = "";
620 foreach my $item (@columns) {
621 if ($form->{"l_$item"} eq "Y") {
622 push @column_index, $item;
624 # add column to callback
625 $callback .= "&l_$item=Y";
629 if ($form->{l_subtotal} eq 'Y') {
630 $callback .= "&l_subtotal=Y";
633 $column_header{number} =
634 qq|<th class=listheading nowrap>| . $locale->text('number') . qq|</th>|;
635 $column_header{partnumber} =
636 qq|<th nowrap><a class=listheading href=$callback&sort=partnumber&revers=$form->{revers}&lastsort=$form->{lastsort}>|
637 . $locale->text('Part Number')
639 $column_header{description} =
640 qq|<th nowrap><a class=listheading href=$callback&sort=description&revers=$form->{revers}&lastsort=$form->{lastsort}>|
641 . $locale->text('Part Description')
643 $column_header{partsgroup} =
644 qq|<th nowrap><a class=listheading href=$callback&sort=partsgroup>|
645 . $locale->text('Group')
647 $column_header{bin} =
648 qq|<th><a class=listheading href=$callback&sort=bin>|
649 . $locale->text('Bin')
651 $column_header{priceupdate} =
652 qq|<th nowrap><a class=listheading href=$callback&sort=priceupdate>|
653 . $locale->text('Updated')
655 $column_header{onhand} =
656 qq|<th nowrap><a class=listheading href=$callback&sort=onhand&revers=$form->{revers}&lastsort=$form->{lastsort}>|
657 . $locale->text('Qty')
659 $column_header{unit} =
660 qq|<th class=listheading nowrap>| . $locale->text('Unit') . qq|</th>|;
661 $column_header{listprice} =
662 qq|<th class=listheading nowrap>|
663 . $locale->text('List Price')
665 $column_header{lastcost} =
666 qq|<th class=listheading nowrap>| . $locale->text('Last Cost') . qq|</th>|;
667 $column_header{rop} =
668 qq|<th class=listheading nowrap>| . $locale->text('ROP') . qq|</th>|;
669 $column_header{weight} =
670 qq|<th class=listheading nowrap>| . $locale->text('Weight') . qq|</th>|;
672 $column_header{invnumber} =
673 qq|<th nowrap><a class=listheading href=$callback&sort=invnumber>|
674 . $locale->text('Invoice Number')
676 $column_header{ordnumber} =
677 qq|<th nowrap><a class=listheading href=$callback&sort=ordnumber>|
678 . $locale->text('Order Number')
680 $column_header{quonumber} =
681 qq|<th nowrap><a class=listheading href=$callback&sort=quonumber>|
682 . $locale->text('Quotation')
685 $column_header{name} =
686 qq|<th nowrap><a class=listheading href=$callback&sort=name>|
687 . $locale->text('Name')
690 $column_header{sellprice} =
691 qq|<th class=listheading nowrap>|
692 . $locale->text('Sell Price')
694 $column_header{linetotalsellprice} =
695 qq|<th class=listheading nowrap>| . $locale->text('Extended') . qq|</th>|;
696 $column_header{linetotallastcost} =
697 qq|<th class=listheading nowrap>| . $locale->text('Extended') . qq|</th>|;
698 $column_header{linetotallistprice} =
699 qq|<th class=listheading nowrap>| . $locale->text('Extended') . qq|</th>|;
701 $column_header{image} =
702 qq|<th class=listheading nowrap>| . $locale->text('Image') . qq|</a></th>|;
703 $column_header{drawing} =
704 qq|<th nowrap><a class=listheading href=$callback&sort=drawing>|
705 . $locale->text('Drawing')
707 $column_header{microfiche} =
708 qq|<th nowrap><a class=listheading href=$callback&sort=microfiche>|
709 . $locale->text('Microfiche')
712 $column_header{serialnumber} =
713 qq|<th nowrap><a class=listheading href=$callback&sort=serialnumber>|
714 . $locale->text('Serial Number')
716 $column_header{soldtotal} =
717 qq|<th nowrap><a class=listheading href=$callback&sort=soldtotal&revers=$form->{revers}&lastsort=$form->{lastsort}>|
718 . $locale->text('soldtotal')
722 my $colspan = $#column_index + 1;
729 <th class=listtop colspan=$colspan>$form->{title}</th>
733 <tr><td colspan=$colspan>$option</td></tr>
735 <tr class=listheading>
738 map { print "\n$column_header{$_}" } @column_index;
744 # add order to callback
745 $form->{callback} = $callback .= "&sort=$form->{sort}";
747 # escape callback for href
748 $callback = $form->escape($callback);
750 if (@{ $form->{parts} }) {
751 $sameitem = $form->{parts}->[0]->{ $form->{sort} };
754 # insert numbers for top100
756 foreach my $ref (@{ $form->{parts} }) {
761 # if avaible -> insert choice here
762 if (($form->{ndxs_counter}) > 0) {
763 for (my $i = 1; ($i < $form->{ndxs_counter} + 1); $i++) {
764 $partnumber = $form->{"totop100_partnumber_$i"};
765 $description = $form->{"totop100_description_$i"};
766 $unit = $form->{"totop100_unit_$i"};
767 $sellprice = $form->{"totop100_sellprice_$i"};
768 $soldtotal = $form->{"totop100_soldtotal_$i"};
771 <input type=hidden name=totop100_partnumber_$i value=$form->{"totop100_partnumber_$i"}>
772 <input type=hidden name=totop100_description_$i value=$form->{"totop100_description_$i"}>
773 <input type=hidden name=totop100_unit_$i value=$form->{"totop100_unit_$i"}>
774 <input type=hidden name=totop100_sellprice_$i value=$form->{"totop100_sellprice_$i"}>
775 <input type=hidden name=totop100_soldtotal_$i value=$form->{"totop100_soldtotal_$i"}>
779 push @{ $form->{parts} },
781 partnumber => "$partnumber",
782 description => "$description",
784 sellprice => "$sellprice",
785 soldtotal => "$soldtotal" };
788 # build data for columns
790 foreach my $ref (@{ $form->{parts} }) {
792 if ($form->{l_subtotal} eq 'Y' && !$ref->{assemblyitem}) {
793 if ($sameitem ne $ref->{ $form->{sort} }) {
794 parts_subtotal(\@column_index, \$subtotalonhand, \$subtotalsellprice, \$subtotallastcost, \$subtotallistprice);
795 $sameitem = $ref->{ $form->{sort} };
799 $ref->{exchangerate} = 1 unless $ref->{exchangerate};
800 $ref->{sellprice} *= $ref->{exchangerate};
801 $ref->{listprice} *= $ref->{exchangerate};
802 $ref->{lastcost} *= $ref->{exchangerate};
804 # use this for assemblies
805 $onhand = $ref->{onhand};
808 if ($ref->{assemblyitem}) {
810 $onhand = 0 if ($form->{sold});
813 $ref->{description} =~ s/\n/<br>/g;
815 $column_data{number} =
817 . $form->format_amount(\%myconfig, $ref->{number})
819 $column_data{partnumber} =
820 "<td align=$align>$ref->{partnumber} </a></td>";
821 $column_data{description} = "<td>$ref->{description} </td>";
822 $column_data{partsgroup} = "<td>$ref->{partsgroup} </td>";
824 $column_data{onhand} =
826 . $form->format_amount(\%myconfig, $ref->{onhand})
828 $column_data{sellprice} =
830 . $form->format_amount(\%myconfig, $ref->{sellprice})
832 $column_data{listprice} =
834 . $form->format_amount(\%myconfig, $ref->{listprice})
836 $column_data{lastcost} =
838 . $form->format_amount(\%myconfig, $ref->{lastcost})
841 $column_data{linetotalsellprice} = "<td align=right>"
842 . $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{sellprice}, 2)
844 $column_data{linetotallastcost} = "<td align=right>"
845 . $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{lastcost}, 2)
847 $column_data{linetotallistprice} = "<td align=right>"
848 . $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{listprice}, 2)
851 if (!$ref->{assemblyitem}) {
852 $totalsellprice += $onhand * $ref->{sellprice};
853 $totallastcost += $onhand * $ref->{lastcost};
854 $totallistprice += $onhand * $ref->{listprice};
856 $subtotalonhand += $onhand;
857 $subtotalsellprice += $onhand * $ref->{sellprice};
858 $subtotallastcost += $onhand * $ref->{lastcost};
859 $subtotallistprice += $onhand * $ref->{listprice};
864 . $form->format_amount(\%myconfig, $ref->{rop}) . "</td>";
865 $column_data{weight} =
867 . $form->format_amount(\%myconfig, $ref->{weight})
869 $column_data{unit} = "<td>$ref->{unit} </td>";
870 $column_data{bin} = "<td>$ref->{bin} </td>";
871 $column_data{priceupdate} = "<td>$ref->{priceupdate} </td>";
873 $column_data{invnumber} =
874 ($ref->{module} ne 'oe')
875 ? "<td><a href=$ref->{module}.pl?action=edit&type=invoice&id=$ref->{trans_id}&callback=$callback>$ref->{invnumber}</a></td>"
876 : "<td>$ref->{invnumber}</td>";
877 $column_data{ordnumber} =
878 ($ref->{module} eq 'oe')
879 ? "<td><a href=$ref->{module}.pl?action=edit&type=$ref->{type}&id=$ref->{trans_id}&callback=$callback>$ref->{ordnumber}</a></td>"
880 : "<td>$ref->{ordnumber}</td>";
881 $column_data{quonumber} =
882 ($ref->{module} eq 'oe' && !$ref->{ordnumber})
883 ? "<td><a href=$ref->{module}.pl?action=edit&type=$ref->{type}&id=$ref->{trans_id}&callback=$callback>$ref->{quonumber}</a></td>"
884 : "<td>$ref->{quonumber}</td>";
886 $column_data{name} = "<td>$ref->{name}</td>";
888 $column_data{image} =
890 ? "<td><a href=$ref->{image}><img src=$ref->{image} height=32 border=0></a></td>"
892 $column_data{drawing} =
894 ? "<td><a href=$ref->{drawing}>$ref->{drawing}</a></td>"
896 $column_data{microfiche} =
898 ? "<td><a href=$ref->{microfiche}>$ref->{microfiche}</a></td>"
901 $column_data{serialnumber} = "<td>$ref->{serialnumber}</td>";
903 $column_data{soldtotal} = "<td align=right>$ref->{soldtotal}</td>";
907 print "<tr class=listrow$i>";
909 map { print "\n$column_data{$_}" } @column_index;
916 if ($form->{l_subtotal} eq 'Y') {
917 parts_subtotal(\@column_index, \$subtotalonhand, \$subtotalsellprice, \$subtotallastcost, \$subtotallistprice);
920 if ($form->{"l_linetotal"}) {
921 map { $column_data{$_} = "<td> </td>" } @column_index;
922 $column_data{linetotalsellprice} =
923 "<th class=listtotal align=right>"
924 . $form->format_amount(\%myconfig, $totalsellprice, 2)
926 $column_data{linetotallastcost} =
927 "<th class=listtotal align=right>"
928 . $form->format_amount(\%myconfig, $totallastcost, 2)
930 $column_data{linetotallistprice} =
931 "<th class=listtotal align=right>"
932 . $form->format_amount(\%myconfig, $totallistprice, 2)
935 print "<tr class=listtotal>";
937 map { print "\n$column_data{$_}" } @column_index;
944 <tr><td colspan=$colspan><hr size=3 noshade></td></tr>
953 <form method=post action=$form->{script}>
955 <input type=hidden name=itemstatus value="$form->{itemstatus}">
956 <input type=hidden name=l_linetotal value="$form->{l_linetotal}">
957 <input type=hidden name=l_partnumber value="$form->{l_partnumber}">
958 <input type=hidden name=l_description value="$form->{l_description}">
959 <input type=hidden name=l_onhand value="$form->{l_onhand}">
960 <input type=hidden name=l_unit value="$form->{l_unit}">
961 <input type=hidden name=l_sellprice value="$form->{l_sellprice}">
962 <input type=hidden name=l_linetotalsellprice value="$form->{l_linetotalsellprice}">
963 <input type=hidden name=sort value="$form->{sort}">
964 <input type=hidden name=revers value="$form->{revers}">
965 <input type=hidden name=lastsort value="$form->{lastsort}">
966 <input type=hidden name=parts value="$form->{parts}">
968 <input type=hidden name=bom value="$form->{bom}">
969 <input type=hidden name=titel value="$form->{titel}">
970 <input type=hidden name=searchitems value="$form->{searchitems}">|;
975 <!-- <input type=hidden name=ndxs_counter value="$form->{ndxs_counter}">-->
977 <input class=submit type=submit name=action value="|
978 . $locale->text('choice') . qq|">
986 $lxdebug->leave_sub();
991 # Warning, deep magic ahead.
992 # This function parses the requested details, sanity checks them, and converts them into a format thats usable for IC->all_parts
994 # flags coming from the form:
996 # searchitems=part revers=0 lastsort=''
999 # partnumber ean description partsgroup serialnumber make model drawing microfiche
1000 # transdatefrom transdateto
1003 # itemstatus = active | onhand | short | obsolete | orphaned
1004 # action = continue | top100
1007 # bought sold onorder ordered rfq quoted
1008 # l_partnumber l_description l_serialnumber l_unit l_listprice l_sellprice l_lastcost
1009 # l_linetotal l_priceupdate l_bin l_rop l_weight l_image l_drawing l_microfiche
1010 # l_partsgroup l_subtotal l_soldtotal l_deliverydate
1013 # nextsub revers lastsort sort ndxs_counter
1015 sub generate_report {
1016 $lxdebug->enter_sub();
1018 $auth->assert('part_service_assembly_edit');
1020 my ($revers, $lastsort, $description);
1022 my $cvar_configs = CVar->get_configs('module' => 'IC');
1024 $form->{title} = (ucfirst $form->{searchitems}) . "s";
1025 $form->{title} =~ s/ys$/ies/;
1026 $form->{title} = $locale->text($form->{title});
1029 'bin' => { 'text' => $locale->text('Bin'), },
1030 'deliverydate' => { 'text' => $locale->text('deliverydate'), },
1031 'description' => { 'text' => $locale->text('Part Description'), },
1032 'drawing' => { 'text' => $locale->text('Drawing'), },
1033 'image' => { 'text' => $locale->text('Image'), },
1034 'invnumber' => { 'text' => $locale->text('Invoice Number'), },
1035 'lastcost' => { 'text' => $locale->text('Last Cost'), },
1036 'linetotallastcost' => { 'text' => $locale->text('Extended'), },
1037 'linetotallistprice' => { 'text' => $locale->text('Extended'), },
1038 'linetotalsellprice' => { 'text' => $locale->text('Extended'), },
1039 'listprice' => { 'text' => $locale->text('List Price'), },
1040 'microfiche' => { 'text' => $locale->text('Microfiche'), },
1041 'name' => { 'text' => $locale->text('Name'), },
1042 'onhand' => { 'text' => $locale->text('Qty'), },
1043 'ordnumber' => { 'text' => $locale->text('Order Number'), },
1044 'partnumber' => { 'text' => $locale->text('Part Number'), },
1045 'partsgroup' => { 'text' => $locale->text('Group'), },
1046 'priceupdate' => { 'text' => $locale->text('Updated'), },
1047 'quonumber' => { 'text' => $locale->text('Quotation'), },
1048 'rop' => { 'text' => $locale->text('ROP'), },
1049 'sellprice' => { 'text' => $locale->text('Sell Price'), },
1050 'serialnumber' => { 'text' => $locale->text('Serial Number'), },
1051 'soldtotal' => { 'text' => $locale->text('soldtotal'), },
1052 'transdate' => { 'text' => $locale->text('Transdate'), },
1053 'unit' => { 'text' => $locale->text('Unit'), },
1054 'weight' => { 'text' => $locale->text('Weight'), },
1057 $revers = $form->{revers};
1058 $lastsort = $form->{lastsort};
1060 # sorting and direction of sorting
1061 # ToDO: change this to the simpler field+direction method
1062 if (($form->{lastsort} eq "") && ($form->{sort} eq undef)) {
1063 $form->{revers} = 0;
1064 $form->{lastsort} = "partnumber";
1065 $form->{sort} = "partnumber";
1067 if ($form->{lastsort} eq $form->{sort}) {
1068 $form->{revers} = 1 - $form->{revers};
1070 $form->{revers} = 0;
1071 $form->{lastsort} = $form->{sort};
1075 # special case if we have a serialnumber limit search
1076 # serialnumbers are only given in invoices and orders,
1077 # so they can only pop up in bought, sold, rfq, and quoted stuff
1078 $form->{no_sn_joins} = 'Y' if ( !$form->{bought} && !$form->{sold}
1079 && !$form->{rfq} && !$form->{quoted}
1080 && ($form->{l_serialnumber} || $form->{serialnumber}));
1082 # special case for any checkbox of bought | sold | onorder | ordered | rfq | quoted.
1083 # if any of these are ticked the behavior changes slightly for lastcost
1084 # since all those are aggregation checks for the legder tables this is an internal switch
1085 # refered to as ledgerchecks
1086 $form->{ledgerchecks} = 'Y' if ( $form->{bought} || $form->{sold} || $form->{onorder}
1087 || $form->{ordered} || $form->{rfq} || $form->{quoted});
1089 # if something should be activated if something else is active, enter it here
1090 my %dependencies = (
1091 onhand => [ qw(l_onhand) ],
1092 short => [ qw(l_onhand) ],
1093 onorder => [ qw(l_ordnumber) ],
1094 ordered => [ qw(l_ordnumber) ],
1095 rfq => [ qw(l_quonumber) ],
1096 quoted => [ qw(l_quonumber) ],
1097 bought => [ qw(l_invnumber) ],
1098 sold => [ qw(l_invnumber) ],
1099 ledgerchecks => [ qw(l_name) ],
1100 serialnumber => [ qw(l_serialnumber) ],
1101 no_sn_joins => [ qw(bought sold) ],
1104 # these strings get displayed at the top of the results to indicate the user which switches were used
1106 active => $locale->text('Active'),
1107 obsolete => $locale->text('Obsolete'),
1108 orphaned => $locale->text('Orphaned'),
1109 onhand => $locale->text('On Hand'),
1110 short => $locale->text('Short'),
1111 onorder => $locale->text('On Order'),
1112 ordered => $locale->text('Ordered'),
1113 rfq => $locale->text('RFQ'),
1114 quoted => $locale->text('Quoted'),
1115 bought => $locale->text('Bought'),
1116 sold => $locale->text('Sold'),
1117 transdatefrom => $locale->text('From') . " " . $locale->date(\%myconfig, $form->{transdatefrom}, 1),
1118 transdateto => $locale->text('To (time)') . " " . $locale->date(\%myconfig, $form->{transdateto}, 1),
1119 partnumber => $locale->text('Part Number') . ": '$form->{partnumber}'",
1120 partsgroup => $locale->text('Group') . ": '$form->{partsgroup}'",
1121 serialnumber => $locale->text('Serial Number') . ": '$form->{serialnumber}'",
1122 description => $locale->text('Part Description') . ": '$form->{description}'",
1123 make => $locale->text('Make') . ": '$form->{make}'",
1124 model => $locale->text('Model') . ": '$form->{model}'",
1125 drawing => $locale->text('Drawing') . ": '$form->{drawing}'",
1126 microfiche => $locale->text('Microfiche') . ": '$form->{microfiche}'",
1127 l_soldtotal => $locale->text('soldtotal'),
1128 ean => $locale->text('EAN') . ": '$form->{ean}'",
1131 my @itemstatus_keys = qw(active obsolete orphaned onhand short);
1132 my @callback_keys = qw(onorder ordered rfq quoted bought sold partnumber partsgroup serialnumber description make model
1133 drawing microfiche l_soldtotal l_deliverydate transdatefrom transdateto ean);
1135 # calculate dependencies
1136 for (@itemstatus_keys, @callback_keys) {
1137 next if ($form->{itemstatus} ne $_ && !$form->{$_});
1138 map { $form->{$_} = 'Y' } @{ $dependencies{$_} } if $dependencies{$_};
1141 # generate callback and optionstrings
1143 for my $key (@itemstatus_keys, @callback_keys) {
1144 next if ($form->{itemstatus} ne $key && !$form->{$key});
1145 push @options, $optiontexts{$key};
1148 # special case for lastcost
1149 if ($form->{ledgerchecks}){
1150 # ledgerchecks don't know about sellprice or lastcost. they just return a
1151 # price. so rename sellprice to price, and drop lastcost.
1152 $column_defs{sellprice}{text} = $locale->text('Price');
1153 $form->{l_lastcost} = ""
1156 if ($form->{description}) {
1157 $description = $form->{description};
1158 $description =~ s/\n/<br>/g;
1161 if ($form->{l_linetotal}) {
1162 $form->{l_onhand} = "Y";
1163 $form->{l_linetotalsellprice} = "Y" if $form->{l_sellprice};
1164 $form->{l_linetotallastcost} = $form->{searchitems} eq 'assembly' && !$form->{bom} ? "" : 'Y' if $form->{l_lastcost};
1165 $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
1168 if ($form->{searchitems} eq 'service') {
1170 # remove bin, weight and rop from list
1171 map { $form->{"l_$_"} = "" } qw(bin weight rop);
1173 $form->{l_onhand} = "";
1175 # qty is irrelevant unless bought or sold
1176 if ( $form->{bought}
1181 || $form->{quoted}) {
1182 $form->{l_onhand} = "Y";
1184 $form->{l_linetotalsellprice} = "";
1185 $form->{l_linetotallastcost} = "";
1189 IC->all_parts(\%myconfig, \%$form);
1192 partnumber description partsgroup bin onhand rop unit listprice
1193 linetotallistprice sellprice linetotalsellprice lastcost linetotallastcost
1194 priceupdate weight image drawing microfiche invnumber ordnumber quonumber
1195 transdate name serialnumber soldtotal deliverydate ean
1198 my @includeable_custom_variables = grep { $_->{includeable} } @{ $cvar_configs };
1199 my @searchable_custom_variables = grep { $_->{searchable} } @{ $cvar_configs };
1200 my %column_defs_cvars = map { +"cvar_$_->{name}" => { 'text' => $_->{description} } } @includeable_custom_variables;
1202 push @columns, map { "cvar_$_->{name}" } @includeable_custom_variables;
1204 %column_defs = (%column_defs,%column_defs_cvars); # nochmal die cvars als überschrift hinzufügen
1205 map { $column_defs{$_}->{visible} = $form->{"l_$_"} ? 1 : 0 } @columns;
1206 map { $column_defs{$_}->{align} = 'right' } qw(onhand sellprice listprice lastcost linetotalsellprice linetotallastcost linetotallistprice rop weight soldtotal);
1208 my @hidden_variables = (qw(l_subtotal l_linetotal searchitems itemstatus bom), @itemstatus_keys, @callback_keys, @searchable_custom_variables, map { "l_$_" } @columns);
1209 my $callback = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
1211 my @sort_full = qw(partnumber description onhand soldtotal deliverydate);
1212 my @sort_no_revers = qw(partsgroup bin priceupdate invnumber ordnumber quonumber name image drawing serialnumber);
1214 foreach my $col (@sort_full) {
1215 $column_defs{$col}->{link} = join '&', $callback, "sort=$col", map { "$_=" . E($form->{$_}) } qw(revers lastsort);
1217 map { $column_defs{$_}->{link} = "${callback}&sort=$_" } @sort_no_revers;
1219 # add order to callback
1220 $form->{callback} = join '&', ($callback, map { "${_}=" . E($form->{$_}) } qw(sort revers));
1222 my $report = SL::ReportGenerator->new(\%myconfig, $form);
1224 my %attachment_basenames = (
1225 'part' => $locale->text('part_list'),
1226 'service' => $locale->text('service_list'),
1227 'assembly' => $locale->text('assembly_list'),
1230 $report->set_options('top_info_text' => $locale->text('Options') . ': ' . join(', ', grep $_, @options),
1231 'raw_bottom_info_text' => $form->parse_html_template('ic/generate_report_bottom'),
1232 'output_format' => 'HTML',
1233 'title' => $form->{title},
1234 'attachment_basename' => $attachment_basenames{$form->{searchitems}} . strftime('_%Y%m%d', localtime time),
1236 $report->set_options_from_form();
1238 $report->set_columns(%column_defs);
1239 $report->set_column_order(@columns);
1241 $report->set_export_options('generate_report', @hidden_variables, qw(sort revers));
1243 $report->set_sort_indicator($form->{sort}, $form->{revers} ? 0 : 1);
1245 CVar->add_custom_variables_to_report('module' => 'IC',
1246 'trans_id_field' => 'id',
1247 'configs' => $cvar_configs,
1248 'column_defs' => \%column_defs,
1249 'data' => $form->{parts});
1251 CVar->add_custom_variables_to_report('module' => 'IC',
1252 'sub_module' => sub { $_[0]->{ioi} },
1253 'trans_id_field' => 'ioi_id',
1254 'configs' => $cvar_configs,
1255 'column_defs' => \%column_defs,
1256 'data' => $form->{parts});
1258 my @subtotal_columns = qw(sellprice listprice lastcost);
1259 my %subtotals = map { $_ => 0 } ('onhand', @subtotal_columns);
1260 my %totals = map { $_ => 0 } @subtotal_columns;
1262 my $same_item = $form->{parts}[0]{ $form->{sort} } if (scalar @{ $form->{parts} });
1264 my $defaults = AM->get_defaults();
1267 foreach my $ref (@{ $form->{parts} }) {
1269 # fresh row, for inserting later
1270 my $row = { map { $_ => { 'data' => $ref->{$_} } } @columns };
1272 $ref->{exchangerate} ||= 1;
1273 $ref->{price_factor} ||= 1;
1274 $ref->{sellprice} *= $ref->{exchangerate} / $ref->{price_factor};
1275 $ref->{listprice} *= $ref->{exchangerate} / $ref->{price_factor};
1276 $ref->{lastcost} *= $ref->{exchangerate} / $ref->{price_factor};
1278 # use this for assemblies
1279 my $onhand = $ref->{onhand};
1281 if ($ref->{assemblyitem}) {
1282 $row->{partnumber}{align} = 'right';
1283 $row->{onhand}{data} = 0;
1284 $onhand = 0 if ($form->{sold});
1287 my $edit_link = build_std_url('action=edit', 'id=' . E($ref->{id}), 'callback');
1288 $row->{partnumber}->{link} = $edit_link;
1289 $row->{description}->{link} = $edit_link;
1291 foreach (qw(sellprice listprice lastcost)) {
1292 $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{$_}, -2);
1293 $row->{"linetotal$_"}{data} = $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{$_}, 2);
1296 map { $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{$_}); } qw(onhand rop weight soldtotal);
1298 $row->{weight}->{data} .= ' ' . $defaults->{weightunit};
1300 if (!$ref->{assemblyitem}) {
1301 foreach my $col (@subtotal_columns) {
1302 $totals{$col} += $onhand * $ref->{$col};
1303 $subtotals{$col} += $onhand * $ref->{$col};
1306 $subtotals{onhand} += $onhand;
1310 if ($ref->{module} eq 'oe') {
1311 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');
1312 $row->{ordnumber}{link} = $edit_oe_link;
1313 $row->{quonumber}{link} = $edit_oe_link if (!$ref->{ordnumber});
1316 $row->{invnumber}{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'type=invoice', 'id=' . E($ref->{trans_id}), 'callback');
1319 # set properties of images
1320 if ($ref->{image} && (lc $report->{options}->{output_format} eq 'html')) {
1321 $row->{image}{data} = '';
1322 $row->{image}{raw_data} = '<a href="' . H($ref->{image}) . '"><img src="' . H($ref->{image}) . '" height="32" border="0"></a>';
1324 map { $row->{$_}{link} = $ref->{$_} } qw(drawing microfiche);
1326 $report->add_data($row);
1328 my $next_ref = $form->{parts}[$idx + 1];
1330 # insert subtotal rows
1331 if (($form->{l_subtotal} eq 'Y') &&
1333 (!$next_ref->{assemblyitem} && ($same_item ne $next_ref->{ $form->{sort} })))) {
1334 my $row = { map { $_ => { 'class' => 'listsubtotal', } } @columns };
1336 if (($form->{searchitems} ne 'assembly') || !$form->{bom}) {
1337 $row->{onhand}->{data} = $form->format_amount(\%myconfig, $subtotals{onhand});
1340 map { $row->{"linetotal$_"}->{data} = $form->format_amount(\%myconfig, $subtotals{$_}, 2) } @subtotal_columns;
1341 map { $subtotals{$_} = 0 } ('onhand', @subtotal_columns);
1343 $report->add_data($row);
1345 $same_item = $next_ref->{ $form->{sort} };
1351 if ($form->{"l_linetotal"}) {
1352 my $row = { map { $_ => { 'class' => 'listtotal', } } @columns };
1354 map { $row->{"linetotal$_"}->{data} = $form->format_amount(\%myconfig, $totals{$_}, 2) } @subtotal_columns;
1356 $report->add_separator();
1357 $report->add_data($row);
1360 $report->generate_with_headers();
1362 $lxdebug->leave_sub();
1363 } #end generate_report
1365 sub parts_subtotal {
1366 $lxdebug->enter_sub();
1368 $auth->assert('part_service_assembly_edit');
1371 my ($column_index, $subtotalonhand, $subtotalsellprice, $subtotallastcost, $subtotallistprice) = @_;
1373 map { $column_data{$_} = "<td> </td>" } @{ $column_index };
1374 $$subtotalonhand = 0 if ($form->{searchitems} eq 'assembly' && $form->{bom});
1376 $column_data{onhand} =
1377 "<th class=listsubtotal align=right>"
1378 . $form->format_amount(\%myconfig, $$subtotalonhand)
1381 $column_data{linetotalsellprice} =
1382 "<th class=listsubtotal align=right>"
1383 . $form->format_amount(\%myconfig, $$subtotalsellprice, 2)
1385 $column_data{linetotallistprice} =
1386 "<th class=listsubtotal align=right>"
1387 . $form->format_amount(\%myconfig, $$subtotallistprice, 2)
1389 $column_data{linetotallastcost} =
1390 "<th class=listsubtotal align=right>"
1391 . $form->format_amount(\%myconfig, $$subtotallastcost, 2)
1394 $$subtotalonhand = 0;
1395 $$subtotalsellprice = 0;
1396 $$subtotallistprice = 0;
1397 $$subtotallastcost = 0;
1399 print "<tr class=listsubtotal>";
1401 map { print "\n$column_data{$_}" } @{ $column_index };
1407 $lxdebug->leave_sub();
1411 $lxdebug->enter_sub();
1413 $auth->assert('part_service_assembly_edit');
1415 # show history button
1416 $form->{javascript} = qq|<script type="text/javascript" src="js/show_history.js"></script>|;
1417 #/show hhistory button
1418 IC->get_part(\%myconfig, \%$form);
1420 $form->{"original_partnumber"} = $form->{"partnumber"};
1422 $form->{title} = $locale->text('Edit' . ucfirst $form->{item});
1427 $lxdebug->leave_sub();
1431 $lxdebug->enter_sub();
1433 $auth->assert('part_service_assembly_edit');
1435 IC->create_links("IC", \%myconfig, \%$form);
1438 map({ $form->{selectcurrency} .= "<option>$_\n" }
1439 split(/:/, $form->{currencies}));
1441 # parts and assemblies have the same links
1442 my $item = $form->{item};
1443 if ($form->{item} eq 'assembly') {
1447 # build the popup menus
1448 $form->{taxaccounts} = "";
1449 foreach my $key (keys %{ $form->{IC_links} }) {
1450 foreach my $ref (@{ $form->{IC_links}{$key} }) {
1452 # if this is a tax field
1453 if ($key =~ /IC_tax/) {
1454 if ($key =~ /\Q$item\E/) {
1455 $form->{taxaccounts} .= "$ref->{accno} ";
1456 $form->{"IC_tax_$ref->{accno}_description"} =
1457 "$ref->{accno}--$ref->{description}";
1460 if ($form->{amount}{ $ref->{accno} }) {
1461 $form->{"IC_tax_$ref->{accno}"} = "checked";
1464 $form->{"IC_tax_$ref->{accno}"} = "checked";
1469 $form->{"select$key"} .=
1470 "<option $ref->{selected}>$ref->{accno}--$ref->{description}\n";
1471 if ($form->{amount}{$key} eq $ref->{accno}) {
1472 $form->{$key} = "$ref->{accno}--$ref->{description}";
1478 chop $form->{taxaccounts};
1480 if (($form->{item} eq "part") || ($form->{item} eq "assembly")) {
1481 $form->{selectIC_income} = $form->{selectIC_sale};
1482 $form->{selectIC_expense} = $form->{selectIC_cogs};
1483 $form->{IC_income} = $form->{IC_sale};
1484 $form->{IC_expense} = $form->{IC_cogs};
1487 delete $form->{IC_links};
1488 delete $form->{amount};
1490 $form->get_partsgroup(\%myconfig, { all => 1 });
1492 $form->{partsgroup} = "$form->{partsgroup}--$form->{partsgroup_id}";
1494 if (@{ $form->{all_partsgroup} }) {
1495 $form->{selectpartsgroup} = qq|<option>\n|;
1496 map { $form->{selectpartsgroup} .= qq|<option value="$_->{partsgroup}--$_->{id}">$_->{partsgroup}\n| } @{ $form->{all_partsgroup} };
1499 if ($form->{item} eq 'assembly') {
1501 foreach my $i (1 .. $form->{assembly_rows}) {
1502 if ($form->{"partsgroup_id_$i"}) {
1503 $form->{"partsgroup_$i"} =
1504 qq|$form->{"partsgroup_$i"}--$form->{"partsgroup_id_$i"}|;
1507 $form->get_partsgroup(\%myconfig);
1509 if (@{ $form->{all_partsgroup} }) {
1510 $form->{selectassemblypartsgroup} = qq|<option>\n|;
1513 $form->{selectassemblypartsgroup} .=
1514 qq|<option value="$_->{partsgroup}--$_->{id}">$_->{partsgroup}\n|
1515 } @{ $form->{all_partsgroup} };
1518 $lxdebug->leave_sub();
1522 $lxdebug->enter_sub();
1524 $auth->assert('part_service_assembly_edit');
1526 $form->{eur} = $main::eur; # config dumps into namespace - yuck
1527 $form->{pg_keys} = sub { "$_[0]->{partsgroup}--$_[0]->{id}" };
1528 $form->{description_area} = ($form->{rows} = $form->numtextrows($form->{description}, 40)) > 1;
1529 $form->{notes_rows} = max 4, $form->numtextrows($form->{notes}, 40), $form->numtextrows($form->{formel}, 40);
1531 map { $form->{"is_$_"} = ($form->{item} eq $_) } qw(part service assembly);
1532 map { $form->{$_} =~ s/"/"/g; } qw(unit);
1534 $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS',
1535 'partsgroup' => 'all_partsgroup',
1536 'vendors' => 'ALL_VENDORS',);
1539 IC->retrieve_buchungsgruppen(\%myconfig, $form);
1540 @{ $form->{BUCHUNGSGRUPPEN} } = grep { $_->{id} eq $form->{buchungsgruppen_id} || ($form->{id} && $form->{orphaned}) || !$form->{id} } @{ $form->{BUCHUNGSGRUPPEN} };
1542 # use JavaScript Calendar or not (yes!)
1543 $form->{jsscript} = 1;
1545 my $units = AM->retrieve_units(\%myconfig, $form);
1546 $form->{ALL_UNITS} = [ map +{ name => $_ }, sort { $units->{$a}{sortkey} <=> $units->{$b}{sortkey} } keys %$units ];
1548 $form->{defaults} = AM->get_defaults();
1550 $form->{fokus} = "ic.partnumber";
1552 $form->{CUSTOM_VARIABLES} = CVar->get_custom_variables('module' => 'IC', 'trans_id' => $form->{id});
1554 CVar->render_inputs('variables' => $form->{CUSTOM_VARIABLES}, show_disabled_message => 1)
1555 if (scalar @{ $form->{CUSTOM_VARIABLES} });
1558 #print $form->parse_html_template('ic/form_header', { ALL_PRICE_FACTORS => $form->{ALL_PRICE_FACTORS},
1559 # ALL_UNITS => $form->{ALL_UNITS},
1560 # BUCHUNGSGRUPPEN => $form->{BUCHUNGSGRUPPEN},
1561 # payment_terms => $form->{payment_terms},
1562 # all_partsgroup => $form->{all_partsgroup}});
1563 print $form->parse_html_template('ic/form_header');
1564 $lxdebug->leave_sub();
1568 $lxdebug->enter_sub();
1570 $auth->assert('part_service_assembly_edit');
1572 print $form->parse_html_template('ic/form_footer');
1574 $lxdebug->leave_sub();
1578 $lxdebug->enter_sub();
1581 my @mm_data = grep { any { $_ ne '' } @$_{qw(make model)} } map +{ make => $form->{"make_$_"}, model => $form->{"model_$_"} }, 1 .. $numrows;
1582 delete @{$form}{grep { m/^make_\d+/ || m/^model_\d+/ } keys %{ $form }};
1583 print $form->parse_html_template('ic/makemodel', { MM_DATA => [ @mm_data, {} ], mm_rows => scalar @mm_data + 1 });
1585 $lxdebug->leave_sub();
1589 $lxdebug->enter_sub();
1592 my ($nochange, $callback, $previousform, $linetotal, $line_purchase_price, $href);
1594 @column_index = qw(runningnumber qty unit bom partnumber description partsgroup lastcost total);
1596 if ($form->{previousform}) {
1598 @column_index = qw(qty unit bom partnumber description partsgroup total);
1602 $form->{old_callback} = $form->{callback};
1603 $callback = $form->{callback};
1604 $form->{callback} = "$form->{script}?action=display_form";
1607 map { delete $form->{$_} } qw(action header);
1609 # save form variables in a previousform variable
1610 $previousform = $form->escape($form->escape(join '&', map {
1611 sprintf "%s=%s", Q($_), /^listprice|lastcost|sellprice$/ ? $form->format_amount(\%myconfig, $form->{$_}) : $form->{$_}
1612 } grep { ref $form->{$_} eq '' && $form->{$_} } grep { !/^select/ } sort keys %$form ));
1614 $form->{callback} = $callback;
1615 $form->{assemblytotal} = 0;
1616 $form->{assembly_purchase_price_total} = 0;
1617 $form->{weight} = 0;
1621 runningnumber => { text => $locale->text('No.'), nowrap => 1, width => '5%' },
1622 qty => { text => $locale->text('Qty'), nowrap => 1, width => '10%' },
1623 unit => { text => $locale->text('Unit'), nowrap => 1, width => '5%' },
1624 partnumber => { text => $locale->text('Part Number'), nowrap => 1, width => '20%' },
1625 description => { text => $locale->text('Part Description'), nowrap => 1, width => '50%' },
1626 lastcost => { text => $locale->text('Purchase Prices'), nowrap => 1, width => '50%' },
1627 total => { text => $locale->text('Sale Prices'), nowrap => 1, },
1628 bom => { text => $locale->text('BOM'), },
1629 partsgroup => { text => $locale->text('Group'), },
1634 for my $i (1 .. $numrows) {
1635 my (%row, @row_hiddens);
1637 $form->{"partnumber_$i"} =~ s/\"/"/g;
1639 $linetotal = $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"} / ($form->{"price_factor_$i"} || 1), 4);
1640 $line_purchase_price = $form->round_amount($form->{"lastcost_$i"} * $form->{"qty_$i"} / ($form->{"price_factor_$i"} || 1), 4);
1641 $form->{assemblytotal} += $linetotal;
1642 $form->{assembly_purchase_price_total} += $line_purchase_price;
1643 $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
1644 $linetotal = $form->format_amount(\%myconfig, $linetotal, 2);
1645 $line_purchase_price = $form->format_amount(\%myconfig, $line_purchase_price, 2);
1646 $href = qq|$form->{script}?action=edit&id=$form->{"id_$i"}&rowcount=$i&previousform=$previousform|;
1647 map { $row{$_}{data} = "" } qw(qty unit partnumber description bom partsgroup runningnumber);
1650 if (($i >= 1) && ($i == $numrows)) {
1651 if (!$form->{previousform}) {
1652 $row{partnumber}{data} = qq|<input name="partnumber_$i" size=15 value="$form->{"partnumber_$i"}">|;
1653 $row{qty}{data} = qq|<input name="qty_$i" size=5 value="$form->{"qty_$i"}">|;
1654 $row{description}{data} = qq|<input name="description_$i" size=40 value="$form->{"description_$i"}">|;
1655 $row{partsgroup}{data} = qq|<input name="partsgroup_$i" size=10 value="$form->{"partsgroup_$i"}">|;
1659 if ($form->{previousform}) {
1660 push @row_hiddens, qw(qty bom);
1661 $row{partnumber}{data} = $form->{"partnumber_$i"};
1662 $row{qty}{data} = $form->{"qty_$i"};
1663 $row{bom}{data} = $form->{"bom_$i"} ? "x" : " ";
1664 $row{qty}{align} = 'right';
1666 $row{partnumber}{data} = qq|<a href=$href>$form->{"partnumber_$i"}</a>|;
1667 $row{qty}{data} = qq|<input name="qty_$i" size=5 value="$form->{"qty_$i"}">|;
1668 $row{runningnumber}{data} = qq|<input name="runningnumber_$i" size=3 value="$i">|;
1669 $row{bom}{data} = sprintf qq|<input name="bom_$i" type=checkbox class=checkbox value=1 %s>|,
1670 $form->{"bom_$i"} ? 'checked' : '';
1672 push @row_hiddens, qw(unit description partnumber partsgroup);
1673 $row{unit}{data} = $form->{"unit_$i"};
1674 $row{description}{data} = $form->{"description_$i"};
1675 $row{partsgroup}{data} = $form->{"partsgroup_$i"};
1676 $row{bom}{align} = 'center';
1679 $row{lastcost}{data} = $line_purchase_price;
1680 $row{total}{data} = $linetotal;
1681 $row{lastcost}{align} = 'right';
1682 $row{total}{align} = 'right';
1683 $row{deliverydate}{align} = 'right';
1685 push @row_hiddens, qw(id sellprice lastcost weight price_factor_id price_factor);
1686 $row{hiddens} = [ map +{ name => "${_}_$i", value => $form->{"${_}_$i"} }, @row_hiddens ];
1691 print $form->parse_html_template('ic/assembly_row', { COLUMNS => \@column_index, ROWS => \@ROWS, HEADER => \%header });
1693 $lxdebug->leave_sub();
1697 $lxdebug->enter_sub();
1699 # parse pricegroups. and no, don't rely on check_form for this...
1700 map { $form->{"price_$_"} = $form->parse_amount(\%myconfig, $form->{"price_$_"}) } 1 .. $form->{price_rows};
1702 if ($form->{item} eq "assembly") {
1703 my $i = $form->{assembly_rows};
1705 # if last row is empty check the form otherwise retrieve item
1706 if ( ($form->{"partnumber_$i"} eq "")
1707 && ($form->{"description_$i"} eq "")
1708 && ($form->{"partsgroup_$i"} eq "")) {
1714 IC->assembly_item(\%myconfig, \%$form);
1716 my $rows = scalar @{ $form->{item_list} };
1719 $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
1722 $form->{makemodel_rows}--;
1726 map { $form->{item_list}[$i]{$_} =~ s/\"/"/g }
1727 qw(partnumber description unit partsgroup);
1728 map { $form->{"${_}_$i"} = $form->{item_list}[0]{$_} }
1729 keys %{ $form->{item_list}[0] };
1730 $form->{"runningnumber_$i"} = $form->{assembly_rows};
1731 $form->{assembly_rows}++;
1739 $form->{rowcount} = $i;
1740 $form->{assembly_rows}++;
1747 } elsif (($form->{item} eq 'part') || ($form->{item} eq 'service')) {
1751 $lxdebug->leave_sub();
1755 $lxdebug->enter_sub();
1757 $auth->assert('part_service_assembly_edit');
1759 my ($parts_id, %newform, $previousform, $amount, $callback);
1761 # check if there is a part number - commented out, cause there is an automatic allocation of numbers
1762 # $form->isblank("partnumber", $locale->text(ucfirst $form->{item}." Part Number missing!"));
1764 # check if there is a description
1765 $form->isblank("description", $locale->text("Part Description missing!"));
1767 $form->error($locale->text("Inventory quantity must be zero before you can set this $form->{item} obsolete!"))
1768 if $form->{obsolete} && $form->{onhand} * 1 && $form->{item} ne 'service';
1770 if (!$form->{buchungsgruppen_id}) {
1771 $form->error($locale->text("Parts must have an entry type.") . " " .
1772 $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.")
1776 $form->error($locale->text('Description must not be empty!')) unless $form->{description};
1777 $form->error($locale->text('Partnumber must not be set to empty!')) if $form->{id} && !$form->{partnumber};
1780 $lxdebug->message($LXDebug::DEBUG1, "ic.pl: sellprice in save = $form->{sellprice}\n");
1781 if (IC->save(\%myconfig, \%$form) == 3) {
1782 $form->error($locale->text('Partnumber not unique!'));
1784 # saving the history
1785 if(!exists $form->{addition}) {
1786 $form->{snumbers} = qq|partnumber_| . $form->{partnumber};
1787 $form->{addition} = "SAVED";
1788 $form->save_history;
1790 # /saving the history
1791 $parts_id = $form->{id};
1794 # load previous variables
1795 if ($form->{previousform}) {
1797 # save the new form variables before splitting previousform
1798 map { $newform{$_} = $form->{$_} } keys %$form;
1800 $previousform = $form->unescape($form->{previousform});
1802 # don't trample on previous variables
1803 map { delete $form->{$_} } keys %newform;
1805 my $ic_cvar_configs = CVar->get_configs(module => 'IC');
1806 my @ic_cvar_fields = map { "cvar_$_->{name}" } @{ $ic_cvar_configs };
1808 # now take it apart and restore original values
1809 foreach my $item (split /&/, $previousform) {
1810 my ($key, $value) = split m/=/, $item, 2;
1811 $value =~ s/%26/&/g;
1812 $form->{$key} = $value;
1814 $form->{taxaccounts} = $newform{taxaccount2};
1816 if ($form->{item} eq 'assembly') {
1818 # undo number formatting
1819 map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) }
1820 qw(weight listprice sellprice rop);
1822 $form->{assembly_rows}--;
1823 $i = $newform{rowcount};
1824 $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
1826 $form->{sellprice} -= $form->{"sellprice_$i"} * $form->{"qty_$i"};
1827 $form->{weight} -= $form->{"weight_$i"} * $form->{"qty_$i"};
1829 # change/add values for assembly item
1830 map { $form->{"${_}_$i"} = $newform{$_} } qw(partnumber description bin unit weight listprice sellprice inventory_accno income_accno expense_accno price_factor_id);
1831 map { $form->{"ic_${_}_$i"} = $newform{$_} } @ic_cvar_fields;
1833 # das ist __voll__ bekloppt, dass so auszurechnen jb 22.5.09
1834 #$form->{sellprice} += $form->{"sellprice_$i"} * $form->{"qty_$i"};
1835 $form->{weight} += $form->{"weight_$i"} * $form->{"qty_$i"};
1839 # set values for last invoice/order item
1840 $i = $form->{rowcount};
1841 $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
1843 map { $form->{"${_}_$i"} = $newform{$_} } qw(partnumber description bin unit listprice inventory_accno income_accno expense_accno sellprice lastcost price_factor_id);
1844 map { $form->{"ic_${_}_$i"} = $newform{$_} } @ic_cvar_fields;
1846 $form->{"longdescription_$i"} = $newform{notes};
1848 $form->{"sellprice_$i"} = $newform{lastcost} if ($form->{vendor_id});
1850 if ($form->{exchangerate} != 0) {
1851 $form->{"sellprice_$i"} /= $form->{exchangerate};
1854 $lxdebug->message($LXDebug::DEBUG1, qq|sellprice_$i in previousform 2 = | . $form->{"sellprice_$i"} . qq|\n|);
1856 map { $form->{"taxaccounts_$i"} .= "$_ " } split / /, $newform{taxaccount};
1857 chop $form->{"taxaccounts_$i"};
1858 foreach my $item (qw(description rate taxnumber)) {
1859 my $index = $form->{"taxaccounts_$i"} . "_$item";
1860 $form->{$index} = $newform{$index};
1863 # credit remaining calculation
1864 $amount = $form->{"sellprice_$i"} * (1 - $form->{"discount_$i"} / 100) * $form->{"qty_$i"};
1866 map { $form->{"${_}_base"} += $amount } (split / /, $form->{"taxaccounts_$i"});
1867 map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded};
1869 $form->{creditremaining} -= $amount;
1871 # redo number formatting, because invoice parse them!
1872 map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}) } qw(weight listprice sellprice lastcost rop);
1875 $form->{"id_$i"} = $parts_id;
1877 # Get the actual price factor (not just the ID) for the marge calculation.
1878 $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
1879 foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
1880 next if ($pfac->{id} != $newform{price_factor_id});
1881 $form->{"marge_price_factor_$i"} = $pfac->{factor};
1884 delete $form->{ALL_PRICE_FACTORS};
1886 delete $form->{action};
1888 # restore original callback
1889 $callback = $form->unescape($form->{callback});
1890 $form->{callback} = $form->unescape($form->{old_callback});
1891 delete $form->{old_callback};
1893 $form->{makemodel_rows}--;
1895 # put callback together
1896 foreach my $key (keys %$form) {
1898 # do single escape for Apache 2.0
1899 my $value = $form->escape($form->{$key}, 1);
1900 $callback .= qq|&$key=$value|;
1902 $form->{callback} = $callback;
1904 $lxdebug->message($LXDebug::DEBUG1, qq|ic.pl: sellprice_$i nach sub save = | . $form->{"sellprice_$i"} . qq|\n|);
1909 $lxdebug->leave_sub();
1913 $lxdebug->enter_sub();
1915 $auth->assert('part_service_assembly_edit');
1917 # saving the history
1918 if(!exists $form->{addition}) {
1919 $form->{snumbers} = qq|partnumber_| . $form->{partnumber};
1920 $form->{addition} = "SAVED AS NEW";
1921 $form->save_history;
1923 # /saving the history
1925 if ($form->{"original_partnumber"} &&
1926 ($form->{"partnumber"} eq $form->{"original_partnumber"})) {
1927 $form->{partnumber} = "";
1930 $lxdebug->leave_sub();
1934 $lxdebug->enter_sub();
1936 $auth->assert('part_service_assembly_edit');
1938 # saving the history
1939 if(!exists $form->{addition}) {
1940 $form->{snumbers} = qq|partnumber_| . $form->{partnumber};
1941 $form->{addition} = "DELETED";
1942 $form->save_history;
1944 # /saving the history
1945 my $rc = IC->delete(\%myconfig, \%$form);
1948 $form->redirect($locale->text('Item deleted!')) if ($rc > 0);
1949 $form->error($locale->text('Cannot delete item!'));
1951 $lxdebug->leave_sub();
1955 $lxdebug->enter_sub();
1957 $auth->assert('part_service_assembly_edit');
1962 pricegroup => $form->{"pricegroup_$_"},
1963 pricegroup_id => $form->{"pricegroup_id_$_"},
1964 price => $form->{"price_$_"},
1967 print $form->parse_html_template('ic/price_row', { PRICES => \@PRICES });
1969 $lxdebug->leave_sub();
1972 sub parts_language_selection {
1973 $lxdebug->enter_sub();
1975 $auth->assert('part_service_assembly_edit');
1977 my $languages = IC->retrieve_languages(\%myconfig, $form);
1979 if ($form->{language_values} ne "") {
1980 foreach my $item (split(/---\+\+\+---/, $form->{language_values})) {
1981 my ($language_id, $translation, $longdescription) = split(/--\+\+--/, $item);
1983 foreach my $language (@{ $languages }) {
1984 next unless ($language->{id} == $language_id);
1986 $language->{translation} = $translation;
1987 $language->{longdescription} = $longdescription;
1993 my @header_sort = qw(name longdescription);
1994 my %header_title = ( "name" => $locale->text("Name"),
1995 "longdescription" => $locale->text("Long Description"),
1999 map(+{ "column_title" => $header_title{$_},
2004 $form->{"title"} = $locale->text("Language Values");
2006 print $form->parse_html_template("ic/parts_language_selection", { "HEADER" => \@header,
2007 "LANGUAGES" => $languages, });
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"}); }