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
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation; either version 2 of the License, or
20 # (at your option) any later version.
22 # This program is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 # GNU General Public License for more details.
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #======================================================================
31 # Inventory Control backend
33 #======================================================================
40 $main::lxdebug->enter_sub();
42 my ($self, $myconfig, $form) = @_;
45 my $dbh = $form->dbconnect($myconfig);
51 c1.accno AS inventory_accno,
52 c2.accno AS income_accno,
53 c3.accno AS expense_accno,
56 LEFT JOIN chart c1 ON (p.inventory_accno_id = c1.id)
57 LEFT JOIN chart c2 ON (p.income_accno_id = c2.id)
58 LEFT JOIN chart c3 ON (p.expense_accno_id = c3.id)
59 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
61 my $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{id}));
63 # copy to $form variables
64 map { $form->{$_} = $ref->{$_} } (keys %{$ref});
66 my %oid = ('Pg' => 'a.oid',
67 'Oracle' => 'a.rowid');
69 # part or service item
70 $form->{item} = ($form->{inventory_accno}) ? 'part' : 'service';
71 if ($form->{assembly}) {
72 $form->{item} = 'assembly';
74 # retrieve assembly items
76 qq|SELECT p.id, p.partnumber, p.description,
77 p.sellprice, p.weight, a.qty, a.bom, p.unit,
80 JOIN assembly a ON (a.parts_id = p.id)
81 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
83 ORDER BY $oid{$myconfig->{dbdriver}}|;
84 $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{id}));
86 $form->{assembly_rows} = 0;
87 while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
88 $form->{assembly_rows}++;
89 foreach my $key (keys %{$ref}) {
90 $form->{"${key}_$form->{assembly_rows}"} = $ref->{$key};
97 # setup accno hash for <option checked> {amount} is used in create_links
98 $form->{amount}{IC} = $form->{inventory_accno};
99 $form->{amount}{IC_income} = $form->{income_accno};
100 $form->{amount}{IC_sale} = $form->{income_accno};
101 $form->{amount}{IC_expense} = $form->{expense_accno};
102 $form->{amount}{IC_cogs} = $form->{expense_accno};
104 my @pricegroups = ();
105 my @pricegroups_not_used = ();
109 qq|SELECT p.parts_id, p.pricegroup_id, p.price,
110 (SELECT pg.pricegroup
112 WHERE pg.id = p.pricegroup_id) AS pricegroup
115 ORDER BY pricegroup|;
116 $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{id}));
120 while (($form->{"klass_$i"}, $form->{"pricegroup_id_$i"},
121 $form->{"price_$i"}, $form->{"pricegroup_$i"})
122 = $sth->fetchrow_array()) {
123 $form->{"price_$i"} = $form->round_amount($form->{"price_$i"}, 5);
124 $form->{"price_$i"} = $form->format_amount($myconfig, $form->{"price_$i"}, -2);
125 push @pricegroups, $form->{"pricegroup_id_$i"};
132 $query = qq|SELECT id, pricegroup FROM pricegroup|;
133 $form->{PRICEGROUPS} = selectall_hashref_query($form, $dbh, $query);
135 #find not used pricegroups
136 while ($tmp = pop(@{ $form->{PRICEGROUPS} })) {
138 foreach my $item (@pricegroups) {
139 if ($item eq $tmp->{id}) {
144 push(@pricegroups_not_used, $tmp) unless ($in_use);
147 # if not used pricegroups are avaible
148 if (@pricegroups_not_used) {
150 foreach $name (@pricegroups_not_used) {
151 $form->{"klass_$i"} = "$name->{id}";
152 $form->{"price_$i"} = $form->round_amount($form->{sellprice}, 5);
153 $form->{"price_$i"} = $form->format_amount($myconfig, $form->{"price_$i"}, -2);
154 $form->{"pricegroup_id_$i"} = "$name->{id}";
155 $form->{"pricegroup_$i"} = "$name->{pricegroup}";
161 $form->{price_rows} = $i - 1;
163 unless ($form->{item} eq 'service') {
166 if ($form->{makemodel}) {
167 $query = qq|SELECT m.make, m.model FROM makemodel m | .
168 qq|WHERE m.parts_id = ?|;
169 @values = ($form->{id});
170 $sth = $dbh->prepare($query);
171 $sth->execute(@values) || $form->dberror("$query (" . join(', ', @values) . ")");
174 while (($form->{"make_$i"}, $form->{"model_$i"}) = $sth->fetchrow_array)
179 $form->{makemodel_rows} = $i - 1;
185 $form->{language_values} = "";
186 $query = qq|SELECT language_id, translation FROM translation WHERE parts_id = ?|;
187 my $trq = prepare_execute_query($form, $dbh, $query, conv_i($form->{id}));
188 while ($tr = $trq->fetchrow_hashref(NAME_lc)) {
189 $form->{language_values} .= "---+++---".$tr->{language_id}."--++--".$tr->{translation};
193 # now get accno for taxes
196 FROM chart c, partstax pt
197 WHERE (pt.chart_id = c.id) AND (pt.parts_id = ?)|;
198 $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{id}));
199 while (($key) = $sth->fetchrow_array) {
200 $form->{amount}{$key} = $key;
209 WHERE (i.parts_id = ?)
215 WHERE (o.parts_id = ?)
221 WHERE (a.parts_id = ?)|;
222 @values = (conv_i($form->{id}), conv_i($form->{id}), conv_i($form->{id}));
223 ($form->{orphaned}) = selectrow_query($form, $dbh, $query, @values);
224 $form->{orphaned} = !$form->{orphaned};
226 $form->{"unit_changeable"} = 1;
227 foreach my $table (qw(invoice assembly orderitems inventory license)) {
228 $query = qq|SELECT COUNT(*) FROM $table WHERE parts_id = ?|;
229 my ($count) = selectrow_query($form, $dbh, $query, conv_i($form->{"id"}));
232 $form->{"unit_changeable"} = 0;
239 $main::lxdebug->leave_sub();
242 sub get_pricegroups {
243 $main::lxdebug->enter_sub();
245 my ($self, $myconfig, $form) = @_;
247 my $dbh = $form->dbconnect($myconfig);
250 my $query = qq|SELECT id, pricegroup FROM pricegroup|;
251 my $pricegroups = selectall_hashref_query($form, $dbh, $query);
254 foreach $pg (@{ $pricegroups }) {
255 $form->{"klass_$i"} = "$pg->{id}";
256 $form->{"price_$i"} = $form->format_amount($myconfig, $form->{"price_$i"}, -2);
257 $form->{"pricegroup_id_$i"} = "$pg->{id}";
258 $form->{"pricegroup_$i"} = "$pg->{pricegroup}";
263 $form->{price_rows} = $i - 1;
267 $main::lxdebug->leave_sub();
270 sub retrieve_buchungsgruppen {
271 $main::lxdebug->enter_sub();
273 my ($self, $myconfig, $form) = @_;
277 my $dbh = $form->dbconnect($myconfig);
279 # get buchungsgruppen
280 $query = qq|SELECT id, description FROM buchungsgruppen ORDER BY sortkey|;
281 $form->{BUCHUNGSGRUPPEN} = selectall_hashref_query($form, $dbh, $query);
283 $main::lxdebug->leave_sub();
287 $main::lxdebug->enter_sub();
289 my ($self, $myconfig, $form) = @_;
291 # connect to database, turn off AutoCommit
292 my $dbh = $form->dbconnect_noauto($myconfig);
295 # make up a unique handle and store in partnumber field
296 # then retrieve the record based on the unique handle to get the id
297 # replace the partnumber field with the actual variable
298 # add records for makemodel
300 # if there is a $form->{id} then replace the old entry
301 # delete all makemodel entries and add the new ones
303 # undo amount formatting
304 map { $form->{$_} = $form->parse_amount($myconfig, $form->{$_}) }
305 qw(rop weight listprice sellprice gv lastcost stock);
307 my $makemodel = (($form->{make_1}) || ($form->{model_1})) ? 1 : 0;
309 $form->{assembly} = ($form->{item} eq 'assembly') ? 1 : 0;
316 $query = qq|SELECT sellprice, weight FROM parts WHERE id = ?|;
317 my ($sellprice, $weight) = selectrow_query($form, $dbh, $query, conv_i($form->{id}));
319 # if item is part of an assembly adjust all assemblies
320 $query = qq|SELECT id, qty FROM assembly WHERE parts_id = ?|;
321 $sth = prepare_execute_query($form, $dbh, $query, conv_i($form->{id}));
322 while (my ($id, $qty) = $sth->fetchrow_array) {
323 &update_assembly($dbh, $form, $id, $qty, $sellprice * 1, $weight * 1);
327 if ($form->{item} ne 'service') {
328 # delete makemodel records
329 do_query($form, $dbh, qq|DELETE FROM makemodel WHERE parts_id = ?|, conv_i($form->{id}));
332 if ($form->{item} eq 'assembly') {
333 if ($form->{onhand} != 0) {
334 &adjust_inventory($dbh, $form, $form->{id}, $form->{onhand} * -1);
337 # delete assembly records
338 do_query($form, $dbh, qq|DELETE FROM assembly WHERE id = ?|, conv_i($form->{id}));
340 $form->{onhand} += $form->{stock};
344 do_query($form, $dbh, qq|DELETE FROM partstax WHERE parts_id = ?|, conv_i($form->{id}));
346 # delete translations
347 do_query($form, $dbh, qq|DELETE FROM translation WHERE parts_id = ?|, conv_i($form->{id}));
350 my ($count) = selectrow_query($form, $dbh, qq|SELECT COUNT(*) FROM parts WHERE partnumber = ?|, $form->{partnumber});
352 $main::lxdebug->leave_sub();
356 ($form->{id}) = selectrow_query($form, $dbh, qq|SELECT nextval('id')|);
357 do_query($form, $dbh, qq|INSERT INTO parts (id, partnumber) VALUES (?, '')|, $form->{id});
359 $form->{orphaned} = 1;
360 $form->{onhand} = $form->{stock} if $form->{item} eq 'assembly';
361 if ($form->{partnumber} eq "" && $form->{"item"} eq "service") {
362 $form->{partnumber} = $form->update_defaults($myconfig, "servicenumber");
364 if ($form->{partnumber} eq "" && $form->{"item"} ne "service") {
365 $form->{partnumber} = $form->update_defaults($myconfig, "articlenumber");
369 my $partsgroup_id = 0;
371 if ($form->{partsgroup}) {
372 ($partsgroup, $partsgroup_id) = split(/--/, $form->{partsgroup});
375 my ($subq_inventory, $subq_expense, $subq_income);
376 if ($form->{"item"} eq "part") {
378 qq|(SELECT bg.inventory_accno_id
379 FROM buchungsgruppen bg
380 WHERE bg.id = | . conv_i($form->{"buchungsgruppen_id"}, 'NULL') . qq|)|;
382 $subq_inventory = "NULL";
385 if ($form->{"item"} ne "assembly") {
387 qq|(SELECT bg.expense_accno_id_0
388 FROM buchungsgruppen bg
389 WHERE bg.id = | . conv_i($form->{"buchungsgruppen_id"}, 'NULL') . qq|)|;
391 $subq_expense = "NULL";
411 buchungsgruppen_id = ?,
413 inventory_accno_id = $subq_inventory,
414 income_accno_id = (SELECT bg.income_accno_id_0 FROM buchungsgruppen bg WHERE bg.id = ?),
415 expense_accno_id = $subq_expense,
423 not_discountable = ?,
427 @values = ($form->{partnumber},
428 $form->{description},
429 $makemodel ? 't' : 'f',
430 $form->{assembly} ? 't' : 'f',
435 conv_date($form->{priceupdate}),
441 conv_i($form->{buchungsgruppen_id}),
442 conv_i($form->{payment_id}),
443 conv_i($form->{buchungsgruppen_id}),
444 $form->{obsolete} ? 't' : 'f',
447 $form->{shop} ? 't' : 'f',
451 $form->{not_discountable} ? 't' : 'f',
453 conv_i($partsgroup_id),
456 do_query($form, $dbh, $query, @values);
458 # delete translation records
459 do_query($form, $dbh, qq|DELETE FROM translation WHERE parts_id = ?|, conv_i($form->{id}));
461 if ($form->{language_values} ne "") {
462 foreach $item (split(/---\+\+\+---/, $form->{language_values})) {
463 my ($language_id, $translation, $longdescription) = split(/--\+\+--/, $item);
464 if ($translation ne "") {
465 $query = qq|INSERT into translation (parts_id, language_id, translation, longdescription)
466 VALUES ( ?, ?, ?, ? )|;
467 @values = (conv_i($form->{id}), conv_i($language_id), $translation, $longdescription);
468 do_query($form, $dbh, $query, @values);
473 # delete price records
474 do_query($form, $dbh, qq|DELETE FROM prices WHERE parts_id = ?|, conv_i($form->{id}));
476 # insert price records only if different to sellprice
477 for my $i (1 .. $form->{price_rows}) {
478 if ($form->{"price_$i"} eq "0") {
479 $form->{"price_$i"} = $form->{sellprice};
482 ( $form->{"price_$i"}
483 || $form->{"klass_$i"}
484 || $form->{"pricegroup_id_$i"})
485 and $form->{"price_$i"} != $form->{sellprice}
487 #$klass = $form->parse_amount($myconfig, $form->{"klass_$i"});
488 $price = $form->parse_amount($myconfig, $form->{"price_$i"});
490 $form->parse_amount($myconfig, $form->{"pricegroup_id_$i"});
491 $query = qq|INSERT INTO prices (parts_id, pricegroup_id, price) | .
493 @values = (conv_i($form->{id}), conv_i($pricegroup_id), $price);
494 do_query($form, $dbh, $query, @values);
498 # insert makemodel records
499 unless ($form->{item} eq 'service') {
500 for my $i (1 .. $form->{makemodel_rows}) {
501 if (($form->{"make_$i"}) || ($form->{"model_$i"})) {
502 map { $form->{"${_}_$i"} =~ s/\'/\'\'/g } qw(make model);
504 $query = qq|INSERT INTO makemodel (parts_id, make, model) | .
505 qq|VALUES (?, ?, ?)|;
506 @values = (conv_i($form->{id}), $form->{"make_$i"}, $form->{"model_$i"});
507 do_query($form, $dbh, $query, @values);
513 foreach $item (split(/ /, $form->{taxaccounts})) {
514 if ($form->{"IC_tax_$item"}) {
516 qq|INSERT INTO partstax (parts_id, chart_id)
517 VALUES (?, (SELECT id FROM chart WHERE accno = ?))|;
518 @values = (conv_i($form->{id}), $item);
519 do_query($form, $dbh, $query, @values);
523 # add assembly records
524 if ($form->{item} eq 'assembly') {
526 for my $i (1 .. $form->{assembly_rows}) {
527 $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
529 if ($form->{"qty_$i"} != 0) {
530 $form->{"bom_$i"} *= 1;
531 $query = qq|INSERT INTO assembly (id, parts_id, qty, bom) | .
532 qq|VALUES (?, ?, ?, ?)|;
533 @values = (conv_i($form->{id}), conv_i($form->{"id_$i"}), conv_i($form->{"qty_$i"}), $form->{"bom_$i"} ? 't' : 'f');
534 do_query($form, $dbh, $query, @values);
538 # adjust onhand for the parts
539 if ($form->{onhand} != 0) {
540 &adjust_inventory($dbh, $form, $form->{id}, $form->{onhand});
546 my $shippingdate = "$a[5]-$a[4]-$a[3]";
548 $form->get_employee($dbh);
550 # add inventory record
552 qq|INSERT INTO inventory (warehouse_id, parts_id, qty, shippingdate, employee_id)
553 VALUES (0, ?, ?, '$shippingdate', ?)|;
554 @values = (conv_i($form->{id}), $form->{stock}, conv_i($form->{employee_id}));
555 do_query($form, $dbh, $query, @values);
559 #set expense_accno=inventory_accno if they are different => bilanz
561 ($form->{expense_accno} != $form->{inventory_accno})
562 ? $form->{inventory_accno}
563 : $form->{expense_accno};
565 # get tax rates and description
567 ($form->{vc} eq "customer") ? $form->{income_accno} : $vendor_accno;
569 qq|SELECT c.accno, c.description, t.rate, t.taxnumber
571 WHERE (c.id = t.chart_id) AND (t.taxkey IN (SELECT taxkey_id FROM chart where accno = ?))
573 $stw = prepare_execute_query($form, $dbh, $query, $accno_id);
575 $form->{taxaccount} = "";
576 while ($ptr = $stw->fetchrow_hashref(NAME_lc)) {
577 $form->{taxaccount} .= "$ptr->{accno} ";
578 if (!($form->{taxaccount2} =~ /$ptr->{accno}/)) {
579 $form->{"$ptr->{accno}_rate"} = $ptr->{rate};
580 $form->{"$ptr->{accno}_description"} = $ptr->{description};
581 $form->{"$ptr->{accno}_taxnumber"} = $ptr->{taxnumber};
582 $form->{taxaccount2} .= " $ptr->{accno} ";
587 my $rc = $dbh->commit;
590 $main::lxdebug->leave_sub();
595 sub update_assembly {
596 $main::lxdebug->enter_sub();
598 my ($dbh, $form, $id, $qty, $sellprice, $weight) = @_;
600 my $query = qq|SELECT id, qty FROM assembly WHERE parts_id = ?|;
601 my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
603 while (my ($pid, $aqty) = $sth->fetchrow_array) {
604 &update_assembly($dbh, $form, $pid, $aqty * $qty, $sellprice, $weight);
609 qq|UPDATE parts SET sellprice = sellprice + ?, weight = weight + ?
611 @values = ($qty * ($form->{sellprice} - $sellprice),
612 $qty * ($form->{weight} - $weight), conv_i($id));
613 do_query($form, $dbh, $query, @values);
615 $main::lxdebug->leave_sub();
618 sub retrieve_assemblies {
619 $main::lxdebug->enter_sub();
621 my ($self, $myconfig, $form) = @_;
623 # connect to database
624 my $dbh = $form->dbconnect($myconfig);
626 my $where = qq|NOT p.obsolete|;
629 if ($form->{partnumber}) {
630 $where .= qq| AND (p.partnumber ILIKE ?)|;
631 push(@values, '%' . $form->{partnumber} . '%');
634 if ($form->{description}) {
635 $where .= qq| AND (p.description ILIKE ?)|;
636 push(@values, '%' . $form->{description} . '%');
639 # retrieve assembly items
641 qq|SELECT p.id, p.partnumber, p.description,
642 p.bin, p.onhand, p.rop,
643 (SELECT sum(p2.inventory_accno_id)
644 FROM parts p2, assembly a
645 WHERE (p2.id = a.parts_id) AND (a.id = p.id)) AS inventory
647 WHERE NOT p.obsolete AND p.assembly $where|;
649 $form->{assembly_items} = selectall_hashref_query($form, $dbh, $query, @values);
653 $main::lxdebug->leave_sub();
656 sub restock_assemblies {
657 $main::lxdebug->enter_sub();
659 my ($self, $myconfig, $form) = @_;
661 # connect to database
662 my $dbh = $form->dbconnect_noauto($myconfig);
664 for my $i (1 .. $form->{rowcount}) {
666 $form->{"qty_$i"} = $form->parse_amount($myconfig, $form->{"qty_$i"});
668 if ($form->{"qty_$i"} != 0) {
669 &adjust_inventory($dbh, $form, $form->{"id_$i"}, $form->{"qty_$i"});
674 my $rc = $dbh->commit;
677 $main::lxdebug->leave_sub();
682 sub adjust_inventory {
683 $main::lxdebug->enter_sub();
685 my ($dbh, $form, $id, $qty) = @_;
688 qq|SELECT p.id, p.inventory_accno_id, p.assembly, a.qty
689 FROM parts p, assembly a
690 WHERE (a.parts_id = p.id) AND (a.id = ?)|;
691 my $sth = prepare_execute_query($form, $dbh, $query, conv_i($id));
693 while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
695 my $allocate = $qty * $ref->{qty};
697 # is it a service item, then loop
698 $ref->{inventory_accno_id} *= 1;
699 next if (($ref->{inventory_accno_id} == 0) && !$ref->{assembly});
701 # adjust parts onhand
702 $form->update_balance($dbh, "parts", "onhand",
710 my $rc = $form->update_balance($dbh, "parts", "onhand", qq|id = ?|, $qty, $id);
712 $main::lxdebug->leave_sub();
718 $main::lxdebug->enter_sub();
720 my ($self, $myconfig, $form) = @_;
721 my @values = (conv_i($form->{id}));
722 # connect to database, turn off AutoCommit
723 my $dbh = $form->dbconnect_noauto($myconfig);
725 my %columns = ( "assembly" => "id", "alternate" => "id", "parts" => "id" );
727 for my $table (qw(prices partstax makemodel inventory assembly parts)) {
728 my $column = defined($columns{$table}) ? $columns{$table} : "parts_id";
729 do_query($form, $dbh, qq|DELETE FROM $table WHERE $column = ?|, @values);
733 my $rc = $dbh->commit;
736 $main::lxdebug->leave_sub();
742 $main::lxdebug->enter_sub();
744 my ($self, $myconfig, $form) = @_;
746 my $i = $form->{assembly_rows};
748 my $where = qq|1 = 1|;
751 my %columns = ("partnumber" => "p", "description" => "p", "partsgroup" => "pg");
753 while (my ($column, $table) = each(%columns)) {
754 next unless ($form->{"${column}_$i"});
755 $where .= qq| AND ${table}.${column} ILIKE ?|;
756 push(@values, '%' . $form->{"${column}_$i"} . '%');
760 $where .= qq| AND NOT (p.id = ?)|;
761 push(@values, conv_i($form->{id}));
765 $where .= qq| ORDER BY p.partnumber|;
767 $where .= qq| ORDER BY p.description|;
770 # connect to database
771 my $dbh = $form->dbconnect($myconfig);
774 qq|SELECT p.id, p.partnumber, p.description, p.sellprice, p.weight, p.onhand, p.unit, pg.partsgroup
776 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
778 $form->{item_list} = selectall_hashref_query($form, $dbh, $query, @values);
782 $main::lxdebug->leave_sub();
786 $main::lxdebug->enter_sub();
788 my ($self, $myconfig, $form) = @_;
790 my $where = qq|1 = 1|;
791 my (@values, $var, $flds, $group, $limit);
793 foreach my $item (qw(partnumber drawing microfiche ean pg.partsgroup)) {
796 if ($form->{$column}) {
797 $where .= qq| AND (${item} ILIKE ?)|;
798 push(@values, '%' . $form->{$column} . '%');
802 # special case for description
803 if ($form->{description}
804 && !( $form->{bought} || $form->{sold} || $form->{onorder}
805 || $form->{ordered} || $form->{rfq} || $form->{quoted})) {
806 $where .= qq| AND (p.description ILIKE ?)|;
807 push(@values, '%' . $form->{description} . '%');
810 # special case for serialnumber
811 if ($form->{l_serialnumber} && $form->{serialnumber}) {
812 $where .= qq| AND (p.serialnumber ILIKE ?)|;
813 push(@values, '%' . $form->{serialnumber} . '%');
816 if ($form->{searchitems} eq 'part') {
817 $where .= qq| AND (p.inventory_accno_id > 0) |;
820 if ($form->{searchitems} eq 'assembly') {
821 $form->{bought} = "";
822 $where .= qq| AND p.assembly|;
825 if ($form->{searchitems} eq 'service') {
826 $where .= qq| AND (p.inventory_accno_id IS NULL) AND NOT (p.assembly = '1')|;
828 # irrelevant for services
829 $form->{make} = $form->{model} = "";
832 # items which were never bought, sold or on an order
833 if ($form->{itemstatus} eq 'orphaned') {
834 $form->{onhand} = $form->{short} = 0;
835 $form->{bought} = $form->{sold} = 0;
836 $form->{onorder} = $form->{ordered} = 0;
837 $form->{rfq} = $form->{quoted} = 0;
839 $form->{transdatefrom} = $form->{transdateto} = "";
842 qq| AND (p.onhand = 0)
845 SELECT DISTINCT parts_id FROM invoice
847 SELECT DISTINCT parts_id FROM assembly
849 SELECT DISTINCT parts_id FROM orderitems
853 if ($form->{itemstatus} eq 'active') {
854 $where .= qq| AND (p.obsolete = '0')|;
855 } elsif ($form->{itemstatus} eq 'obsolete') {
856 $where .= qq| AND (p.obsolete = '1')|;
857 $form->{onhand} = $form->{short} = 0;
858 } elsif ($form->{itemstatus} eq 'onhand') {
859 $where .= qq| AND (p.onhand > 0)|;
860 } elsif ($form->{itemstatus} eq 'short') {
861 $where .= qq| AND (p.onhand < p.rop)|;
864 foreach my $column (qw(make model)) {
865 next unless ($form->{$column});
866 $where .= qq| AND p.id IN (SELECT DISTINCT m.parts_id FROM makemodel WHERE $column ILIKE ?)|;
867 push(@values, '%' . $form->{$column} . '%');
870 if ($form->{l_soldtotal}) {
871 $where .= qq| AND (p.id = i.parts_id) AND (i.qty >= 0)|;
873 qq| GROUP BY p.id, p.partnumber, p.description, p.onhand, p.unit, p.bin, p.sellprice, p.listprice, p.lastcost, p.priceupdate, pg.partsgroup|;
876 $limit = qq| LIMIT 100| if ($form->{top100});
878 # connect to database
879 my $dbh = $form->dbconnect($myconfig);
881 my @sort_cols = qw(id partnumber description partsgroup bin priceupdate onhand
882 invnumber ordnumber quonumber name drawing microfiche
883 serialnumber soldtotal deliverydate);
885 my $sortorder = "partnumber";
886 $sortorder = $form->{sort} if ($form->{sort} && grep({ $_ eq $form->{sort} } @sort_cols));
887 $sortorder .= " DESC" if ($form->{revers});
891 if ($form->{l_soldtotal}) {
892 $form->{soldtotal} = 'soldtotal';
894 qq|SELECT p.id, p.partnumber, p.description, p.onhand, p.unit, p.bin, p.sellprice, p.listprice,
895 p.lastcost, p.priceupdate, pg.partsgroup,sum(i.qty) AS soldtotal FROM parts
896 p LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id), invoice i
903 qq|SELECT p.id, p.partnumber, p.description, p.onhand, p.unit,
904 p.bin, p.sellprice, p.listprice, p.lastcost, p.rop, p.weight,
905 p.priceupdate, p.image, p.drawing, p.microfiche,
908 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
915 my @all_values = @values;
917 # rebuild query for bought and sold items
923 || $form->{quoted}) {
928 if ($form->{bought} || $form->{sold}) {
930 my @invvalues = @values;
931 my $invwhere = "$where";
932 $invwhere .= qq| AND i.assemblyitem = '0'|;
934 if ($form->{transdatefrom}) {
935 $invwhere .= qq| AND a.transdate >= ?|;
936 push(@invvalues, $form->{transdatefrom});
939 if ($form->{transdateto}) {
940 $invwhere .= qq| AND a.transdate <= ?|;
941 push(@invvalues, $form->{transdateto});
944 if ($form->{description}) {
945 $invwhere .= qq| AND i.description ILIKE ?|;
946 push(@invvalues, '%' . $form->{description} . '%');
950 qq|p.id, p.partnumber, i.description, i.serialnumber,
951 i.qty AS onhand, i.unit, p.bin, i.sellprice,
952 p.listprice, p.lastcost, p.rop, p.weight,
953 p.priceupdate, p.image, p.drawing, p.microfiche,
955 a.invnumber, a.ordnumber, a.quonumber, i.trans_id,
956 ct.name, i.deliverydate|;
958 if ($form->{bought}) {
960 qq|SELECT $flds, 'ir' AS module, '' AS type, 1 AS exchangerate
962 JOIN parts p ON (p.id = i.parts_id)
963 JOIN ap a ON (a.id = i.trans_id)
964 JOIN vendor ct ON (a.vendor_id = ct.id)
965 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
968 $union = qq| UNION |;
970 push(@all_values, @invvalues);
977 SELECT $flds, 'is' AS module, '' AS type, 1 As exchangerate
979 JOIN parts p ON (p.id = i.parts_id)
980 JOIN ar a ON (a.id = i.trans_id)
981 JOIN customer ct ON (a.customer_id = ct.id)
982 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
984 $union = qq| UNION |;
986 push(@all_values, @invvalues);
990 if ($form->{onorder} || $form->{ordered}) {
991 my @ordvalues = @values;
992 my $ordwhere = $where . qq| AND o.quotation = '0'|;
994 if ($form->{transdatefrom}) {
995 $ordwhere .= qq| AND o.transdate >= ?|;
996 push(@ordvalues, $form->{transdatefrom});
999 if ($form->{transdateto}) {
1000 $ordwhere .= qq| AND o.transdate <= ?|;
1001 push(@ordvalues, $form->{transdateto});
1004 if ($form->{description}) {
1005 $ordwhere .= qq| AND oi.description ILIKE ?|;
1006 push(@ordvalues, '%' . $form->{description} . '%');
1009 if ($form->{ordered}) {
1013 SELECT p.id, p.partnumber, oi.description, oi.serialnumber AS serialnumber,
1014 oi.qty AS onhand, oi.unit, p.bin, oi.sellprice,
1015 p.listprice, p.lastcost, p.rop, p.weight,
1016 p.priceupdate, p.image, p.drawing, p.microfiche,
1018 '' AS invnumber, o.ordnumber, o.quonumber, oi.trans_id,
1019 ct.name, NULL AS deliverydate,
1020 'oe' AS module, 'sales_order' AS type,
1021 (SELECT buy FROM exchangerate ex
1022 WHERE ex.curr = o.curr AND ex.transdate = o.transdate) AS exchangerate
1024 JOIN parts p ON (oi.parts_id = p.id)
1025 JOIN oe o ON (oi.trans_id = o.id)
1026 JOIN customer ct ON (o.customer_id = ct.id)
1027 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
1028 WHERE $ordwhere AND (o.customer_id > 0)|;
1029 $union = qq| UNION |;
1031 push(@all_values, @ordvalues);
1034 if ($form->{onorder}) {
1038 SELECT p.id, p.partnumber, oi.description, oi.serialnumber AS serialnumber,
1039 oi.qty * -1 AS onhand, oi.unit, p.bin, oi.sellprice,
1040 p.listprice, p.lastcost, p.rop, p.weight,
1041 p.priceupdate, p.image, p.drawing, p.microfiche,
1043 '' AS invnumber, o.ordnumber, o.quonumber, oi.trans_id,
1044 ct.name, NULL AS deliverydate,
1045 'oe' AS module, 'purchase_order' AS type,
1046 (SELECT sell FROM exchangerate ex
1047 WHERE ex.curr = o.curr AND (ex.transdate = o.transdate)) AS exchangerate
1049 JOIN parts p ON (oi.parts_id = p.id)
1050 JOIN oe o ON (oi.trans_id = o.id)
1051 JOIN vendor ct ON (o.vendor_id = ct.id)
1052 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
1053 WHERE $ordwhere AND (o.vendor_id > 0)|;
1054 $union = qq| UNION |;
1056 push(@all_values, @ordvalues);
1061 if ($form->{rfq} || $form->{quoted}) {
1062 my $quowhere = $where . qq| AND o.quotation = '1'|;
1063 my @quovalues = @values;
1065 if ($form->{transdatefrom}) {
1066 $quowhere .= qq| AND o.transdate >= ?|;
1067 push(@quovalues, $form->{transdatefrom});
1070 if ($form->{transdateto}) {
1071 $quowhere .= qq| AND o.transdate <= ?|;
1072 push(@quovalues, $form->{transdateto});
1075 if ($form->{description}) {
1076 $quowhere .= qq| AND oi.description ILIKE ?|;
1077 push(@quovalues, '%' . $form->{description} . '%');
1080 if ($form->{quoted}) {
1085 p.id, p.partnumber, oi.description, oi.serialnumber AS serialnumber,
1086 oi.qty AS onhand, oi.unit, p.bin, oi.sellprice,
1087 p.listprice, p.lastcost, p.rop, p.weight,
1088 p.priceupdate, p.image, p.drawing, p.microfiche,
1090 '' AS invnumber, o.ordnumber, o.quonumber, oi.trans_id,
1091 ct.name, NULL AS deliverydate, 'oe' AS module, 'sales_quotation' AS type,
1092 (SELECT buy FROM exchangerate ex
1093 WHERE (ex.curr = o.curr) AND (ex.transdate = o.transdate)) AS exchangerate
1095 JOIN parts p ON (oi.parts_id = p.id)
1096 JOIN oe o ON (oi.trans_id = o.id)
1097 JOIN customer ct ON (o.customer_id = ct.id)
1098 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
1100 AND o.customer_id > 0|;
1101 $union = qq| UNION |;
1103 push(@all_values, @quovalues);
1110 SELECT p.id, p.partnumber, oi.description, oi.serialnumber AS serialnumber,
1111 oi.qty * -1 AS onhand, oi.unit, p.bin, oi.sellprice,
1112 p.listprice, p.lastcost, p.rop, p.weight,
1113 p.priceupdate, p.image, p.drawing, p.microfiche,
1115 '' AS invnumber, o.ordnumber, o.quonumber, oi.trans_id,
1116 ct.name, NULL AS deliverydate,
1117 'oe' AS module, 'request_quotation' AS type,
1118 (SELECT sell FROM exchangerate ex
1119 WHERE (ex.curr = o.curr) AND (ex.transdate = o.transdate)) AS exchangerate
1121 JOIN parts p ON (oi.parts_id = p.id)
1122 JOIN oe o ON (oi.trans_id = o.id)
1123 JOIN vendor ct ON (o.vendor_id = ct.id)
1124 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
1126 AND o.vendor_id > 0|;
1128 push(@all_values, @quovalues);
1132 $query .= qq| ORDER BY | . $sortorder;
1136 $form->{parts} = selectall_hashref_query($form, $dbh, $query, @all_values);
1139 # include individual items for assemblies
1140 if ($form->{searchitems} eq 'assembly' && $form->{bom}) {
1142 qq|SELECT p.id, p.partnumber, p.description, a.qty AS onhand,
1144 p.sellprice, p.listprice, p.lastcost,
1145 p.rop, p.weight, p.priceupdate,
1146 p.image, p.drawing, p.microfiche
1147 FROM parts p, assembly a
1148 WHERE (p.id = a.parts_id) AND (a.id = ?)|;
1149 $sth = prepare_query($form, $dbh, $query);
1151 foreach $item (@{ $form->{parts} }) {
1152 push(@assemblies, $item);
1153 do_statement($form, $sth, $query, conv_i($item->{id}));
1155 while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1156 $ref->{assemblyitem} = 1;
1157 push(@assemblies, $ref);
1161 push(@assemblies, { id => $item->{id} });
1165 # copy assemblies to $form->{parts}
1166 $form->{parts} = \@assemblies;
1170 $main::lxdebug->leave_sub();
1174 $main::lxdebug->enter_sub();
1176 my ($self, $myconfig, $form) = @_;
1178 my $where = '1 = 1';
1186 if ($item ne 'make') {
1187 foreach my $item (qw(partnumber drawing microfiche make model pg.partsgroup)) {
1189 $column =~ s/.*\.//;
1190 next unless ($form->{$column});
1191 $where .= qq| AND $item ILIKE ?|;
1192 push(@where_values, '%' . $form->{$column} . '%');
1196 # special case for description
1197 if ($form->{description}
1198 && !( $form->{bought} || $form->{sold} || $form->{onorder}
1199 || $form->{ordered} || $form->{rfq} || $form->{quoted})) {
1200 $where .= qq| AND (p.description ILIKE ?)|;
1201 push(@where_values, '%' . $form->{description} . '%');
1204 # special case for serialnumber
1205 if ($form->{l_serialnumber} && $form->{serialnumber}) {
1206 $where .= qq| AND serialnumber ILIKE ?|;
1207 push(@where_values, '%' . $form->{serialnumber} . '%');
1211 # items which were never bought, sold or on an order
1212 if ($form->{itemstatus} eq 'orphaned') {
1213 $form->{onhand} = $form->{short} = 0;
1214 $form->{bought} = $form->{sold} = 0;
1215 $form->{onorder} = $form->{ordered} = 0;
1216 $form->{rfq} = $form->{quoted} = 0;
1218 $form->{transdatefrom} = $form->{transdateto} = "";
1221 qq| AND (p.onhand = 0)
1224 SELECT DISTINCT parts_id FROM invoice
1226 SELECT DISTINCT parts_id FROM assembly
1228 SELECT DISTINCT parts_id FROM orderitems
1232 if ($form->{itemstatus} eq 'active') {
1233 $where .= qq| AND p.obsolete = '0'|;
1236 if ($form->{itemstatus} eq 'obsolete') {
1237 $where .= qq| AND p.obsolete = '1'|;
1238 $form->{onhand} = $form->{short} = 0;
1241 if ($form->{itemstatus} eq 'onhand') {
1242 $where .= qq| AND p.onhand > 0|;
1245 if ($form->{itemstatus} eq 'short') {
1246 $where .= qq| AND p.onhand < p.rop|;
1249 foreach my $column (qw(make model)) {
1250 next unless ($form->{$colum});
1251 $where .= qq| AND p.id IN (SELECT DISTINCT parts_id FROM makemodel WHERE $column ILIKE ?|;
1252 push(@where_values, '%' . $form->{$column} . '%');
1255 # connect to database
1256 my $dbh = $form->dbconnect_noauto($myconfig);
1258 for my $column (qw(sellprice listprice)) {
1259 next if ($form->{$column} eq "");
1261 my $value = $form->parse_amount($myconfig, $form->{$column});
1264 if ($form->{"${column}_type"} eq "percent") {
1265 $value = ($value / 100) + 1;
1270 qq|UPDATE parts SET $column = $column $operator ?
1274 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
1276 do_query($from, $dbh, $query, $value, @where_values);
1280 qq|UPDATE prices SET price = price + ?
1284 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
1285 WHERE $where) AND (pricegroup_id = ?)|;
1286 my $sth_add = prepare_query($form, $dbh, $q_add);
1289 qq|UPDATE prices SET price = price * ?
1293 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
1294 WHERE $where) AND (pricegroup_id = ?)|;
1295 my $sth_multiply = prepare_query($form, $dbh, $q_multiply);
1297 for my $i (1 .. $form->{price_rows}) {
1298 next if ($form->{"price_$i"} eq "");
1300 my $value = $form->parse_amount($myconfig, $form->{"price_$i"});
1302 if ($form->{"pricegroup_type_$i"} eq "percent") {
1303 do_statement($form, $sth_multiply, $q_multiply, ($value / 100) + 1, @where_values, conv_i($form->{"pricegroup_id_$i"}));
1305 do_statement($form, $sth_add, $q_add, $value, @where_values, conv_i($form->{"pricegroup_id_$i"}));
1310 $sth_multiply->finish();
1312 my $rc= $dbh->commit;
1315 $main::lxdebug->leave_sub();
1321 $main::lxdebug->enter_sub();
1323 my ($self, $module, $myconfig, $form) = @_;
1325 # connect to database
1326 my $dbh = $form->dbconnect($myconfig);
1328 my @values = ('%' . $module . '%');
1332 qq|SELECT c.accno, c.description, c.link, c.id,
1333 p.inventory_accno_id, p.income_accno_id, p.expense_accno_id
1334 FROM chart c, parts p
1335 WHERE (c.link LIKE ?) AND (p.id = ?)
1337 push(@values, conv_i($form->{id}));
1341 qq|SELECT c.accno, c.description, c.link, c.id,
1342 d.inventory_accno_id, d.income_accno_id, d.expense_accno_id
1343 FROM chart c, defaults d
1348 my $sth = prepare_execute_query($form, $dbh, $query, @values);
1349 while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1350 foreach my $key (split(/:/, $ref->{link})) {
1351 if ($key =~ /$module/) {
1352 if ( ($ref->{id} eq $ref->{inventory_accno_id})
1353 || ($ref->{id} eq $ref->{income_accno_id})
1354 || ($ref->{id} eq $ref->{expense_accno_id})) {
1355 push @{ $form->{"${module}_links"}{$key} },
1356 { accno => $ref->{accno},
1357 description => $ref->{description},
1358 selected => "selected" };
1359 $form->{"${key}_default"} = "$ref->{accno}--$ref->{description}";
1361 push @{ $form->{"${module}_links"}{$key} },
1362 { accno => $ref->{accno},
1363 description => $ref->{description},
1371 # get buchungsgruppen
1372 $form->{BUCHUNGSGRUPPEN} = selectall_hashref_query($form, $dbh, qq|SELECT id, description FROM buchungsgruppen|);
1375 $form->{payment_terms} = selectall_hashref_query($form, $dbh, qq|SELECT id, description FROM payment_terms ORDER BY sortkey|);
1378 ($form->{priceupdate}) = selectrow_query($form, $dbh, qq|SELECT current_date|);
1382 $main::lxdebug->leave_sub();
1385 # get partnumber, description, unit, sellprice and soldtotal with choice through $sortorder for Top100
1387 $main::lxdebug->enter_sub();
1389 my ($self, $myconfig, $form, $sortorder) = @_;
1390 my $dbh = $form->dbconnect($myconfig);
1391 my $order = qq| p.partnumber|;
1392 my $where = qq|1 = 1|;
1395 if ($sortorder eq "all") {
1396 $where .= qq| AND (partnumber ILIKE ?) AND (description ILIKE ?)|;
1397 push(@values, '%' . $form->{partnumber} . '%', '%' . $form->{description} . '%');
1399 } elsif ($sortorder eq "partnumber") {
1400 $where .= qq| AND (partnumber ILIKE ?)|;
1401 push(@values, '%' . $form->{partnumber} . '%');
1403 } elsif ($sortorder eq "description") {
1404 $where .= qq| AND (description ILIKE ?)|;
1405 push(@values, '%' . $form->{description} . '%');
1406 $order = "description";
1411 qq|SELECT id, partnumber, description, unit, sellprice
1413 WHERE $where ORDER BY $order|;
1415 my $sth = prepare_execute_query($form, $dbh, $query, @values);
1418 while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1419 if (($ref->{partnumber} eq "*") && ($ref->{description} eq "")) {
1424 $form->{"id_$j"} = $ref->{id};
1425 $form->{"partnumber_$j"} = $ref->{partnumber};
1426 $form->{"description_$j"} = $ref->{description};
1427 $form->{"unit_$j"} = $ref->{unit};
1428 $form->{"sellprice_$j"} = $ref->{sellprice};
1429 $form->{"soldtotal_$j"} = get_soldtotal($dbh, $ref->{id});
1435 $main::lxdebug->leave_sub();
1440 # gets sum of sold part with part_id
1442 $main::lxdebug->enter_sub();
1444 my ($dbh, $id) = @_;
1446 my $query = qq|SELECT sum(qty) FROM invoice WHERE parts_id = ?|;
1447 my ($sum) = selectrow_query($form, $dbh, $query, conv_i($id));
1450 $main::lxdebug->leave_sub();
1453 } #end get_soldtotal
1455 sub retrieve_languages {
1456 $main::lxdebug->enter_sub();
1458 my ($self, $myconfig, $form) = @_;
1460 # connect to database
1461 my $dbh = $form->dbconnect($myconfig);
1466 if ($form->{language_values} ne "") {
1468 qq|SELECT l.id, l.description, tr.translation, tr.longdescription
1470 LEFT OUTER JOIN translation tr ON (tr.language_id = l.id) AND (tr.parts_id = ?)|;
1471 @values = (conv_i($form->{id}));
1474 $query = qq|SELECT id, description FROM language|;
1477 my $languages = selectall_hashref_query($form, $dbh, $query, @values);
1481 $main::lxdebug->leave_sub();
1486 sub follow_account_chain {
1487 $main::lxdebug->enter_sub(2);
1489 my ($self, $form, $dbh, $transdate, $accno_id, $accno) = @_;
1491 my @visited_accno_ids = ($accno_id);
1496 qq|SELECT c.new_chart_id, date($transdate) >= c.valid_from AS is_valid, | .
1499 qq|LEFT JOIN chart cnew ON c.new_chart_id = cnew.id | .
1500 qq|WHERE (c.id = ?) AND NOT c.new_chart_id ISNULL AND (c.new_chart_id > 0)|;
1501 $sth = prepare_query($form, $dbh, $query);
1504 do_statement($form, $sth, $query, $accno_id);
1505 $ref = $sth->fetchrow_hashref();
1506 last unless ($ref && $ref->{"is_valid"} &&
1507 !grep({ $_ == $ref->{"new_chart_id"} } @visited_accno_ids));
1508 $accno_id = $ref->{"new_chart_id"};
1509 $accno = $ref->{"accno"};
1510 push(@visited_accno_ids, $accno_id);
1513 $main::lxdebug->leave_sub(2);
1515 return ($accno_id, $accno);
1518 sub retrieve_accounts {
1519 $main::lxdebug->enter_sub(2);
1521 my ($self, $myconfig, $form, $parts_id, $index, $copy_accnos) = @_;
1523 my ($query, $sth, $dbh);
1525 $form->{"taxzone_id"} *= 1;
1527 $dbh = $form->dbconnect($myconfig);
1530 if ($form->{type} eq "invoice") {
1531 if (($form->{vc} eq "vendor") || !$form->{deliverydate}) {
1532 $transdate = $form->{invdate};
1534 $transdate = $form->{deliverydate};
1536 } elsif ($form->{type} eq "credit_note") {
1537 $transdate = $form->{invdate};
1539 $transdate = $form->{transdate};
1542 if ($transdate eq "") {
1543 $transdate = "current_date";
1545 $transdate = $dbh->quote($transdate);
1550 qq| p.inventory_accno_id AS is_part, | .
1551 qq| bg.inventory_accno_id, | .
1552 qq| bg.income_accno_id_$form->{taxzone_id} AS income_accno_id, | .
1553 qq| bg.expense_accno_id_$form->{taxzone_id} AS expense_accno_id, | .
1554 qq| c1.accno AS inventory_accno, | .
1555 qq| c2.accno AS income_accno, | .
1556 qq| c3.accno AS expense_accno | .
1558 qq|LEFT JOIN buchungsgruppen bg ON p.buchungsgruppen_id = bg.id | .
1559 qq|LEFT JOIN chart c1 ON bg.inventory_accno_id = c1.id | .
1560 qq|LEFT JOIN chart c2 ON bg.income_accno_id_$form->{taxzone_id} = c2.id | .
1561 qq|LEFT JOIN chart c3 ON bg.expense_accno_id_$form->{taxzone_id} = c3.id | .
1563 my $ref = selectfirst_hashref_query($form, $dbh, $query, $parts_id);
1567 return $main::lxdebug->leave_sub(2);
1570 $ref->{"inventory_accno_id"} = undef unless ($ref->{"is_part"});
1573 foreach my $type (qw(inventory income expense)) {
1574 next unless ($ref->{"${type}_accno_id"});
1575 ($accounts{"${type}_accno_id"}, $accounts{"${type}_accno"}) =
1576 $self->follow_account_chain($form, $dbh, $transdate,
1577 $ref->{"${type}_accno_id"},
1578 $ref->{"${type}_accno"});
1581 map({ $form->{"${_}_accno_$index"} = $accounts{"${_}_accno"} }
1582 qw(inventory income expense));
1584 my $inc_exp = $form->{"vc"} eq "customer" ? "income" : "expense";
1585 my $accno_id = $accounts{"${inc_exp}_accno_id"};
1588 qq|SELECT c.accno, t.taxdescription AS description, t.rate, t.taxnumber | .
1590 qq|LEFT JOIN chart c ON c.id = t.chart_id | .
1591 qq|WHERE t.id IN | .
1592 qq| (SELECT tk.tax_id | .
1593 qq| FROM taxkeys tk | .
1594 qq| WHERE tk.chart_id = ? AND startdate <= | . quote_db_date($transdate) .
1595 qq| ORDER BY startdate DESC LIMIT 1) |;
1596 $ref = selectfirst_hashref_query($form, $dbh, $query, $accno_id);
1599 $main::lxdebug->leave_sub(2);
1603 $form->{"taxaccounts_$index"} = $ref->{"accno"};
1604 if ($form->{"taxaccounts"} !~ /$ref->{accno}/) {
1605 $form->{"taxaccounts"} .= "$ref->{accno} ";
1607 map({ $form->{"$ref->{accno}_${_}"} = $ref->{$_}; }
1608 qw(rate description taxnumber));
1610 # $main::lxdebug->message(0, "formvars: rate " . $form->{"$ref->{accno}_rate"} .
1611 # " description " . $form->{"$ref->{accno}_description"} .
1612 # " taxnumber " . $form->{"$ref->{accno}_taxnumber"} .
1613 # " || taxaccounts_$index " . $form->{"taxaccounts_$index"} .
1614 # " || taxaccounts " . $form->{"taxaccounts"});
1616 $main::lxdebug->leave_sub(2);