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);
38 use SL::ReportGenerator;
46 our ($form, $locale, %myconfig, $lxdebug);
48 require "bin/mozilla/io.pl";
49 require "bin/mozilla/invoice_io.pl";
50 require "bin/mozilla/common.pl";
51 require "bin/mozilla/reportgenerator.pl";
56 # type=submit $locale->text('Add Part')
57 # type=submit $locale->text('Add Service')
58 # type=submit $locale->text('Add Assembly')
59 # type=submit $locale->text('Edit Part')
60 # type=submit $locale->text('Edit Service')
61 # type=submit $locale->text('Edit Assembly')
62 # $locale->text('Parts')
63 # $locale->text('Services')
64 # $locale->text('Inventory quantity must be zero before you can set this part obsolete!')
65 # $locale->text('Inventory quantity must be zero before you can set this assembly obsolete!')
66 # $locale->text('Part Number missing!')
67 # $locale->text('Service Number missing!')
68 # $locale->text('Assembly Number missing!')
69 # $locale->text('ea');
74 $lxdebug->enter_sub();
76 $auth->assert('part_service_assembly_edit');
78 $form->{title} = $locale->text('Add ' . ucfirst $form->{item});
79 $form->{callback} = "$form->{script}?action=add&item=$form->{item}" unless $form->{callback};
80 $form->{unit_changeable} = 1;
82 IC->get_pricegroups(\%myconfig, \%$form);
86 $lxdebug->leave_sub();
90 $lxdebug->enter_sub();
92 $auth->assert('part_service_assembly_edit');
94 $form->{revers} = 0; # switch for backward sorting
95 $form->{lastsort} = ""; # memory for which table was sort at last time
96 $form->{ndxs_counter} = 0; # counter for added entries to top100
98 my $is_service = $form->{searchitems} eq 'service';
99 my $is_assembly = $form->{searchitems} eq 'assembly';
101 $form->{title} = (ucfirst $form->{searchitems}) . "s";
102 $form->{title} = $locale->text($form->{title});
103 $form->{title} = $locale->text('Assemblies') if $is_assembly;
105 $form->{jsscript} = 1;
109 print $form->parse_html_template('ic/search', { is_assembly => $is_assembly,
110 is_service => $is_service,
111 dateformat => $myconfig{dateformat}, });
113 $lxdebug->leave_sub();
116 sub search_update_prices {
117 $lxdebug->enter_sub();
119 $auth->assert('part_service_assembly_edit');
121 my $pricegroups = IC->get_pricegroups(\%myconfig, \%$form);
125 print $form->parse_html_template('ic/search_update_prices', { PRICE_ROWS => $pricegroups });
127 $lxdebug->leave_sub();
130 sub confirm_price_update {
131 $lxdebug->enter_sub();
133 $auth->assert('part_service_assembly_edit');
135 $form->{nextsub} = "update_prices";
138 map { delete $form->{$_} } qw(action header);
140 print $form->parse_html_template('ic/confirm_price_update', { HIDDENS => [ map { name => $_, value => $form->{$_} }, keys %$form ] });
142 $lxdebug->leave_sub();
146 $lxdebug->enter_sub();
148 $auth->assert('part_service_assembly_edit');
150 if (IC->update_prices(\%myconfig, \%$form)) {
151 $form->redirect($form->{update_count} . $locale->text('prices updated!'));
153 $form->error($locale->text('Could not update prices!'));
156 $lxdebug->leave_sub();
160 $lxdebug->enter_sub();
162 $auth->assert('part_service_assembly_edit');
167 $form->{title} = $locale->text('Top 100 hinzufuegen');
171 push @custom_hiddens, qw(searchitems title bom titel revers lastsort sort ndxs_counter extras);
172 push @custom_hiddens, qw(itemstatus l_linetotal l_partnumber l_description l_onhand l_unit l_sellprice l_linetotalsellprice);
174 +{ name => 'row', value => $j },
175 +{ name => 'nextsub', value => 'item_selected' },
176 +{ name => 'test', value => 'item_selected' },
177 +{ name => 'lastndx', value => $lastndx },
178 map(+{ name => $_, value => $form->{$_} }, @custom_hiddens),
181 my ($partnumber, $description, $unit, $sellprice, $soldtotal);
183 # if ($form->{ndx}) {
184 # for my $i (0 .. $form->{ndxs_counter}) {
186 # # insert data into top100
187 # push @{ $form->{parts} },
189 # partnumber => $form->{"totop100_partnumber_$j"},
190 # description => $form->{"totop100_description_$j"},
191 # unit => $form->{"totop100_unit_$j"},
192 # sellprice => $form->{"totop100_sellprice_$j"},
193 # soldtotal => $form->{"totop100_soldtotal_$j"},
200 # set data for next page
201 for my $i (1 .. $form->{ndxs_counter}) {
202 $partnumber = $form->{"totop100_partnumber_$i"};
203 $description = $form->{"totop100_description_$i"};
204 $unit = $form->{"totop100_unit_$i"};
205 $sellprice = $form->{"totop100_sellprice_$i"};
206 $soldtotal = $form->{"totop100_soldtotal_$i"};
209 totop100_partnumber => $form->{"totop100_partnumber_$i"},
210 totop100_description => $form->{"totop100_description_$i"},
211 totop100_unit => $form->{"totop100_unit_$i"},
212 totop100_sellprice => $form->{"totop100_sellprice_$i"},
213 totop100_soldtotal => $form->{"totop100_soldtotal_$i"},
217 #<input type=hidden name=totop100_partnumber_$i value=$form->{"totop100_partnumber_$i"}>
218 #<input type=hidden name=totop100_description_$i value=$form->{"totop100_description_$i"}>
219 #<input type=hidden name=totop100_unit_$i value=$form->{"totop100_unit_$i"}>
220 #<input type=hidden name=totop100_sellprice_$i value=$form->{"totop100_sellprice_$i"}>
221 #<input type=hidden name=totop100_soldtotal_$i value=$form->{"totop100_soldtotal_$i"}>
225 print $form->parse_html_template('ic/choice', +{ HIDDENS => \@HIDDENS, PARTS => \@PARTS });
227 $lxdebug->leave_sub();
231 $lxdebug->enter_sub();
233 $auth->assert('part_service_assembly_edit');
236 our ($partnumber, $description, $unit, $sellprice, $soldtotal);
238 my @sortorders = ("", "partnumber", "description", "all");
239 my $sortorder = $sortorders[($form->{description} ? 2 : 0) + ($form->{partnumber} ? 1 : 0)];
240 IC->get_parts(\%myconfig, \%$form, $sortorder);
242 $form->{title} = $locale->text('Top 100 hinzufuegen');
248 <form method=post action=ic.pl>
251 <th class=listtop colspan=6>| . $locale->text('choice part') . qq|</th>
254 <tr class=listheading>
256 <th class=listheading>| . $locale->text('Part Number') . qq|</th>
257 <th class=listheading>| . $locale->text('Part Description') . qq|</th>
258 <th class=listheading>| . $locale->text('Unit of measure') . qq|</th>
259 <th class=listheading>| . $locale->text('Sell Price') . qq|</th>
260 <th class=listheading>| . $locale->text('soldtotal') . qq|</th>
264 my $i = $form->{rows};
266 for ($j = 1; $j <= $i; $j++) {
269 <tr class=listrow| . ($j % 2) . qq|>|;
272 <td><input name=ndx class=radio type=radio value=$j checked></td>|;
275 <td><input name=ndx class=radio type=radio value=$j></td>|;
278 <td><input name="new_partnumber_$j" type=hidden value="$form->{"partnumber_$j"}">$form->{"partnumber_$j"}</td>
279 <td><input name="new_description_$j" type=hidden value="$form->{"description_$j"}">$form->{"description_$j"}</td>
280 <td><input name="new_unit_$j" type=hidden value="$form->{"unit_$j"}">$form->{"unit_$j"}</td>
281 <td><input name="new_sellprice_$j" type=hidden value="$form->{"sellprice_$j"}">$form->{"sellprice_$j"}</td>
282 <td><input name="new_soldtotal_$j" type=hidden value="$form->{"soldtotal_$j"}">$form->{"soldtotal_$j"}</td>
285 <input name="new_id_$j" type=hidden value="$form->{"id_$j"}">|;
295 <input type=hidden name=itemstatus value="$form->{itemstatus}">
296 <input type=hidden name=l_linetotal value="$form->{l_linetotal}">
297 <input type=hidden name=l_partnumber value="$form->{l_partnumber}">
298 <input type=hidden name=l_description value="$form->{l_description}">
299 <input type=hidden name=l_onhand value="$form->{l_onhand}">
300 <input type=hidden name=l_unit value="$form->{l_unit}">
301 <input type=hidden name=l_sellprice value="$form->{l_sellprice}">
302 <input type=hidden name=l_linetotalsellprice value="$form->{l_linetotalsellprice}">
303 <input type=hidden name=sort value="$form->{sort}">
304 <input type=hidden name=revers value="$form->{revers}">
305 <input type=hidden name=lastsort value="$form->{lastsort}">
307 <input type=hidden name=bom value="$form->{bom}">
308 <input type=hidden name=titel value="$form->{titel}">
309 <input type=hidden name=searchitems value="$form->{searchitems}">
311 <input type=hidden name=row value=$j>
313 <input type=hidden name=nextsub value=item_selected>
315 <input name=lastndx type=hidden value=$lastndx>
317 <input name=ndxs_counter type=hidden value=$form->{ndxs_counter}>|;
321 if (($form->{ndxs_counter}) > 0) {
322 for ($i = 1; ($i < $form->{ndxs_counter} + 1); $i++) {
324 $partnumber = $form->{"totop100_partnumber_$i"};
325 $description = $form->{"totop100_description_$i"};
326 $unit = $form->{"totop100_unit_$i"};
327 $sellprice = $form->{"totop100_sellprice_$i"};
328 $soldtotal = $form->{"totop100_soldtotal_$i"};
331 <input type=hidden name=totop100_partnumber_$i value=$form->{"totop100_partnumber_$i"}>
332 <input type=hidden name=totop100_description_$i value=$form->{"totop100_description_$i"}>
333 <input type=hidden name=totop100_unit_$i value=$form->{"totop100_unit_$i"}>
334 <input type=hidden name=totop100_sellprice_$i value=$form->{"totop100_sellprice_$i"}>
335 <input type=hidden name=totop100_soldtotal_$i value=$form->{"totop100_soldtotal_$i"}>
343 <input class=submit type=submit name=action value="|
344 . $locale->text('TOP100') . qq|">
350 $lxdebug->leave_sub();
354 $lxdebug->enter_sub();
356 $auth->assert('part_service_assembly_edit');
359 $form->{ndxs_counter}++;
361 if ($form->{ndxs_counter} > 0) {
363 my $index = $form->{ndx};
365 $form->{"totop100_partnumber_$form->{ndxs_counter}"} = $form->{"new_partnumber_$index"};
366 $form->{"totop100_description_$form->{ndxs_counter}"} = $form->{"new_description_$index"};
367 $form->{"totop100_unit_$form->{ndxs_counter}"} = $form->{"new_unit_$index"};
368 $form->{"totop100_sellprice_$form->{ndxs_counter}"} = $form->{"new_sellprice_$index"};
369 $form->{"totop100_soldtotal_$form->{ndxs_counter}"} = $form->{"new_soldtotal_$index"};
373 $lxdebug->leave_sub();
377 $lxdebug->enter_sub();
379 $auth->assert('part_service_assembly_edit');
381 my ($revers, $lastsort, $callback, $option, $description, $sameitem,
382 $partnumber, $unit, $sellprice, $soldtotal, $totop100, $onhand, $align);
383 my (@column_index, %column_header, %column_data);
384 my ($totalsellprice, $totallastcost, $totallistprice, $subtotalonhand, $subtotalsellprice, $subtotallastcost, $subtotallistprice);
386 $form->{top100} = "top100";
387 $form->{l_soldtotal} = "Y";
388 $form->{soldtotal} = "soldtotal";
389 $form->{sort} = "soldtotal";
390 $form->{l_qty} = "N";
391 $form->{l_linetotal} = "";
393 $form->{number} = "position";
394 $form->{l_number} = "Y";
398 $form->{title} = $locale->text('Top 100');
400 $revers = $form->{revers};
401 $lastsort = $form->{lastsort};
403 if (($form->{lastsort} eq "") && ($form->{sort} eq undef)) {
405 $form->{lastsort} = "partnumber";
406 $form->{sort} = "partnumber";
410 "$form->{script}?action=top100&searchitems=$form->{searchitems}&itemstatus=$form->{itemstatus}&bom=$form->{bom}&l_linetotal=$form->{l_linetotal}&title="
411 . $form->escape($form->{title}, 1);
413 # if we have a serialnumber limit search
414 if ($form->{serialnumber} || $form->{l_serialnumber}) {
415 $form->{l_serialnumber} = "Y";
416 unless ( $form->{bought}
419 || $form->{quoted}) {
420 $form->{bought} = $form->{sold} = 1;
423 IC->all_parts(\%myconfig, \%$form);
425 if ($form->{itemstatus} eq 'active') {
426 $option .= $locale->text('Active') . " : ";
428 if ($form->{itemstatus} eq 'obsolete') {
429 $option .= $locale->text('Obsolete') . " : ";
431 if ($form->{itemstatus} eq 'orphaned') {
432 $option .= $locale->text('Orphaned') . " : ";
434 if ($form->{itemstatus} eq 'onhand') {
435 $option .= $locale->text('On Hand') . " : ";
436 $form->{l_onhand} = "Y";
438 if ($form->{itemstatus} eq 'short') {
439 $option .= $locale->text('Short') . " : ";
440 $form->{l_onhand} = "Y";
442 if ($form->{onorder}) {
443 $form->{l_ordnumber} = "Y";
444 $callback .= "&onorder=$form->{onorder}";
445 $option .= $locale->text('On Order') . " : ";
447 if ($form->{ordered}) {
448 $form->{l_ordnumber} = "Y";
449 $callback .= "&ordered=$form->{ordered}";
450 $option .= $locale->text('Ordered') . " : ";
453 $form->{l_quonumber} = "Y";
454 $callback .= "&rfq=$form->{rfq}";
455 $option .= $locale->text('RFQ') . " : ";
457 if ($form->{quoted}) {
458 $form->{l_quonumber} = "Y";
459 $callback .= ""ed=$form->{quoted}";
460 $option .= $locale->text('Quoted') . " : ";
462 if ($form->{bought}) {
463 $form->{l_invnumber} = "Y";
464 $callback .= "&bought=$form->{bought}";
465 $option .= $locale->text('Bought') . " : ";
468 $form->{l_invnumber} = "Y";
469 $callback .= "&sold=$form->{sold}";
470 $option .= $locale->text('Sold') . " : ";
477 || $form->{quoted}) {
479 $form->{l_lastcost} = "";
480 $form->{l_name} = "Y";
481 if ($form->{transdatefrom}) {
482 $callback .= "&transdatefrom=$form->{transdatefrom}";
484 . $locale->text('From')
486 . $locale->date(\%myconfig, $form->{transdatefrom}, 1);
488 if ($form->{transdateto}) {
489 $callback .= "&transdateto=$form->{transdateto}";
491 . $locale->text('To')
493 . $locale->date(\%myconfig, $form->{transdateto}, 1);
499 if ($form->{partnumber}) {
500 $callback .= "&partnumber=$form->{partnumber}";
501 $option .= $locale->text('Part Number') . qq| : $form->{partnumber}<br>|;
504 $callback .= "&partnumber=$form->{ean}";
505 $option .= $locale->text('EAN') . qq| : $form->{ean}<br>|;
507 if ($form->{partsgroup}) {
508 $callback .= "&partsgroup=$form->{partsgroup}";
509 $option .= $locale->text('Group') . qq| : $form->{partsgroup}<br>|;
511 if ($form->{serialnumber}) {
512 $callback .= "&serialnumber=$form->{serialnumber}";
513 $option .= $locale->text('Serial Number') . qq| : $form->{serialnumber}<br>|;
515 if ($form->{description}) {
516 $callback .= "&description=$form->{description}";
517 $description = $form->{description};
518 $description =~ s/\n/<br>/g;
519 $option .= $locale->text('Part Description') . qq| : $form->{description}<br>|;
522 $callback .= "&make=$form->{make}";
523 $option .= $locale->text('Make') . qq| : $form->{make}<br>|;
525 if ($form->{model}) {
526 $callback .= "&model=$form->{model}";
527 $option .= $locale->text('Model') . qq| : $form->{model}<br>|;
529 if ($form->{drawing}) {
530 $callback .= "&drawing=$form->{drawing}";
531 $option .= $locale->text('Drawing') . qq| : $form->{drawing}<br>|;
533 if ($form->{microfiche}) {
534 $callback .= "µfiche=$form->{microfiche}";
535 $option .= $locale->text('Microfiche') . qq| : $form->{microfiche}<br>|;
537 if ($form->{l_soldtotal}) {
538 $callback .= "&soldtotal=$form->{soldtotal}";
539 $option .= $locale->text('soldtotal') . qq| : $form->{soldtotal}<br>|;
542 my @columns = $form->sort_columns(
543 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)
546 if ($form->{l_linetotal}) {
547 $form->{l_onhand} = "Y";
548 $form->{l_linetotalsellprice} = "Y" if $form->{l_sellprice};
549 if ($form->{l_lastcost}) {
550 $form->{l_linetotallastcost} = "Y";
551 if (($form->{searchitems} eq 'assembly') && !$form->{bom}) {
552 $form->{l_linetotallastcost} = "";
555 $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
558 if ($form->{searchitems} eq 'service') {
560 # remove bin, weight and rop from list
561 map { $form->{"l_$_"} = "" } qw(bin weight rop);
563 $form->{l_onhand} = "";
565 # qty is irrelevant unless bought or sold
571 || $form->{quoted}) {
572 $form->{l_onhand} = "Y";
574 $form->{l_linetotalsellprice} = "";
575 $form->{l_linetotallastcost} = "";
579 $form->{l_lastcost} = ""
580 if ($form->{searchitems} eq 'assembly' && !$form->{bom});
582 foreach my $item (@columns) {
583 if ($form->{"l_$item"} eq "Y") {
584 push @column_index, $item;
586 # add column to callback
587 $callback .= "&l_$item=Y";
591 if ($form->{l_subtotal} eq 'Y') {
592 $callback .= "&l_subtotal=Y";
595 $column_header{number} =
596 qq|<th class=listheading nowrap>| . $locale->text('number') . qq|</th>|;
597 $column_header{partnumber} =
598 qq|<th nowrap><a class=listheading href=$callback&sort=partnumber&revers=$form->{revers}&lastsort=$form->{lastsort}>|
599 . $locale->text('Part Number')
601 $column_header{description} =
602 qq|<th nowrap><a class=listheading href=$callback&sort=description&revers=$form->{revers}&lastsort=$form->{lastsort}>|
603 . $locale->text('Part Description')
605 $column_header{partsgroup} =
606 qq|<th nowrap><a class=listheading href=$callback&sort=partsgroup>|
607 . $locale->text('Group')
609 $column_header{bin} =
610 qq|<th><a class=listheading href=$callback&sort=bin>|
611 . $locale->text('Bin')
613 $column_header{priceupdate} =
614 qq|<th nowrap><a class=listheading href=$callback&sort=priceupdate>|
615 . $locale->text('Updated')
617 $column_header{onhand} =
618 qq|<th nowrap><a class=listheading href=$callback&sort=onhand&revers=$form->{revers}&lastsort=$form->{lastsort}>|
619 . $locale->text('Qty')
621 $column_header{unit} =
622 qq|<th class=listheading nowrap>| . $locale->text('Unit') . qq|</th>|;
623 $column_header{listprice} =
624 qq|<th class=listheading nowrap>|
625 . $locale->text('List Price')
627 $column_header{lastcost} =
628 qq|<th class=listheading nowrap>| . $locale->text('Last Cost') . qq|</th>|;
629 $column_header{rop} =
630 qq|<th class=listheading nowrap>| . $locale->text('ROP') . qq|</th>|;
631 $column_header{weight} =
632 qq|<th class=listheading nowrap>| . $locale->text('Weight') . qq|</th>|;
634 $column_header{invnumber} =
635 qq|<th nowrap><a class=listheading href=$callback&sort=invnumber>|
636 . $locale->text('Invoice Number')
638 $column_header{ordnumber} =
639 qq|<th nowrap><a class=listheading href=$callback&sort=ordnumber>|
640 . $locale->text('Order Number')
642 $column_header{quonumber} =
643 qq|<th nowrap><a class=listheading href=$callback&sort=quonumber>|
644 . $locale->text('Quotation')
647 $column_header{name} =
648 qq|<th nowrap><a class=listheading href=$callback&sort=name>|
649 . $locale->text('Name')
652 $column_header{sellprice} =
653 qq|<th class=listheading nowrap>|
654 . $locale->text('Sell Price')
656 $column_header{linetotalsellprice} =
657 qq|<th class=listheading nowrap>| . $locale->text('Extended') . qq|</th>|;
658 $column_header{linetotallastcost} =
659 qq|<th class=listheading nowrap>| . $locale->text('Extended') . qq|</th>|;
660 $column_header{linetotallistprice} =
661 qq|<th class=listheading nowrap>| . $locale->text('Extended') . qq|</th>|;
663 $column_header{image} =
664 qq|<th class=listheading nowrap>| . $locale->text('Image') . qq|</a></th>|;
665 $column_header{drawing} =
666 qq|<th nowrap><a class=listheading href=$callback&sort=drawing>|
667 . $locale->text('Drawing')
669 $column_header{microfiche} =
670 qq|<th nowrap><a class=listheading href=$callback&sort=microfiche>|
671 . $locale->text('Microfiche')
674 $column_header{serialnumber} =
675 qq|<th nowrap><a class=listheading href=$callback&sort=serialnumber>|
676 . $locale->text('Serial Number')
678 $column_header{soldtotal} =
679 qq|<th nowrap><a class=listheading href=$callback&sort=soldtotal&revers=$form->{revers}&lastsort=$form->{lastsort}>|
680 . $locale->text('soldtotal')
684 my $colspan = $#column_index + 1;
691 <th class=listtop colspan=$colspan>$form->{title}</th>
695 <tr><td colspan=$colspan>$option</td></tr>
697 <tr class=listheading>
700 map { print "\n$column_header{$_}" } @column_index;
706 # add order to callback
707 $form->{callback} = $callback .= "&sort=$form->{sort}";
709 # escape callback for href
710 $callback = $form->escape($callback);
712 if (@{ $form->{parts} }) {
713 $sameitem = $form->{parts}->[0]->{ $form->{sort} };
716 # insert numbers for top100
718 foreach my $ref (@{ $form->{parts} }) {
723 # if avaible -> insert choice here
724 if (($form->{ndxs_counter}) > 0) {
725 for (my $i = 1; ($i < $form->{ndxs_counter} + 1); $i++) {
726 $partnumber = $form->{"totop100_partnumber_$i"};
727 $description = $form->{"totop100_description_$i"};
728 $unit = $form->{"totop100_unit_$i"};
729 $sellprice = $form->{"totop100_sellprice_$i"};
730 $soldtotal = $form->{"totop100_soldtotal_$i"};
733 <input type=hidden name=totop100_partnumber_$i value=$form->{"totop100_partnumber_$i"}>
734 <input type=hidden name=totop100_description_$i value=$form->{"totop100_description_$i"}>
735 <input type=hidden name=totop100_unit_$i value=$form->{"totop100_unit_$i"}>
736 <input type=hidden name=totop100_sellprice_$i value=$form->{"totop100_sellprice_$i"}>
737 <input type=hidden name=totop100_soldtotal_$i value=$form->{"totop100_soldtotal_$i"}>
741 push @{ $form->{parts} },
743 partnumber => "$partnumber",
744 description => "$description",
746 sellprice => "$sellprice",
747 soldtotal => "$soldtotal" };
750 # build data for columns
752 foreach my $ref (@{ $form->{parts} }) {
754 if ($form->{l_subtotal} eq 'Y' && !$ref->{assemblyitem}) {
755 if ($sameitem ne $ref->{ $form->{sort} }) {
757 $sameitem = $ref->{ $form->{sort} };
761 $ref->{exchangerate} = 1 unless $ref->{exchangerate};
762 $ref->{sellprice} *= $ref->{exchangerate};
763 $ref->{listprice} *= $ref->{exchangerate};
764 $ref->{lastcost} *= $ref->{exchangerate};
766 # use this for assemblies
767 $onhand = $ref->{onhand};
770 if ($ref->{assemblyitem}) {
772 $onhand = 0 if ($form->{sold});
775 $ref->{description} =~ s/\n/<br>/g;
777 $column_data{number} =
779 . $form->format_amount(\%myconfig, $ref->{number})
781 $column_data{partnumber} =
782 "<td align=$align>$ref->{partnumber} </a></td>";
783 $column_data{description} = "<td>$ref->{description} </td>";
784 $column_data{partsgroup} = "<td>$ref->{partsgroup} </td>";
786 $column_data{onhand} =
788 . $form->format_amount(\%myconfig, $ref->{onhand})
790 $column_data{sellprice} =
792 . $form->format_amount(\%myconfig, $ref->{sellprice})
794 $column_data{listprice} =
796 . $form->format_amount(\%myconfig, $ref->{listprice})
798 $column_data{lastcost} =
800 . $form->format_amount(\%myconfig, $ref->{lastcost})
803 $column_data{linetotalsellprice} = "<td align=right>"
804 . $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{sellprice}, 2)
806 $column_data{linetotallastcost} = "<td align=right>"
807 . $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{lastcost}, 2)
809 $column_data{linetotallistprice} = "<td align=right>"
810 . $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{listprice}, 2)
813 if (!$ref->{assemblyitem}) {
814 $totalsellprice += $onhand * $ref->{sellprice};
815 $totallastcost += $onhand * $ref->{lastcost};
816 $totallistprice += $onhand * $ref->{listprice};
818 $subtotalonhand += $onhand;
819 $subtotalsellprice += $onhand * $ref->{sellprice};
820 $subtotallastcost += $onhand * $ref->{lastcost};
821 $subtotallistprice += $onhand * $ref->{listprice};
826 . $form->format_amount(\%myconfig, $ref->{rop}) . "</td>";
827 $column_data{weight} =
829 . $form->format_amount(\%myconfig, $ref->{weight})
831 $column_data{unit} = "<td>$ref->{unit} </td>";
832 $column_data{bin} = "<td>$ref->{bin} </td>";
833 $column_data{priceupdate} = "<td>$ref->{priceupdate} </td>";
835 $column_data{invnumber} =
836 ($ref->{module} ne 'oe')
837 ? "<td><a href=$ref->{module}.pl?action=edit&type=invoice&id=$ref->{trans_id}&callback=$callback>$ref->{invnumber}</a></td>"
838 : "<td>$ref->{invnumber}</td>";
839 $column_data{ordnumber} =
840 ($ref->{module} eq 'oe')
841 ? "<td><a href=$ref->{module}.pl?action=edit&type=$ref->{type}&id=$ref->{trans_id}&callback=$callback>$ref->{ordnumber}</a></td>"
842 : "<td>$ref->{ordnumber}</td>";
843 $column_data{quonumber} =
844 ($ref->{module} eq 'oe' && !$ref->{ordnumber})
845 ? "<td><a href=$ref->{module}.pl?action=edit&type=$ref->{type}&id=$ref->{trans_id}&callback=$callback>$ref->{quonumber}</a></td>"
846 : "<td>$ref->{quonumber}</td>";
848 $column_data{name} = "<td>$ref->{name}</td>";
850 $column_data{image} =
852 ? "<td><a href=$ref->{image}><img src=$ref->{image} height=32 border=0></a></td>"
854 $column_data{drawing} =
856 ? "<td><a href=$ref->{drawing}>$ref->{drawing}</a></td>"
858 $column_data{microfiche} =
860 ? "<td><a href=$ref->{microfiche}>$ref->{microfiche}</a></td>"
863 $column_data{serialnumber} = "<td>$ref->{serialnumber}</td>";
865 $column_data{soldtotal} = "<td align=right>$ref->{soldtotal}</td>";
869 print "<tr class=listrow$i>";
871 map { print "\n$column_data{$_}" } @column_index;
878 if ($form->{l_subtotal} eq 'Y') {
882 if ($form->{"l_linetotal"}) {
883 map { $column_data{$_} = "<td> </td>" } @column_index;
884 $column_data{linetotalsellprice} =
885 "<th class=listtotal align=right>"
886 . $form->format_amount(\%myconfig, $totalsellprice, 2)
888 $column_data{linetotallastcost} =
889 "<th class=listtotal align=right>"
890 . $form->format_amount(\%myconfig, $totallastcost, 2)
892 $column_data{linetotallistprice} =
893 "<th class=listtotal align=right>"
894 . $form->format_amount(\%myconfig, $totallistprice, 2)
897 print "<tr class=listtotal>";
899 map { print "\n$column_data{$_}" } @column_index;
906 <tr><td colspan=$colspan><hr size=3 noshade></td></tr>
915 <form method=post action=$form->{script}>
917 <input type=hidden name=itemstatus value="$form->{itemstatus}">
918 <input type=hidden name=l_linetotal value="$form->{l_linetotal}">
919 <input type=hidden name=l_partnumber value="$form->{l_partnumber}">
920 <input type=hidden name=l_description value="$form->{l_description}">
921 <input type=hidden name=l_onhand value="$form->{l_onhand}">
922 <input type=hidden name=l_unit value="$form->{l_unit}">
923 <input type=hidden name=l_sellprice value="$form->{l_sellprice}">
924 <input type=hidden name=l_linetotalsellprice value="$form->{l_linetotalsellprice}">
925 <input type=hidden name=sort value="$form->{sort}">
926 <input type=hidden name=revers value="$form->{revers}">
927 <input type=hidden name=lastsort value="$form->{lastsort}">
928 <input type=hidden name=parts value="$form->{parts}">
930 <input type=hidden name=bom value="$form->{bom}">
931 <input type=hidden name=titel value="$form->{titel}">
932 <input type=hidden name=searchitems value="$form->{searchitems}">|;
937 <input type=hidden name=ndxs_counter value="$form->{ndxs_counter}">
939 <input class=submit type=submit name=action value="|
940 . $locale->text('choice') . qq|">
948 $lxdebug->leave_sub();
953 # Warning, deep magic ahead.
954 # This function parses the requested details, sanity checks them, and converts them into a format thats usable for IC->all_parts
956 # flags coming from the form:
958 # searchitems=part revers=0 lastsort=''
961 # partnumber ean description partsgroup serialnumber make model drawing microfiche
962 # transdatefrom transdateto
965 # itemstatus = active | onhand | short | obsolete | orphaned
966 # action = continue | top100
969 # bought sold onorder ordered rfq quoted
970 # l_partnumber l_description l_serialnumber l_unit l_listprice l_sellprice l_lastcost
971 # l_linetotal l_priceupdate l_bin l_rop l_weight l_image l_drawing l_microfiche
972 # l_partsgroup l_subtotal l_soldtotal l_deliverydate
975 # nextsub revers lastsort sort ndxs_counter
977 sub generate_report {
978 $lxdebug->enter_sub();
980 $auth->assert('part_service_assembly_edit');
982 my ($revers, $lastsort, $description);
984 $form->{title} = (ucfirst $form->{searchitems}) . "s";
985 $form->{title} =~ s/ys$/ies/;
986 $form->{title} = $locale->text($form->{title});
988 my $revers = $form->{revers};
989 my $lastsort = $form->{lastsort};
991 # sorting and direction of sorting
992 # ToDO: change this to the simpler field+direction method
993 if (($form->{lastsort} eq "") && ($form->{sort} eq undef)) {
995 $form->{lastsort} = "partnumber";
996 $form->{sort} = "partnumber";
998 if ($form->{lastsort} eq $form->{sort}) {
999 $form->{revers} = 1 - $form->{revers};
1001 $form->{revers} = 0;
1002 $form->{lastsort} = $form->{sort};
1006 # special case if we have a serialnumber limit search
1007 # serialnumbers are only given in invoices and orders,
1008 # so they can only pop up in bought, sold, rfq, and quoted stuff
1009 $form->{no_sn_joins} = 'Y' if ( !$form->{bought} && !$form->{sold}
1010 && !$form->{rfq} && !$form->{quoted}
1011 && ($form->{l_serialnumber} || $form->{serialnumber}));
1013 # special case for any checkbox of bought | sold | onorder | ordered | rfq | quoted.
1014 # if any of these are ticked the behavior changes slightly for lastcost
1015 # since all those are aggregation checks for the legder tables this is an internal switch
1016 # refered to as ledgerchecks
1017 $form->{ledgerchecks} = 'Y' if ( $form->{bought} || $form->{sold} || $form->{onorder}
1018 || $form->{ordered} || $form->{rfq} || $form->{quoted});
1020 # if something should be activated if something else is active, enter it here
1021 my %dependencies = (
1022 onhand => [ qw(l_onhand) ],
1023 short => [ qw(l_onhand) ],
1024 onorder => [ qw(l_ordnumber) ],
1025 ordered => [ qw(l_ordnumber) ],
1026 rfq => [ qw(l_quonumber) ],
1027 quoted => [ qw(l_quonumber) ],
1028 bought => [ qw(l_invnumber) ],
1029 sold => [ qw(l_invnumber) ],
1030 ledgerchecks => [ qw(l_name) ],
1031 serialnumber => [ qw(l_serialnumber) ],
1032 no_sn_joins => [ qw(bought sold) ],
1035 # these strings get displayed at the top of the results to indicate the user which switches were used
1037 active => $locale->text('Active'),
1038 obsolete => $locale->text('Obsolete'),
1039 orphaned => $locale->text('Orphaned'),
1040 onhand => $locale->text('On Hand'),
1041 short => $locale->text('Short'),
1042 onorder => $locale->text('On Order'),
1043 ordered => $locale->text('Ordered'),
1044 rfq => $locale->text('RFQ'),
1045 quoted => $locale->text('Quoted'),
1046 bought => $locale->text('Bought'),
1047 sold => $locale->text('Sold'),
1048 transdatefrom => $locale->text('From') . " " . $locale->date(\%myconfig, $form->{transdatefrom}, 1),
1049 transdateto => $locale->text('To (time)') . " " . $locale->date(\%myconfig, $form->{transdateto}, 1),
1050 partnumber => $locale->text('Part Number') . ": '$form->{partnumber}'",
1051 partsgroup => $locale->text('Group') . ": '$form->{partsgroup}'",
1052 serialnumber => $locale->text('Serial Number') . ": '$form->{serialnumber}'",
1053 description => $locale->text('Part Description') . ": '$form->{description}'",
1054 make => $locale->text('Make') . ": '$form->{make}'",
1055 model => $locale->text('Model') . ": '$form->{model}'",
1056 drawing => $locale->text('Drawing') . ": '$form->{drawing}'",
1057 microfiche => $locale->text('Microfiche') . ": '$form->{microfiche}'",
1058 l_soldtotal => $locale->text('soldtotal'),
1061 my @itemstatus_keys = qw(active obsolete orphaned onhand short);
1062 my @callback_keys = qw(onorder ordered rfq quoted bought sold partnumber partsgroup serialnumber description make model
1063 drawing microfiche l_soldtotal l_deliverydate transdatefrom transdateto ean);
1065 # calculate dependencies
1066 for (@itemstatus_keys, @callback_keys) {
1067 next if ($form->{itemstatus} ne $_ && !$form->{$_});
1068 map { $form->{$_} = 'Y' } @{ $dependencies{$_} } if $dependencies{$_};
1071 # generate callback and optionstrings
1073 for my $key (@itemstatus_keys, @callback_keys) {
1074 next if ($form->{itemstatus} ne $key && !$form->{$key});
1075 push @options, $optiontexts{$key};
1078 # special case for lastcost
1079 $form->{l_lastcost} = "" if $form->{ledgerchecks};
1081 if ($form->{description}) {
1082 $description = $form->{description};
1083 $description =~ s/\n/<br>/g;
1086 if ($form->{l_linetotal}) {
1087 $form->{l_onhand} = "Y";
1088 $form->{l_linetotalsellprice} = "Y" if $form->{l_sellprice};
1089 if ($form->{l_lastcost}) {
1090 $form->{l_linetotallastcost} = "Y";
1091 if (($form->{searchitems} eq 'assembly') && !$form->{bom}) {
1092 $form->{l_linetotallastcost} = "";
1095 $form->{l_linetotallistprice} = "Y" if $form->{l_listprice};
1098 if ($form->{searchitems} eq 'service') {
1100 # remove bin, weight and rop from list
1101 map { $form->{"l_$_"} = "" } qw(bin weight rop);
1103 $form->{l_onhand} = "";
1105 # qty is irrelevant unless bought or sold
1106 if ( $form->{bought}
1111 || $form->{quoted}) {
1112 $form->{l_onhand} = "Y";
1114 $form->{l_linetotalsellprice} = "";
1115 $form->{l_linetotallastcost} = "";
1119 $form->{l_lastcost} = "" if ($form->{searchitems} eq 'assembly' && !$form->{bom});
1121 IC->all_parts(\%myconfig, \%$form);
1124 qw(partnumber description partsgroup bin onhand rop unit listprice linetotallistprice sellprice linetotalsellprice lastcost linetotallastcost
1125 priceupdate weight image drawing microfiche invnumber ordnumber quonumber name serialnumber soldtotal deliverydate);
1128 'bin' => { 'text' => $locale->text('Bin'), },
1129 'deliverydate' => { 'text' => $locale->text('deliverydate'), },
1130 'description' => { 'text' => $locale->text('Part Description'), },
1131 'drawing' => { 'text' => $locale->text('Drawing'), },
1132 'image' => { 'text' => $locale->text('Image'), },
1133 'invnumber' => { 'text' => $locale->text('Invoice Number'), },
1134 'lastcost' => { 'text' => $locale->text('Last Cost'), },
1135 'linetotallastcost' => { 'text' => $locale->text('Extended'), },
1136 'linetotallistprice' => { 'text' => $locale->text('Extended'), },
1137 'linetotalsellprice' => { 'text' => $locale->text('Extended'), },
1138 'listprice' => { 'text' => $locale->text('List Price'), },
1139 'microfiche' => { 'text' => $locale->text('Microfiche'), },
1140 'name' => { 'text' => $locale->text('Name'), },
1141 'onhand' => { 'text' => $locale->text('Qty'), },
1142 'ordnumber' => { 'text' => $locale->text('Order Number'), },
1143 'partnumber' => { 'text' => $locale->text('Part Number'), },
1144 'partsgroup' => { 'text' => $locale->text('Group'), },
1145 'priceupdate' => { 'text' => $locale->text('Updated'), },
1146 'quonumber' => { 'text' => $locale->text('Quotation'), },
1147 'rop' => { 'text' => $locale->text('ROP'), },
1148 'sellprice' => { 'text' => $locale->text('Sell Price'), },
1149 'serialnumber' => { 'text' => $locale->text('Serial Number'), },
1150 'soldtotal' => { 'text' => $locale->text('soldtotal'), },
1151 'unit' => { 'text' => $locale->text('Unit'), },
1152 'weight' => { 'text' => $locale->text('Weight'), },
1155 map { $column_defs{$_}->{visible} = $form->{"l_$_"} ? 1 : 0 } @columns;
1156 map { $column_defs{$_}->{align} = 'right' } qw(onhand sellprice listprice lastcost linetotalsellprice linetotallastcost linetotallistprice rop weight soldtotal);
1158 my @hidden_variables = (qw(l_subtotal l_linetotal searchitems itemstatus bom), @itemstatus_keys, @callback_keys, map { "l_$_" } @columns);
1159 my $callback = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
1161 my @sort_full = qw(partnumber description onhand soldtotal deliverydate);
1162 my @sort_no_revers = qw(partsgroup bin priceupdate invnumber ordnumber quonumber name image drawing serialnumber);
1164 foreach my $col (@sort_full) {
1165 $column_defs{$col}->{link} = join '&', $callback, "sort=$col", map { "$_=" . E($form->{$_}) } qw(revers lastsort);
1167 map { $column_defs{$_}->{link} = "${callback}&sort=$_" } @sort_no_revers;
1169 # add order to callback
1170 $form->{callback} = join '&', ($callback, map { "${_}=" . E($form->{$_}) } qw(sort revers));
1172 my $report = SL::ReportGenerator->new(\%myconfig, $form);
1174 my %attachment_basenames = (
1175 'part' => $locale->text('part_list'),
1176 'service' => $locale->text('service_list'),
1177 'assembly' => $locale->text('assembly_list'),
1180 $report->set_options('top_info_text' => $locale->text('Options') . ': ' . join(', ', grep $_, @options),
1181 'raw_bottom_info_text' => $form->parse_html_template('ic/generate_report_bottom'),
1182 'output_format' => 'HTML',
1183 'title' => $form->{title},
1184 'attachment_basename' => $attachment_basenames{$form->{searchitems}} . strftime('_%Y%m%d', localtime time),
1186 $report->set_options_from_form();
1188 $report->set_columns(%column_defs);
1189 $report->set_column_order(@columns);
1191 $report->set_export_options('generate_report', @hidden_variables, qw(sort revers));
1193 $report->set_sort_indicator($form->{sort}, $form->{revers} ? 0 : 1);
1195 my @subtotal_columns = qw(sellprice listprice lastcost);
1196 my %subtotals = map { $_ => 0 } ('onhand', @subtotal_columns);
1197 my %totals = map { $_ => 0 } @subtotal_columns;
1199 my $same_item = $form->{parts}[0]{ $form->{sort} } if (scalar @{ $form->{parts} });
1202 foreach my $ref (@{ $form->{parts} }) {
1204 # fresh row, for inserting later
1205 my $row = { map { $_ => { 'data' => $ref->{$_} } } @columns };
1207 $ref->{exchangerate} ||= 1;
1208 $ref->{price_factor} ||= 1;
1209 $ref->{sellprice} *= $ref->{exchangerate} / $ref->{price_factor};
1210 $ref->{listprice} *= $ref->{exchangerate} / $ref->{price_factor};
1211 $ref->{lastcost} *= $ref->{exchangerate} / $ref->{price_factor};
1213 # use this for assemblies
1214 my $onhand = $ref->{onhand};
1216 if ($ref->{assemblyitem}) {
1217 $row->{partnumber}{align} = 'right';
1218 $row->{onhand}{data} = 0;
1219 $onhand = 0 if ($form->{sold});
1222 my $edit_link = build_std_url('action=edit', 'id=' . E($ref->{id}), 'callback');
1223 $row->{partnumber}->{link} = $edit_link;
1224 $row->{description}->{link} = $edit_link;
1226 foreach (qw(sellprice listprice lastcost)) {
1227 $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{$_}, -2);
1228 $row->{"linetotal$_"}{data} = $form->format_amount(\%myconfig, $ref->{onhand} * $ref->{$_}, 2);
1231 map { $row->{$_}{data} = $form->format_amount(\%myconfig, $ref->{$_}); } qw(onhand rop weight soldtotal);
1233 if (!$ref->{assemblyitem}) {
1234 foreach my $col (@subtotal_columns) {
1235 $totals{$col} += $onhand * $ref->{$col};
1236 $subtotals{$col} += $onhand * $ref->{$col};
1239 $subtotals{onhand} += $onhand;
1243 if ($ref->{module} eq 'oe') {
1244 my $edit_oe_link = build_std_url("script=oe.pl", 'action=edit', 'type=' . E($ref->{type}), 'id=' . E($ref->{trans_id}), 'callback');
1245 $row->{ordnumber}{link} = $edit_oe_link;
1246 $row->{quonumber}{link} = $edit_oe_link if (!$ref->{ordnumber});
1249 $row->{invnumber}{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'type=invoice', 'id=' . E($ref->{trans_id}), 'callback');
1252 # set properties of images
1253 if ($ref->{image} && (lc $report->{options}->{output_format} eq 'html')) {
1254 $row->{image}{data} = '';
1255 $row->{image}{raw_data} = '<a href="' . H($ref->{image}) . '"><img src="' . H($ref->{image}) . '" height="32" border="0"></a>';
1257 map { $row->{$_}{link} = $ref->{$_} } qw(drawing microfiche);
1259 $report->add_data($row);
1261 my $next_ref = $form->{parts}[$idx + 1];
1263 # insert subtotal rows
1264 if (($form->{l_subtotal} eq 'Y') &&
1266 (!$next_ref->{assemblyitem} && ($same_item ne $next_ref->{ $form->{sort} })))) {
1267 my $row = { map { $_ => { 'class' => 'listsubtotal', } } @columns };
1269 if (($form->{searchitems} ne 'assembly') || !$form->{bom}) {
1270 $row->{onhand}->{data} = $form->format_amount(\%myconfig, $subtotals{onhand});
1273 map { $row->{"linetotal$_"}->{data} = $form->format_amount(\%myconfig, $subtotals{$_}, 2) } @subtotal_columns;
1274 map { $subtotals{$_} = 0 } ('onhand', @subtotal_columns);
1276 $report->add_data($row);
1278 $same_item = $next_ref->{ $form->{sort} };
1284 if ($form->{"l_linetotal"}) {
1285 my $row = { map { $_ => { 'class' => 'listtotal', } } @columns };
1287 map { $row->{"linetotal$_"}->{data} = $form->format_amount(\%myconfig, $totals{$_}, 2) } @subtotal_columns;
1289 $report->add_separator();
1290 $report->add_data($row);
1293 $report->generate_with_headers();
1295 $lxdebug->leave_sub();
1296 } #end generate_report
1298 sub parts_subtotal {
1299 $lxdebug->enter_sub();
1301 $auth->assert('part_service_assembly_edit');
1304 our (%column_data, @column_index);
1305 our ($subtotalonhand, $totalsellprice, $totallastcost, $totallistprice, $subtotalsellprice, $subtotallastcost, $subtotallistprice);
1307 map { $column_data{$_} = "<td> </td>" } @column_index;
1308 $subtotalonhand = 0 if ($form->{searchitems} eq 'assembly' && $form->{bom});
1310 $column_data{onhand} =
1311 "<th class=listsubtotal align=right>"
1312 . $form->format_amount(\%myconfig, $subtotalonhand)
1315 $column_data{linetotalsellprice} =
1316 "<th class=listsubtotal align=right>"
1317 . $form->format_amount(\%myconfig, $subtotalsellprice, 2)
1319 $column_data{linetotallistprice} =
1320 "<th class=listsubtotal align=right>"
1321 . $form->format_amount(\%myconfig, $subtotallistprice, 2)
1323 $column_data{linetotallastcost} =
1324 "<th class=listsubtotal align=right>"
1325 . $form->format_amount(\%myconfig, $subtotallastcost, 2)
1328 $subtotalonhand = 0;
1329 $subtotalsellprice = 0;
1330 $subtotallistprice = 0;
1331 $subtotallastcost = 0;
1333 print "<tr class=listsubtotal>";
1335 map { print "\n$column_data{$_}" } @column_index;
1341 $lxdebug->leave_sub();
1345 $lxdebug->enter_sub();
1347 $auth->assert('part_service_assembly_edit');
1349 # show history button
1350 $form->{javascript} = qq|<script type="text/javascript" src="js/show_history.js"></script>|;
1351 #/show hhistory button
1352 IC->get_part(\%myconfig, \%$form);
1354 $form->{"original_partnumber"} = $form->{"partnumber"};
1356 $form->{title} = $locale->text('Edit ' . ucfirst $form->{item});
1361 $lxdebug->leave_sub();
1365 $lxdebug->enter_sub();
1367 $auth->assert('part_service_assembly_edit');
1369 IC->create_links("IC", \%myconfig, \%$form);
1372 map({ $form->{selectcurrency} .= "<option>$_\n" }
1373 split(/:/, $form->{currencies}));
1375 # parts and assemblies have the same links
1376 my $item = $form->{item};
1377 if ($form->{item} eq 'assembly') {
1381 # build the popup menus
1382 $form->{taxaccounts} = "";
1383 foreach my $key (keys %{ $form->{IC_links} }) {
1384 foreach my $ref (@{ $form->{IC_links}{$key} }) {
1386 # if this is a tax field
1387 if ($key =~ /IC_tax/) {
1388 if ($key =~ /\Q$item\E/) {
1389 $form->{taxaccounts} .= "$ref->{accno} ";
1390 $form->{"IC_tax_$ref->{accno}_description"} =
1391 "$ref->{accno}--$ref->{description}";
1394 if ($form->{amount}{ $ref->{accno} }) {
1395 $form->{"IC_tax_$ref->{accno}"} = "checked";
1398 $form->{"IC_tax_$ref->{accno}"} = "checked";
1403 $form->{"select$key"} .=
1404 "<option $ref->{selected}>$ref->{accno}--$ref->{description}\n";
1405 if ($form->{amount}{$key} eq $ref->{accno}) {
1406 $form->{$key} = "$ref->{accno}--$ref->{description}";
1412 chop $form->{taxaccounts};
1414 if (($form->{item} eq "part") || ($form->{item} eq "assembly")) {
1415 $form->{selectIC_income} = $form->{selectIC_sale};
1416 $form->{selectIC_expense} = $form->{selectIC_cogs};
1417 $form->{IC_income} = $form->{IC_sale};
1418 $form->{IC_expense} = $form->{IC_cogs};
1421 delete $form->{IC_links};
1422 delete $form->{amount};
1424 $form->get_partsgroup(\%myconfig, { all => 1 });
1426 $form->{partsgroup} = "$form->{partsgroup}--$form->{partsgroup_id}";
1428 if (@{ $form->{all_partsgroup} }) {
1429 $form->{selectpartsgroup} = qq|<option>\n|;
1430 map { $form->{selectpartsgroup} .= qq|<option value="$_->{partsgroup}--$_->{id}">$_->{partsgroup}\n| } @{ $form->{all_partsgroup} };
1433 if ($form->{item} eq 'assembly') {
1435 foreach my $i (1 .. $form->{assembly_rows}) {
1436 if ($form->{"partsgroup_id_$i"}) {
1437 $form->{"partsgroup_$i"} =
1438 qq|$form->{"partsgroup_$i"}--$form->{"partsgroup_id_$i"}|;
1441 $form->get_partsgroup(\%myconfig);
1443 if (@{ $form->{all_partsgroup} }) {
1444 $form->{selectassemblypartsgroup} = qq|<option>\n|;
1447 $form->{selectassemblypartsgroup} .=
1448 qq|<option value="$_->{partsgroup}--$_->{id}">$_->{partsgroup}\n|
1449 } @{ $form->{all_partsgroup} };
1452 $lxdebug->leave_sub();
1456 $lxdebug->enter_sub();
1458 $auth->assert('part_service_assembly_edit');
1460 $form->{eur} = $eur; # config dumps into namespace - yuck
1461 $form->{pg_keys} = sub { "$_[0]->{partsgroup}--$_[0]->{id}" };
1462 $form->{description_area} = ($form->{rows} = $form->numtextrows($form->{description}, 40)) > 1;
1463 $form->{notes_rows} = max 4, $form->numtextrows($form->{notes}, 40), $form->numtextrows($form->{formel}, 40);
1465 map { $form->{"is_$_"} = ($form->{item} eq $_) } qw(part service assembly);
1466 map { $form->{$_} =~ s/"/"/g; } qw(unit);
1468 $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS',
1469 'partsgroup' => 'all_partsgroup');
1471 IC->retrieve_buchungsgruppen(\%myconfig, $form);
1472 @{ $form->{BUCHUNGSGRUPPEN} } = grep { $_->{id} eq $form->{buchungsgruppen_id} || ($form->{id} && $form->{orphaned}) || !$form->{id} } @{ $form->{BUCHUNGSGRUPPEN} };
1474 # use JavaScript Calendar or not (yes!)
1475 $form->{jsscript} = 1;
1477 $units = AM->retrieve_units(\%myconfig, $form);
1478 $form->{ALL_UNITS} = [ map +{ name => $_ }, sort { $units->{$a}{sortkey} <=> $units->{$b}{sortkey} } keys %$units ];
1480 $form->{fokus} = "ic.partnumber";
1483 print $form->parse_html_template('ic/form_header', { ALL_PRICE_FACTORS => $form->{ALL_PRICE_FACTORS},
1484 ALL_UNITS => $form->{ALL_UNITS},
1485 BUCHUNGSGRUPPEN => $form->{BUCHUNGSGRUPPEN},
1486 payment_terms => $form->{payment_terms},
1487 all_partsgroup => $form->{all_partsgroup}});
1488 $lxdebug->leave_sub();
1492 $lxdebug->enter_sub();
1494 $auth->assert('part_service_assembly_edit');
1496 if ($form->{item} eq "assembly") {
1501 <table width="100%">
1503 <th colspan=2 align=right>| . $locale->text('Total') . qq| </th>
1504 <th align=right>| . $form->format_amount(\%myconfig, $form->{assemblytotal}, 2) . qq|</th>
1509 <input type=hidden name=assembly_rows value=$form->{assembly_rows}>
1514 <input type=hidden name=callback value="$form->{callback}">
1515 <input type=hidden name=previousform value="$form->{previousform}">
1516 <input type=hidden name=taxaccount2 value="$form->{taxaccount2}">
1517 <input type=hidden name=vc value=$form->{vc}>
1519 <td><hr size=3 noshade></td>
1524 <input class=submit type=submit name=action value="|
1525 . $locale->text('Update') . qq|">
1528 unless ($form->{item} eq "service") {
1530 <input type=hidden name=makemodel_rows value=$form->{makemodel_rows}>
1535 <input type=hidden name=price_rows value=$form->{price_rows}>|;
1538 <input class=submit type=submit name=action value="|
1539 . $locale->text('Save') . qq|">|;
1543 if (!$form->{previousform}) {
1545 <input class=submit type=submit name=action value="|
1546 . $locale->text('Save as new') . qq|">|;
1549 if ($form->{orphaned}) {
1550 if (!$form->{previousform}) {
1551 if ($form->{item} eq 'assembly') {
1552 if (!$form->{onhand}) {
1554 <input class=submit type=submit name=action value="|
1555 . $locale->text('Delete') . qq|">|;
1559 <input class=submit type=submit name=action value="|
1560 . $locale->text('Delete') . qq|">|;
1566 if (!$form->{previousform}) {
1567 if ($form->{menubar}) {
1568 require "bin/mozilla/menu.pl";
1572 # button for saving history
1573 if($form->{id} ne "") {
1575 <input type=button class=submit onclick=set_history_window(|
1577 . qq|); name=history id=history value=|
1578 . $locale->text('history')
1581 # /button for saving history
1586 <script type="text/javascript" src="js/wz_tooltip.js"></script>
1592 $lxdebug->leave_sub();
1596 $lxdebug->enter_sub();
1604 <th class="listheading">| . $locale->text('Make') . qq|</th>
1605 <th class="listheading">| . $locale->text('Model') . qq|</th>
1609 for my $i (1 .. $numrows) {
1610 $form->{"make_$i"} =~ s/\"/"/g;
1611 $form->{"model_$i"} =~ s/\"/"/g;
1614 <td width=50%><input name="make_$i" size=30 value="$form->{"make_$i"}"></td>
1615 <td width=50%><input name="model_$i" size=30 value="$form->{"model_$i"}"></td>
1626 $lxdebug->leave_sub();
1630 $lxdebug->enter_sub();
1632 my (@column_index, %column_data, %column_header);
1633 my ($nochange, $callback, $previousform, $linetotal, $href);
1635 our ($deliverydate); # ToDO: cjeck if this indeed comes from global context
1638 qw(runningnumber qty unit bom partnumber description partsgroup total);
1640 if ($form->{previousform}) {
1642 @column_index = qw(qty unit bom partnumber description partsgroup total);
1646 $form->{old_callback} = $form->{callback};
1647 $callback = $form->{callback};
1648 $form->{callback} = "$form->{script}?action=display_form";
1651 map { delete $form->{$_} } qw(action header);
1655 # save form variables in a previousform variable
1656 foreach my $key (sort keys %$form) {
1659 $form->{$key} =~ s/&/%26/g;
1660 $previousform .= qq|$key=$form->{$key}&|;
1663 $previousform = $form->escape($form->escape($previousform, 1));
1664 $form->{callback} = $callback;
1666 $form->{assemblytotal} = 0;
1667 $form->{weight} = 0;
1670 $column_header{runningnumber} =
1671 qq|<th nowrap width=5%>| . $locale->text('No.') . qq|</th>|;
1672 $column_header{qty} =
1673 qq|<th align=left nowrap width=10%>| . $locale->text('Qty') . qq|</th>|;
1674 $column_header{unit} =
1675 qq|<th align=left nowrap width=5%>| . $locale->text('Unit') . qq|</th>|;
1676 $column_header{partnumber} =
1677 qq|<th align=left nowrap width=20%>|
1678 . $locale->text('Part Number')
1680 $column_header{description} =
1681 qq|<th nowrap width=50%>| . $locale->text('Part Description') . qq|</th>|;
1682 $column_header{total} =
1683 qq|<th align=right nowrap>| . $locale->text('Extended') . qq|</th>|;
1684 $column_header{bom} = qq|<th>| . $locale->text('BOM') . qq|</th>|;
1685 $column_header{partsgroup} = qq|<th>| . $locale->text('Group') . qq|</th>|;
1688 <tr class=listheading>
1689 <th class=listheading>| . $locale->text('Individual Items') . qq|</th>
1697 map { print "\n$column_header{$_}" } @column_index;
1703 for my $i (1 .. $numrows) {
1704 $form->{"partnumber_$i"} =~ s/\"/"/g;
1707 $form->round_amount($form->{"sellprice_$i"} * $form->{"qty_$i"}, 2);
1708 $form->{assemblytotal} += $linetotal;
1710 $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
1712 $linetotal = $form->format_amount(\%myconfig, $linetotal, 2);
1714 if (($i >= 1) && ($i == $numrows)) {
1717 map { $column_data{$_} = qq|<td></td>| }
1718 qw(qty unit partnumber description bom partsgroup);
1721 map { $column_data{$_} = qq|<td></td>| } qw(runningnumber unit bom);
1724 qq|<td><input name="qty_$i" size=5 value="$form->{"qty_$i"}"></td>|;
1725 $column_data{partnumber} =
1726 qq|<td><input name="partnumber_$i" size=15 value="$form->{"partnumber_$i"}"></td>|;
1727 $column_data{description} =
1728 qq|<td><input name="description_$i" size=40 value="$form->{"description_$i"}"></td>|;
1729 $column_data{partsgroup} =
1730 qq|<td><input name="partsgroup_$i" size=10 value="$form->{"partsgroup_$i"}"></td>|;
1736 if ($form->{previousform}) {
1737 $column_data{partnumber} =
1738 qq|<td><input type=hidden name="partnumber_$i" value="$form->{"partnumber_$i"}">$form->{"partnumber_$i"}</td>|;
1740 qq|<td align=right><input type=hidden name="qty_$i" value="$form->{"qty_$i"}">$form->{"qty_$i"}</td>|;
1743 qq|<td align=center><input type=hidden name="bom_$i" value=$form->{"bom_$i"}>|;
1744 $column_data{bom} .= ($form->{"bom_$i"}) ? "x" : " ";
1745 $column_data{bom} .= qq|</td>|;
1747 $column_data{partsgroup} =
1748 qq|<td><input type=hidden name="partsgroup_$i" value="$form->{"partsgroup_$i"}">$form->{"partsgroup_$i"}</td>|;
1752 qq|$form->{script}?action=edit&id=$form->{"id_$i"}&rowcount=$i&previousform=$previousform|;
1753 $column_data{partnumber} =
1754 qq|<td><input type=hidden name="partnumber_$i" value="$form->{"partnumber_$i"}"><a href=$href>$form->{"partnumber_$i"}</a></td>|;
1755 $column_data{runningnumber} =
1756 qq|<td><input name="runningnumber_$i" size=3 value="$i"></td>|;
1758 qq|<td><input name="qty_$i" size=5 value="$form->{"qty_$i"}"></td>|;
1760 $form->{"bom_$i"} = ($form->{"bom_$i"}) ? "checked" : "";
1762 qq|<td align=center><input name="bom_$i" type=checkbox class=checkbox value=1 $form->{"bom_$i"}></td>|;
1764 $column_data{partsgroup} =
1765 qq|<td><input type=hidden name="partsgroup_$i" value="$form->{"partsgroup_$i"}">$form->{"partsgroup_$i"}</td>|;
1768 $column_data{unit} =
1769 qq|<td><input type=hidden name="unit_$i" value="$form->{"unit_$i"}">$form->{"unit_$i"}</td>|;
1770 $column_data{description} =
1771 qq|<td><input type=hidden name="description_$i" value="$form->{"description_$i"}">$form->{"description_$i"}</td>|;
1774 $column_data{total} = qq|<td align=right>$linetotal</td>|;
1776 $column_data{deliverydate} = qq|<td align=right>$deliverydate</td>|;
1781 map { print "\n$column_data{$_}" } @column_index;
1785 <input type=hidden name="id_$i" value=$form->{"id_$i"}>
1786 <input type=hidden name="sellprice_$i" value=$form->{"sellprice_$i"}>
1787 <input type=hidden name="weight_$i" value=$form->{"weight_$i"}>
1797 $lxdebug->leave_sub();
1801 $lxdebug->enter_sub();
1803 if ($form->{item} eq "assembly") {
1804 my $i = $form->{assembly_rows};
1806 # if last row is empty check the form otherwise retrieve item
1807 if ( ($form->{"partnumber_$i"} eq "")
1808 && ($form->{"description_$i"} eq "")
1809 && ($form->{"partsgroup_$i"} eq "")) {
1815 IC->assembly_item(\%myconfig, \%$form);
1817 my $rows = scalar @{ $form->{item_list} };
1820 $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
1823 $form->{makemodel_rows}--;
1827 map { $form->{item_list}[$i]{$_} =~ s/\"/"/g }
1828 qw(partnumber description unit partsgroup);
1829 map { $form->{"${_}_$i"} = $form->{item_list}[0]{$_} }
1830 keys %{ $form->{item_list}[0] };
1831 $form->{"runningnumber_$i"} = $form->{assembly_rows};
1832 $form->{assembly_rows}++;
1840 $form->{rowcount} = $i;
1841 $form->{assembly_rows}++;
1848 } elsif (($form->{item} eq 'part') || ($form->{item} eq 'service')) {
1852 $lxdebug->leave_sub();
1856 $lxdebug->enter_sub();
1858 $auth->assert('part_service_assembly_edit');
1860 my ($parts_id, %newform, $previousform, $amount, $callback);
1862 # check if there is a part number - commented out, cause there is an automatic allocation of numbers
1863 # $form->isblank("partnumber", $locale->text(ucfirst $form->{item}." Part Number missing!"));
1865 # check if there is a description
1866 $form->isblank("description", $locale->text("Part Description missing!"));
1868 if ($form->{obsolete}) {
1871 "Inventory quantity must be zero before you can set this $form->{item} obsolete!"
1873 if ($form->{onhand} * 1);
1876 if (!$form->{buchungsgruppen_id}) {
1877 $form->error($locale->text("Parts must have an entry type.") . " " .
1878 $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.")
1882 $form->error($locale->text('Description must not be empty!')) unless $form->{description};
1883 $form->error($locale->text('Partnumber must not be set to empty!')) if $form->{id} && !$form->{partnumber};
1886 $lxdebug->message($LXDebug::DEBUG1, "ic.pl: sellprice in save = $form->{sellprice}\n");
1887 if (IC->save(\%myconfig, \%$form) == 3) {
1888 $form->error($locale->text('Partnumber not unique!'));
1890 # saving the history
1891 if(!exists $form->{addition}) {
1892 $form->{snumbers} = qq|partnumber_| . $form->{partnumber};
1893 $form->{addition} = "SAVED";
1894 $form->save_history($form->dbconnect(\%myconfig));
1896 # /saving the history
1897 $parts_id = $form->{id};
1900 # load previous variables
1901 if ($form->{previousform}) {
1903 # save the new form variables before splitting previousform
1904 map { $newform{$_} = $form->{$_} } keys %$form;
1906 $previousform = $form->unescape($form->{previousform});
1908 # don't trample on previous variables
1909 map { delete $form->{$_} } keys %newform;
1911 # now take it apart and restore original values
1912 foreach my $item (split /&/, $previousform) {
1913 my ($key, $value) = split m/=/, $item, 2;
1914 $value =~ s/%26/&/g;
1915 $form->{$key} = $value;
1917 $form->{taxaccounts} = $newform{taxaccount2};
1919 if ($form->{item} eq 'assembly') {
1921 # undo number formatting
1922 map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) }
1923 qw(weight listprice sellprice rop);
1925 $form->{assembly_rows}--;
1926 $i = $newform{rowcount};
1927 $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
1929 $form->{sellprice} -= $form->{"sellprice_$i"} * $form->{"qty_$i"};
1930 $form->{weight} -= $form->{"weight_$i"} * $form->{"qty_$i"};
1932 # change/add values for assembly item
1933 map { $form->{"${_}_$i"} = $newform{$_} } qw(partnumber description bin unit weight listprice sellprice inventory_accno income_accno expense_accno price_factor_id);
1935 $form->{sellprice} += $form->{"sellprice_$i"} * $form->{"qty_$i"};
1936 $form->{weight} += $form->{"weight_$i"} * $form->{"qty_$i"};
1940 # set values for last invoice/order item
1941 $i = $form->{rowcount};
1942 $form->{"qty_$i"} = 1 unless ($form->{"qty_$i"});
1944 map { $form->{"${_}_$i"} = $newform{$_} } qw(partnumber description bin unit listprice inventory_accno income_accno expense_accno sellprice lastcost price_factor_id);
1946 $form->{"longdescription_$i"} = $newform{notes};
1948 $form->{"sellprice_$i"} = $newform{lastcost} if ($form->{vendor_id});
1950 if ($form->{exchangerate} != 0) {
1951 $form->{"sellprice_$i"} /= $form->{exchangerate};
1954 $lxdebug->message($LXDebug::DEBUG1, qq|sellprice_$i in previousform 2 = | . $form->{"sellprice_$i"} . qq|\n|);
1956 map { $form->{"taxaccounts_$i"} .= "$_ " } split / /, $newform{taxaccount};
1957 chop $form->{"taxaccounts_$i"};
1958 foreach my $item (qw(description rate taxnumber)) {
1959 my $index = $form->{"taxaccounts_$i"} . "_$item";
1960 $form->{$index} = $newform{$index};
1963 # credit remaining calculation
1964 $amount = $form->{"sellprice_$i"} * (1 - $form->{"discount_$i"} / 100) * $form->{"qty_$i"};
1966 map { $form->{"${_}_base"} += $amount } (split / /, $form->{"taxaccounts_$i"});
1967 map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded};
1969 $form->{creditremaining} -= $amount;
1971 # redo number formatting, because invoice parse them!
1972 map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}) } qw(weight listprice sellprice rop);
1975 $form->{"id_$i"} = $parts_id;
1977 # Get the actual price factor (not just the ID) for the marge calculation.
1978 $form->get_lists('price_factors' => 'ALL_PRICE_FACTORS');
1979 foreach my $pfac (@{ $form->{ALL_PRICE_FACTORS} }) {
1980 next if ($pfac->{id} != $newform{price_factor_id});
1981 $form->{"marge_price_factor_$i"} = $pfac->{factor};
1984 delete $form->{ALL_PRICE_FACTORS};
1986 delete $form->{action};
1988 # restore original callback
1989 $callback = $form->unescape($form->{callback});
1990 $form->{callback} = $form->unescape($form->{old_callback});
1991 delete $form->{old_callback};
1993 $form->{makemodel_rows}--;
1995 # put callback together
1996 foreach my $key (keys %$form) {
1998 # do single escape for Apache 2.0
1999 my $value = $form->escape($form->{$key}, 1);
2000 $callback .= qq|&$key=$value|;
2002 $form->{callback} = $callback;
2004 $lxdebug->message($LXDebug::DEBUG1, qq|ic.pl: sellprice_$i nach sub save = | . $form->{"sellprice_$i"} . qq|\n|);
2009 $lxdebug->leave_sub();
2013 $lxdebug->enter_sub();
2015 $auth->assert('part_service_assembly_edit');
2017 # saving the history
2018 if(!exists $form->{addition}) {
2019 $form->{snumbers} = qq|partnumber_| . $form->{partnumber};
2020 $form->{addition} = "SAVED AS NEW";
2021 $form->save_history($form->dbconnect(\%myconfig));
2023 # /saving the history
2025 if ($form->{"original_partnumber"} &&
2026 ($form->{"partnumber"} eq $form->{"original_partnumber"})) {
2027 $form->{partnumber} = "";
2030 $lxdebug->leave_sub();
2034 $lxdebug->enter_sub();
2036 $auth->assert('part_service_assembly_edit');
2038 # saving the history
2039 if(!exists $form->{addition}) {
2040 $form->{snumbers} = qq|partnumber_| . $form->{partnumber};
2041 $form->{addition} = "DELETED";
2042 $form->save_history($form->dbconnect(\%myconfig));
2044 # /saving the history
2045 my $rc = IC->delete(\%myconfig, \%$form);
2048 $form->redirect($locale->text('Item deleted!')) if ($rc > 0);
2049 $form->error($locale->text('Cannot delete item!'));
2051 $lxdebug->leave_sub();
2055 $lxdebug->enter_sub();
2057 $auth->assert('part_service_assembly_edit');
2062 pricegroup => $form->{"pricegroup_$_"},
2063 pricegroup_id => $form->{"pricegroup_id_$_"},
2064 price => $form->{"price_$_"},
2067 print $form->parse_html_template('ic/price_row', { PRICES => \@PRICES });
2069 $lxdebug->leave_sub();
2072 sub parts_language_selection {
2073 $lxdebug->enter_sub();
2075 $auth->assert('part_service_assembly_edit');
2079 my $languages = IC->retrieve_languages(\%myconfig, $form);
2081 if ($form->{language_values} ne "") {
2082 foreach $item (split(/---\+\+\+---/, $form->{language_values})) {
2083 my ($language_id, $translation, $longdescription) = split(/--\+\+--/, $item);
2085 foreach my $language (@{ $languages }) {
2086 next unless ($language->{id} == $language_id);
2088 $language->{translation} = $translation;
2089 $language->{longdescription} = $longdescription;
2095 my @header_sort = qw(name longdescription);
2096 my %header_title = ( "name" => $locale->text("Name"),
2097 "longdescription" => $locale->text("Long Description"),
2101 map(+{ "column_title" => $header_title{$_},
2103 "callback" => $callback,
2107 $form->{"title"} = $locale->text("Language Values");
2109 print $form->parse_html_template("ic/parts_language_selection", { "HEADER" => \@header,
2110 "LANGUAGES" => $languages,
2111 "onload" => $onload });
2113 $lxdebug->leave_sub();
2116 sub continue { call_sub($form->{"nextsub"}); }