ff9fc46e23d89aa1e98ea436debe279db52dcac2
[kivitendo-erp.git] / SL / AM.pm
1 #=====================================================================
2 # LX-Office ERP
3 # Copyright (C) 2004
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
6 #
7 #=====================================================================
8 # SQL-Ledger Accounting
9 # Copyright (C) 2001
10 #
11 #  Author: Dieter Simader
12 #   Email: dsimader@sql-ledger.org
13 #     Web: http://www.sql-ledger.org
14 #
15 #  Contributors:
16 #
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.
21 #
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 #======================================================================
30 #
31 # Administration module
32 #    Chart of Accounts
33 #    template routines
34 #    preferences
35 #
36 #======================================================================
37
38 package AM;
39
40 use Carp;
41 use Data::Dumper;
42 use Encode;
43 use SL::DBUtils;
44
45 use strict;
46
47 sub get_account {
48   $main::lxdebug->enter_sub();
49
50   my ($self, $myconfig, $form) = @_;
51
52   # connect to database
53   my $dbh = $form->dbconnect($myconfig);
54   my $query = qq{
55     SELECT c.accno, c.description, c.charttype, c.category,
56       c.link, c.pos_bilanz, c.pos_eur, c.new_chart_id, c.valid_from,
57       c.pos_bwa, datevautomatik,
58       tk.taxkey_id, tk.pos_ustva, tk.tax_id,
59       tk.tax_id || '--' || tk.taxkey_id AS tax, tk.startdate
60     FROM chart c
61     LEFT JOIN taxkeys tk
62     ON (c.id=tk.chart_id AND tk.id =
63       (SELECT id FROM taxkeys
64        WHERE taxkeys.chart_id = c.id AND startdate <= current_date
65        ORDER BY startdate DESC LIMIT 1))
66     WHERE c.id = ?
67     };
68
69
70   $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query");
71   my $sth = $dbh->prepare($query);
72   $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})");
73
74   my $ref = $sth->fetchrow_hashref("NAME_lc");
75
76   foreach my $key (keys %$ref) {
77     $form->{"$key"} = $ref->{"$key"};
78   }
79
80   $sth->finish;
81
82   # get default accounts
83   $query = qq|SELECT inventory_accno_id, income_accno_id, expense_accno_id
84               FROM defaults|;
85   $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query");
86   $sth = $dbh->prepare($query);
87   $sth->execute || $form->dberror($query);
88
89   $ref = $sth->fetchrow_hashref("NAME_lc");
90
91   map { $form->{$_} = $ref->{$_} } keys %{ $ref };
92
93   $sth->finish;
94
95
96
97   # get taxkeys and description
98   $query = qq{
99     SELECT
100       id,
101       (SELECT accno FROM chart WHERE id=tax.chart_id) AS chart_accno,
102       taxkey,
103       id||'--'||taxkey AS tax,
104       taxdescription,
105       rate
106     FROM tax ORDER BY taxkey
107   };
108   $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query");
109   $sth = $dbh->prepare($query);
110   $sth->execute || $form->dberror($query);
111
112   $form->{TAXKEY} = [];
113
114   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
115     push @{ $form->{TAXKEY} }, $ref;
116   }
117
118   $sth->finish;
119   if ($form->{id}) {
120     # get new accounts
121     $query = qq|SELECT id, accno,description
122                 FROM chart
123                 WHERE link = ?
124                 ORDER BY accno|;
125     $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query");
126     $sth = $dbh->prepare($query);
127     $sth->execute($form->{link}) || $form->dberror($query . " ($form->{link})");
128
129     $form->{NEWACCOUNT} = [];
130     while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
131       push @{ $form->{NEWACCOUNT} }, $ref;
132     }
133
134     $sth->finish;
135
136     # get the taxkeys of account
137
138     $query = qq{
139       SELECT
140         tk.id,
141         tk.chart_id,
142         c.accno,
143         tk.tax_id,
144         t.taxdescription,
145         t.rate,
146         tk.taxkey_id,
147         tk.pos_ustva,
148         tk.startdate
149       FROM taxkeys tk
150       LEFT JOIN   tax t ON (t.id = tk.tax_id)
151       LEFT JOIN chart c ON (c.id = t.chart_id)
152
153       WHERE tk.chart_id = ?
154       ORDER BY startdate DESC
155     };
156     $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query");
157     $sth = $dbh->prepare($query);
158
159     $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})");
160
161     $form->{ACCOUNT_TAXKEYS} = [];
162
163     while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
164       push @{ $form->{ACCOUNT_TAXKEYS} }, $ref;
165     }
166
167     $sth->finish;
168
169   }
170   # check if we have any transactions
171   $query = qq|SELECT a.trans_id FROM acc_trans a
172               WHERE a.chart_id = ?|;
173   $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query");
174   $sth = $dbh->prepare($query);
175   $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})");
176
177   ($form->{orphaned}) = $sth->fetchrow_array;
178   $form->{orphaned} = !$form->{orphaned};
179   $sth->finish;
180
181   # check if new account is active
182   $form->{new_chart_valid} = 0;
183   if ($form->{new_chart_id}) {
184     $query = qq|SELECT current_date-valid_from FROM chart
185                 WHERE id = ?|;
186     $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query");
187     my ($count) = selectrow_query($form, $dbh, $query, $form->{id});
188     if ($count >=0) {
189       $form->{new_chart_valid} = 1;
190     }
191     $sth->finish;
192   }
193
194   $dbh->disconnect;
195
196   $main::lxdebug->leave_sub();
197 }
198
199 sub save_account {
200   $main::lxdebug->enter_sub();
201
202   # TODO: it should be forbidden to change an account to a heading if there
203   # have been bookings to this account in the past
204
205   my ($self, $myconfig, $form) = @_;
206
207   # connect to database, turn off AutoCommit
208   my $dbh = $form->dbconnect_noauto($myconfig);
209
210   # sanity check, can't have AR with AR_...
211   if ($form->{AR} || $form->{AP} || $form->{IC}) {
212     map { delete $form->{$_} }
213       qw(AR_amount AR_tax AR_paid AP_amount AP_tax AP_paid IC_sale IC_cogs IC_taxpart IC_income IC_expense IC_taxservice CT_tax);
214   }
215
216   $form->{link} = "";
217   foreach my $item ($form->{AR},            $form->{AR_amount},
218                     $form->{AR_tax},        $form->{AR_paid},
219                     $form->{AP},            $form->{AP_amount},
220                     $form->{AP_tax},        $form->{AP_paid},
221                     $form->{IC},            $form->{IC_sale},
222                     $form->{IC_cogs},       $form->{IC_taxpart},
223                     $form->{IC_income},     $form->{IC_expense},
224                     $form->{IC_taxservice}, $form->{CT_tax}
225     ) {
226     $form->{link} .= "${item}:" if ($item);
227   }
228   chop $form->{link};
229
230   # strip blanks from accno
231   map { $form->{$_} =~ s/ //g; } qw(accno);
232
233   my ($query, $sth);
234
235   if ($form->{id} eq "NULL") {
236     $form->{id} = "";
237   }
238
239   if (!$form->{id} || $form->{id} eq "") {
240     $query = qq|SELECT nextval('id')|;
241     ($form->{"id"}) = selectrow_query($form, $dbh, $query);
242     $query = qq|INSERT INTO chart (id, accno) VALUES (?, ?)|;
243     do_query($form, $dbh, $query, $form->{"id"}, $form->{"accno"});
244   }
245
246   my @values;
247
248
249   if ($form->{id}) {
250
251     # if charttype is heading make sure certain values are empty
252     # specifically, if charttype is changed from an existing account, empty the
253     # fields unnecessary for headings, so that e.g. heading doesn't appear in
254     # drop-down menues due to still having a valid "link" entry
255
256     if ( $form->{charttype} eq 'H' ) {
257       $form->{link} = '';
258       $form->{pos_bwa} = '';
259       $form->{pos_bilanz} = '';
260       $form->{pos_eur} = '';
261       $form->{new_chart_id} = '';
262       $form->{valid_from} = '';
263     };
264
265     $query = qq|UPDATE chart SET
266                   accno = ?,
267                   description = ?,
268                   charttype = ?,
269                   category = ?,
270                   link = ?,
271                   pos_bwa   = ?,
272                   pos_bilanz = ?,
273                   pos_eur = ?,
274                   new_chart_id = ?,
275                   valid_from = ?,
276                   datevautomatik = ?
277                 WHERE id = ?|;
278
279     @values = (
280                   $form->{accno},
281                   $form->{description},
282                   $form->{charttype},
283                   $form->{category},
284                   $form->{link},
285                   conv_i($form->{pos_bwa}),
286                   conv_i($form->{pos_bilanz}),
287                   conv_i($form->{pos_eur}),
288                   conv_i($form->{new_chart_id}),
289                   conv_date($form->{valid_from}),
290                   ($form->{datevautomatik} eq 'T') ? 'true':'false',
291                 $form->{id},
292     );
293
294
295   }
296
297   do_query($form, $dbh, $query, @values);
298
299   #Save Taxkeys
300
301   my @taxkeys = ();
302
303   my $MAX_TRIES = 10; # Maximum count of taxkeys in form
304   my $tk_count;
305
306   READTAXKEYS:
307   for $tk_count (0 .. $MAX_TRIES) {
308
309     # Loop control
310
311     # Check if the account already exists, else cancel
312
313     print(STDERR "Keine Taxkeys weil ID =: $form->{id}\n");
314
315     last READTAXKEYS if ( $form->{'id'} == 0);
316
317     # check if there is a startdate
318     if ( $form->{"taxkey_startdate_$tk_count"} eq '' ) {
319       $tk_count++;
320       next READTAXKEYS;
321     }
322
323     # Add valid taxkeys into the array
324     push @taxkeys ,
325       {
326         id        => ($form->{"taxkey_id_$tk_count"} eq 'NEW') ? conv_i('') : conv_i($form->{"taxkey_id_$tk_count"}),
327         tax_id    => conv_i($form->{"taxkey_tax_$tk_count"}),
328         startdate => conv_date($form->{"taxkey_startdate_$tk_count"}),
329         chart_id  => conv_i($form->{"id"}),
330         pos_ustva => conv_i($form->{"taxkey_pos_ustva_$tk_count"}),
331         delete    => ( $form->{"taxkey_del_$tk_count"} eq 'delete' ) ? '1' : '',
332       };
333
334     $tk_count++;
335   }
336
337   TAXKEY:
338   for my $j (0 .. $#taxkeys){
339     if ( defined $taxkeys[$j]{'id'} ){
340       # delete Taxkey?
341
342       if ($taxkeys[$j]{'delete'}){
343         $query = qq{
344           DELETE FROM taxkeys WHERE id = ?
345         };
346
347         @values = ($taxkeys[$j]{'id'});
348
349         do_query($form, $dbh, $query, @values);
350
351         next TAXKEY;
352       }
353
354       # UPDATE Taxkey
355
356       $query = qq{
357         UPDATE taxkeys
358         SET taxkey_id = (SELECT taxkey FROM tax WHERE tax.id = ?),
359             chart_id  = ?,
360             tax_id    = ?,
361             pos_ustva = ?,
362             startdate = ?
363         WHERE id = ?
364       };
365       @values = (
366         $taxkeys[$j]{'tax_id'},
367         $taxkeys[$j]{'chart_id'},
368         $taxkeys[$j]{'tax_id'},
369         $taxkeys[$j]{'pos_ustva'},
370         $taxkeys[$j]{'startdate'},
371         $taxkeys[$j]{'id'},
372       );
373       do_query($form, $dbh, $query, @values);
374     }
375     else {
376       # INSERT Taxkey
377
378       $query = qq{
379         INSERT INTO taxkeys (
380           taxkey_id,
381           chart_id,
382           tax_id,
383           pos_ustva,
384           startdate
385         )
386         VALUES ((SELECT taxkey FROM tax WHERE tax.id = ?), ?, ?, ?, ?)
387       };
388       @values = (
389         $taxkeys[$j]{'tax_id'},
390         $taxkeys[$j]{'chart_id'},
391         $taxkeys[$j]{'tax_id'},
392         $taxkeys[$j]{'pos_ustva'},
393         $taxkeys[$j]{'startdate'},
394       );
395
396       do_query($form, $dbh, $query, @values);
397     }
398
399   }
400
401   # Update chart.taxkey_id to the latest from taxkeys for this chart.
402   $query = <<SQL;
403     UPDATE chart
404     SET taxkey_id = (
405       SELECT taxkey_id
406       FROM taxkeys
407       WHERE taxkeys.chart_id = chart.id
408       ORDER BY startdate DESC
409       LIMIT 1
410     )
411     WHERE id = ?
412 SQL
413
414   do_query($form, $dbh, $query, $form->{id});
415
416   # commit
417   my $rc = $dbh->commit;
418   $dbh->disconnect;
419
420   $main::lxdebug->leave_sub();
421
422   return $rc;
423 }
424
425 sub delete_account {
426   $main::lxdebug->enter_sub();
427
428   my ($self, $myconfig, $form) = @_;
429
430   # connect to database, turn off AutoCommit
431   my $dbh = $form->dbconnect_noauto($myconfig);
432
433   my $query = qq|SELECT count(*) FROM acc_trans a
434                  WHERE a.chart_id = ?|;
435   my ($count) = selectrow_query($form, $dbh, $query, $form->{id});
436
437   if ($count) {
438     $dbh->disconnect;
439     $main::lxdebug->leave_sub();
440     return;
441   }
442
443   # set inventory_accno_id, income_accno_id, expense_accno_id to defaults
444   foreach my $type (qw(inventory income expense)) {
445     $query =
446       qq|UPDATE parts | .
447       qq|SET ${type}_accno_id = (SELECT ${type}_accno_id FROM defaults) | .
448       qq|WHERE ${type}_accno_id = ?|;
449     do_query($form, $dbh, $query, $form->{id});
450   }
451
452   foreach my $table (qw(partstax customertax vendortax tax)) {
453     $query = qq|DELETE FROM $table
454                 WHERE chart_id = ?|;
455     do_query($form, $dbh, $query, $form->{id});
456   }
457
458   # delete chart of account record
459   $query = qq|DELETE FROM chart
460               WHERE id = ?|;
461   do_query($form, $dbh, $query, $form->{id});
462
463   # delete account taxkeys
464   $query = qq|DELETE FROM taxkeys
465               WHERE chart_id = ?|;
466   do_query($form, $dbh, $query, $form->{id});
467
468   # commit and redirect
469   my $rc = $dbh->commit;
470   $dbh->disconnect;
471
472   $main::lxdebug->leave_sub();
473
474   return $rc;
475 }
476
477 sub lead {
478   $main::lxdebug->enter_sub();
479
480   my ($self, $myconfig, $form) = @_;
481
482   # connect to database
483   my $dbh = $form->dbconnect($myconfig);
484
485   my $query = qq|SELECT id, lead
486                  FROM leads
487                  ORDER BY 2|;
488
489   my $sth = $dbh->prepare($query);
490   $sth->execute || $form->dberror($query);
491
492   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
493     push @{ $form->{ALL} }, $ref;
494   }
495
496   $sth->finish;
497   $dbh->disconnect;
498
499   $main::lxdebug->leave_sub();
500 }
501
502 sub get_lead {
503   $main::lxdebug->enter_sub();
504
505   my ($self, $myconfig, $form) = @_;
506
507   # connect to database
508   my $dbh = $form->dbconnect($myconfig);
509
510   my $query =
511     qq|SELECT l.id, l.lead | .
512     qq|FROM leads l | .
513     qq|WHERE l.id = ?|;
514   my $sth = $dbh->prepare($query);
515   $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})");
516
517   my $ref = $sth->fetchrow_hashref("NAME_lc");
518
519   map { $form->{$_} = $ref->{$_} } keys %$ref;
520
521   $sth->finish;
522
523   $dbh->disconnect;
524
525   $main::lxdebug->leave_sub();
526 }
527
528 sub save_lead {
529   $main::lxdebug->enter_sub();
530
531   my ($self, $myconfig, $form) = @_;
532   my ($query);
533
534   # connect to database
535   my $dbh = $form->dbconnect($myconfig);
536
537   my @values = ($form->{description});
538   # id is the old record
539   if ($form->{id}) {
540     $query = qq|UPDATE leads SET
541                 lead = ?
542                 WHERE id = ?|;
543     puhs(@values, $form->{id});
544   } else {
545     $query = qq|INSERT INTO leads
546                 (lead)
547                 VALUES (?)|;
548   }
549   do_query($form, $dbh, $query, @values);
550
551   $dbh->disconnect;
552
553   $main::lxdebug->leave_sub();
554 }
555
556 sub delete_lead {
557   $main::lxdebug->enter_sub();
558
559   my ($self, $myconfig, $form) = @_;
560   my ($query);
561
562   # connect to database
563   my $dbh = $form->dbconnect($myconfig);
564
565   $query = qq|DELETE FROM leads
566               WHERE id = ?|;
567   do_query($form, $dbh, $query, $form->{id});
568
569   $dbh->disconnect;
570
571   $main::lxdebug->leave_sub();
572 }
573
574 sub business {
575   $main::lxdebug->enter_sub();
576
577   my ($self, $myconfig, $form) = @_;
578
579   # connect to database
580   my $dbh = $form->dbconnect($myconfig);
581
582   my $query = qq|SELECT id, description, discount, customernumberinit, salesman
583                  FROM business
584                  ORDER BY 2|;
585
586   my $sth = $dbh->prepare($query);
587   $sth->execute || $form->dberror($query);
588
589   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
590     push @{ $form->{ALL} }, $ref;
591   }
592
593   $sth->finish;
594   $dbh->disconnect;
595
596   $main::lxdebug->leave_sub();
597 }
598
599 sub get_business {
600   $main::lxdebug->enter_sub();
601
602   my ($self, $myconfig, $form) = @_;
603
604   # connect to database
605   my $dbh = $form->dbconnect($myconfig);
606
607   my $query =
608     qq|SELECT b.description, b.discount, b.customernumberinit, b.salesman
609        FROM business b
610        WHERE b.id = ?|;
611   my $sth = $dbh->prepare($query);
612   $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})");
613
614   my $ref = $sth->fetchrow_hashref("NAME_lc");
615
616   map { $form->{$_} = $ref->{$_} } keys %$ref;
617
618   $sth->finish;
619
620   $dbh->disconnect;
621
622   $main::lxdebug->leave_sub();
623 }
624
625 sub save_business {
626   $main::lxdebug->enter_sub();
627
628   my ($self, $myconfig, $form) = @_;
629   my ($query);
630
631   # connect to database
632   my $dbh = $form->dbconnect($myconfig);
633
634   my @values = ($form->{description}, $form->{discount}, $form->{customernumberinit}, $form->{salesman} ? 't' : 'f');
635   # id is the old record
636   if ($form->{id}) {
637     $query = qq|UPDATE business SET
638                 description = ?,
639                 discount = ?,
640                 customernumberinit = ?,
641                 salesman = ?
642                 WHERE id = ?|;
643     push(@values, $form->{id});
644   } else {
645     $query = qq|INSERT INTO business
646                 (description, discount, customernumberinit, salesman)
647                 VALUES (?, ?, ?, ?)|;
648   }
649   do_query($form, $dbh, $query, @values);
650
651   $dbh->disconnect;
652
653   $main::lxdebug->leave_sub();
654 }
655
656 sub delete_business {
657   $main::lxdebug->enter_sub();
658
659   my ($self, $myconfig, $form) = @_;
660
661   # connect to database
662   my $dbh = $form->dbconnect($myconfig);
663
664   my $query = qq|DELETE FROM business
665               WHERE id = ?|;
666   do_query($form, $dbh, $query, $form->{id});
667
668   $dbh->disconnect;
669
670   $main::lxdebug->leave_sub();
671 }
672
673
674 sub language {
675   $main::lxdebug->enter_sub();
676
677   my ($self, $myconfig, $form, $return_list) = @_;
678
679   # connect to database
680   my $dbh = $form->dbconnect($myconfig);
681
682   my $query =
683     "SELECT id, description, template_code, article_code, " .
684     "  output_numberformat, output_dateformat, output_longdates " .
685     "FROM language ORDER BY description";
686
687   my $sth = $dbh->prepare($query);
688   $sth->execute || $form->dberror($query);
689
690   my $ary = [];
691
692   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
693     push(@{ $ary }, $ref);
694   }
695
696   $sth->finish;
697   $dbh->disconnect;
698
699   $main::lxdebug->leave_sub();
700
701   if ($return_list) {
702     return @{$ary};
703   } else {
704     $form->{ALL} = $ary;
705   }
706 }
707
708 sub get_language {
709   $main::lxdebug->enter_sub();
710
711   my ($self, $myconfig, $form) = @_;
712
713   # connect to database
714   my $dbh = $form->dbconnect($myconfig);
715
716   my $query =
717     "SELECT description, template_code, article_code, " .
718     "  output_numberformat, output_dateformat, output_longdates " .
719     "FROM language WHERE id = ?";
720   my $sth = $dbh->prepare($query);
721   $sth->execute($form->{"id"}) || $form->dberror($query . " ($form->{id})");
722
723   my $ref = $sth->fetchrow_hashref("NAME_lc");
724
725   map { $form->{$_} = $ref->{$_} } keys %$ref;
726
727   $sth->finish;
728
729   $dbh->disconnect;
730
731   $main::lxdebug->leave_sub();
732 }
733
734 sub get_language_details {
735   $main::lxdebug->enter_sub();
736
737   my ($self, $myconfig, $form, $id) = @_;
738
739   # connect to database
740   my $dbh = $form->dbconnect($myconfig);
741
742   my $query =
743     "SELECT template_code, " .
744     "  output_numberformat, output_dateformat, output_longdates " .
745     "FROM language WHERE id = ?";
746   my @res = selectrow_query($form, $dbh, $query, $id);
747   $dbh->disconnect;
748
749   $main::lxdebug->leave_sub();
750
751   return @res;
752 }
753
754 sub save_language {
755   $main::lxdebug->enter_sub();
756
757   my ($self, $myconfig, $form) = @_;
758
759   # connect to database
760   my $dbh = $form->dbconnect($myconfig);
761   my (@values, $query);
762
763   map({ push(@values, $form->{$_}); }
764       qw(description template_code article_code
765          output_numberformat output_dateformat output_longdates));
766
767   # id is the old record
768   if ($form->{id}) {
769     $query =
770       "UPDATE language SET " .
771       "  description = ?, template_code = ?, article_code = ?, " .
772       "  output_numberformat = ?, output_dateformat = ?, " .
773       "  output_longdates = ? " .
774       "WHERE id = ?";
775     push(@values, $form->{id});
776   } else {
777     $query =
778       "INSERT INTO language (" .
779       "  description, template_code, article_code, " .
780       "  output_numberformat, output_dateformat, output_longdates" .
781       ") VALUES (?, ?, ?, ?, ?, ?)";
782   }
783   do_query($form, $dbh, $query, @values);
784
785   $dbh->disconnect;
786
787   $main::lxdebug->leave_sub();
788 }
789
790 sub delete_language {
791   $main::lxdebug->enter_sub();
792
793   my ($self, $myconfig, $form) = @_;
794   my $query;
795
796   # connect to database
797   my $dbh = $form->dbconnect_noauto($myconfig);
798
799   foreach my $table (qw(generic_translations units_language)) {
800     $query = qq|DELETE FROM $table WHERE language_id = ?|;
801     do_query($form, $dbh, $query, $form->{"id"});
802   }
803
804   $query = "DELETE FROM language WHERE id = ?";
805   do_query($form, $dbh, $query, $form->{"id"});
806
807   $dbh->commit();
808   $dbh->disconnect;
809
810   $main::lxdebug->leave_sub();
811 }
812
813
814 sub buchungsgruppe {
815   $main::lxdebug->enter_sub();
816
817   my ($self, $myconfig, $form) = @_;
818
819   # connect to database
820   my $dbh = $form->dbconnect($myconfig);
821
822   my $query = qq|SELECT id, description,
823                  inventory_accno_id,
824                  (SELECT accno FROM chart WHERE id = inventory_accno_id) AS inventory_accno,
825                  income_accno_id_0,
826                  (SELECT accno FROM chart WHERE id = income_accno_id_0) AS income_accno_0,
827                  expense_accno_id_0,
828                  (SELECT accno FROM chart WHERE id = expense_accno_id_0) AS expense_accno_0,
829                  income_accno_id_1,
830                  (SELECT accno FROM chart WHERE id = income_accno_id_1) AS income_accno_1,
831                  expense_accno_id_1,
832                  (SELECT accno FROM chart WHERE id = expense_accno_id_1) AS expense_accno_1,
833                  income_accno_id_2,
834                  (SELECT accno FROM chart WHERE id = income_accno_id_2) AS income_accno_2,
835                  expense_accno_id_2,
836                  (select accno FROM chart WHERE id = expense_accno_id_2) AS expense_accno_2,
837                  income_accno_id_3,
838                  (SELECT accno FROM chart WHERE id = income_accno_id_3) AS income_accno_3,
839                  expense_accno_id_3,
840                  (SELECT accno FROM chart WHERE id = expense_accno_id_3) AS expense_accno_3
841                  FROM buchungsgruppen
842                  ORDER BY sortkey|;
843
844   my $sth = $dbh->prepare($query);
845   $sth->execute || $form->dberror($query);
846
847   $form->{ALL} = [];
848   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
849     push @{ $form->{ALL} }, $ref;
850   }
851
852   $sth->finish;
853   $dbh->disconnect;
854
855   $main::lxdebug->leave_sub();
856 }
857
858 sub get_buchungsgruppe {
859   $main::lxdebug->enter_sub();
860
861   my ($self, $myconfig, $form) = @_;
862   my $query;
863
864   # connect to database
865   my $dbh = $form->dbconnect($myconfig);
866
867   if ($form->{id}) {
868     $query =
869       qq|SELECT description, inventory_accno_id,
870          (SELECT accno FROM chart WHERE id = inventory_accno_id) AS inventory_accno,
871          income_accno_id_0,
872          (SELECT accno FROM chart WHERE id = income_accno_id_0) AS income_accno_0,
873          expense_accno_id_0,
874          (SELECT accno FROM chart WHERE id = expense_accno_id_0) AS expense_accno_0,
875          income_accno_id_1,
876          (SELECT accno FROM chart WHERE id = income_accno_id_1) AS income_accno_1,
877          expense_accno_id_1,
878          (SELECT accno FROM chart WHERE id = expense_accno_id_1) AS expense_accno_1,
879          income_accno_id_2,
880          (SELECT accno FROM chart WHERE id = income_accno_id_2) AS income_accno_2,
881          expense_accno_id_2,
882          (select accno FROM chart WHERE id = expense_accno_id_2) AS expense_accno_2,
883          income_accno_id_3,
884          (SELECT accno FROM chart WHERE id = income_accno_id_3) AS income_accno_3,
885          expense_accno_id_3,
886          (SELECT accno FROM chart WHERE id = expense_accno_id_3) AS expense_accno_3
887          FROM buchungsgruppen
888          WHERE id = ?|;
889     my $sth = $dbh->prepare($query);
890     $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})");
891
892     my $ref = $sth->fetchrow_hashref("NAME_lc");
893
894     map { $form->{$_} = $ref->{$_} } keys %$ref;
895
896     $sth->finish;
897
898     $query =
899       qq|SELECT count(id) = 0 AS orphaned
900          FROM parts
901          WHERE buchungsgruppen_id = ?|;
902     ($form->{orphaned}) = selectrow_query($form, $dbh, $query, $form->{id});
903   }
904
905   $query = "SELECT inventory_accno_id, income_accno_id, expense_accno_id ".
906     "FROM defaults";
907   ($form->{"std_inventory_accno_id"}, $form->{"std_income_accno_id"},
908    $form->{"std_expense_accno_id"}) = selectrow_query($form, $dbh, $query);
909
910   my $module = "IC";
911   $query = qq|SELECT c.accno, c.description, c.link, c.id,
912               d.inventory_accno_id, d.income_accno_id, d.expense_accno_id
913               FROM chart c, defaults d
914               WHERE c.link LIKE '%$module%'
915               ORDER BY c.accno|;
916
917
918   my $sth = $dbh->prepare($query);
919   $sth->execute || $form->dberror($query);
920   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
921     foreach my $key (split(/:/, $ref->{link})) {
922       if (!$form->{"std_inventory_accno_id"} && ($key eq "IC")) {
923         $form->{"std_inventory_accno_id"} = $ref->{"id"};
924       }
925       if ($key =~ /$module/) {
926         if (   ($ref->{id} eq $ref->{inventory_accno_id})
927             || ($ref->{id} eq $ref->{income_accno_id})
928             || ($ref->{id} eq $ref->{expense_accno_id})) {
929           push @{ $form->{"${module}_links"}{$key} },
930             { accno       => $ref->{accno},
931               description => $ref->{description},
932               selected    => "selected",
933               id          => $ref->{id} };
934         } else {
935           push @{ $form->{"${module}_links"}{$key} },
936             { accno       => $ref->{accno},
937               description => $ref->{description},
938               selected    => "",
939               id          => $ref->{id} };
940         }
941       }
942     }
943   }
944   $sth->finish;
945
946
947   $dbh->disconnect;
948
949   $main::lxdebug->leave_sub();
950 }
951
952 sub save_buchungsgruppe {
953   $main::lxdebug->enter_sub();
954
955   my ($self, $myconfig, $form) = @_;
956
957   # connect to database
958   my $dbh = $form->dbconnect($myconfig);
959
960   my @values = ($form->{description}, $form->{inventory_accno_id},
961                 $form->{income_accno_id_0}, $form->{expense_accno_id_0},
962                 $form->{income_accno_id_1}, $form->{expense_accno_id_1},
963                 $form->{income_accno_id_2}, $form->{expense_accno_id_2},
964                 $form->{income_accno_id_3}, $form->{expense_accno_id_3});
965
966   my $query;
967
968   # id is the old record
969   if ($form->{id}) {
970     $query = qq|UPDATE buchungsgruppen SET
971                 description = ?, inventory_accno_id = ?,
972                 income_accno_id_0 = ?, expense_accno_id_0 = ?,
973                 income_accno_id_1 = ?, expense_accno_id_1 = ?,
974                 income_accno_id_2 = ?, expense_accno_id_2 = ?,
975                 income_accno_id_3 = ?, expense_accno_id_3 = ?
976                 WHERE id = ?|;
977     push(@values, $form->{id});
978   } else {
979     $query = qq|SELECT COALESCE(MAX(sortkey) + 1, 1) FROM buchungsgruppen|;
980     my ($sortkey) = $dbh->selectrow_array($query);
981     $form->dberror($query) if ($dbh->err);
982     push(@values, $sortkey);
983     $query = qq|INSERT INTO buchungsgruppen
984                 (description, inventory_accno_id,
985                 income_accno_id_0, expense_accno_id_0,
986                 income_accno_id_1, expense_accno_id_1,
987                 income_accno_id_2, expense_accno_id_2,
988                 income_accno_id_3, expense_accno_id_3,
989                 sortkey)
990                 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)|;
991   }
992   do_query($form, $dbh, $query, @values);
993
994   $dbh->disconnect;
995
996   $main::lxdebug->leave_sub();
997 }
998
999 sub delete_buchungsgruppe {
1000   $main::lxdebug->enter_sub();
1001
1002   my ($self, $myconfig, $form) = @_;
1003
1004   # connect to database
1005   my $dbh = $form->dbconnect($myconfig);
1006
1007   my $query = qq|DELETE FROM buchungsgruppen WHERE id = ?|;
1008   do_query($form, $dbh, $query, $form->{id});
1009
1010   $dbh->disconnect;
1011
1012   $main::lxdebug->leave_sub();
1013 }
1014
1015 sub swap_sortkeys {
1016   $main::lxdebug->enter_sub();
1017
1018   my ($self, $myconfig, $form, $table) = @_;
1019
1020   # connect to database
1021   my $dbh = $form->get_standard_dbh($myconfig);
1022
1023   my $query =
1024     qq|SELECT
1025        (SELECT sortkey FROM $table WHERE id = ?) AS sortkey1,
1026        (SELECT sortkey FROM $table WHERE id = ?) AS sortkey2|;
1027   my @values   = ($form->{"id1"}, $form->{"id2"});
1028   my @sortkeys = selectrow_query($form, $dbh, $query, @values);
1029
1030   $query  = qq|UPDATE $table SET sortkey = ? WHERE id = ?|;
1031   my $sth = prepare_query($form, $dbh, $query);
1032
1033   do_statement($form, $sth, $query, $sortkeys[1], $form->{"id1"});
1034   do_statement($form, $sth, $query, $sortkeys[0], $form->{"id2"});
1035
1036   $sth->finish();
1037
1038   $dbh->commit();
1039
1040   $main::lxdebug->leave_sub();
1041 }
1042
1043 sub prepare_template_filename {
1044   $main::lxdebug->enter_sub();
1045
1046   my ($self, $myconfig, $form) = @_;
1047
1048   my ($filename, $display_filename);
1049
1050   if ($form->{type} eq "stylesheet") {
1051     $filename = "css/$myconfig->{stylesheet}";
1052     $display_filename = $myconfig->{stylesheet};
1053
1054   } else {
1055     $filename = $form->{formname};
1056
1057     if ($form->{language}) {
1058       my ($id, $template_code) = split(/--/, $form->{language});
1059       $filename .= "_${template_code}";
1060     }
1061
1062     if ($form->{printer}) {
1063       my ($id, $template_code) = split(/--/, $form->{printer});
1064       $filename .= "_${template_code}";
1065     }
1066
1067     $filename .= "." . ($form->{format} eq "html" ? "html" : "tex");
1068     $filename =~ s|.*/||;
1069     $display_filename = $filename;
1070     $filename = "$myconfig->{templates}/$filename";
1071   }
1072
1073   $main::lxdebug->leave_sub();
1074
1075   return ($filename, $display_filename);
1076 }
1077
1078
1079 sub load_template {
1080   $main::lxdebug->enter_sub();
1081
1082   my ($self, $filename) = @_;
1083
1084   my ($content, $lines) = ("", 0);
1085
1086   local *TEMPLATE;
1087
1088   if (open(TEMPLATE, $filename)) {
1089     while (<TEMPLATE>) {
1090       $content .= $_;
1091       $lines++;
1092     }
1093     close(TEMPLATE);
1094   }
1095
1096   $content = Encode::decode('utf-8-strict', $content) if $::locale->is_utf8;
1097
1098   $main::lxdebug->leave_sub();
1099
1100   return ($content, $lines);
1101 }
1102
1103 sub save_template {
1104   $main::lxdebug->enter_sub();
1105
1106   my ($self, $filename, $content) = @_;
1107
1108   local *TEMPLATE;
1109
1110   my $error = "";
1111
1112   if (open(TEMPLATE, ">$filename")) {
1113     $content = Encode::encode('utf-8-strict', $content) if $::locale->is_utf8;
1114     $content =~ s/\r\n/\n/g;
1115     print(TEMPLATE $content);
1116     close(TEMPLATE);
1117   } else {
1118     $error = $!;
1119   }
1120
1121   $main::lxdebug->leave_sub();
1122
1123   return $error;
1124 }
1125
1126 sub save_defaults {
1127   $main::lxdebug->enter_sub();
1128
1129   my $self     = shift;
1130   my %params   = @_;
1131
1132   my $myconfig = \%main::myconfig;
1133   my $form     = $main::form;
1134
1135   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
1136
1137   my %accnos;
1138   map { ($accnos{$_}) = split(m/--/, $form->{$_}) } qw(inventory_accno income_accno expense_accno fxgain_accno fxloss_accno ar_paid_accno);
1139
1140   $form->{curr}  =~ s/ //g;
1141   my @currencies =  grep { $_ ne '' } split m/:/, $form->{curr};
1142   my $currency   =  join ':', @currencies;
1143
1144   # these defaults are database wide
1145
1146   my $query =
1147     qq|UPDATE defaults SET
1148         inventory_accno_id = (SELECT c.id FROM chart c WHERE c.accno = ?),
1149         income_accno_id    = (SELECT c.id FROM chart c WHERE c.accno = ?),
1150         expense_accno_id   = (SELECT c.id FROM chart c WHERE c.accno = ?),
1151         fxgain_accno_id    = (SELECT c.id FROM chart c WHERE c.accno = ?),
1152         fxloss_accno_id    = (SELECT c.id FROM chart c WHERE c.accno = ?),
1153         ar_paid_accno_id   = (SELECT c.id FROM chart c WHERE c.accno = ?),
1154         invnumber          = ?,
1155         cnnumber           = ?,
1156         sonumber           = ?,
1157         ponumber           = ?,
1158         sqnumber           = ?,
1159         rfqnumber          = ?,
1160         customernumber     = ?,
1161         vendornumber       = ?,
1162         articlenumber      = ?,
1163         servicenumber      = ?,
1164         sdonumber          = ?,
1165         pdonumber          = ?,
1166         curr               = ?,
1167         businessnumber     = ?,
1168         weightunit         = ?|;
1169   my @values = ($accnos{inventory_accno}, $accnos{income_accno}, $accnos{expense_accno},
1170                 $accnos{fxgain_accno},    $accnos{fxloss_accno}, $accnos{ar_paid_accno},
1171                 $form->{invnumber},       $form->{cnnumber},
1172                 $form->{sonumber},        $form->{ponumber},
1173                 $form->{sqnumber},        $form->{rfqnumber},
1174                 $form->{customernumber},  $form->{vendornumber},
1175                 $form->{articlenumber},   $form->{servicenumber},
1176                 $form->{sdonumber},       $form->{pdonumber},
1177                 $currency,
1178                 $form->{businessnumber},  $form->{weightunit});
1179   do_query($form, $dbh, $query, @values);
1180
1181   $dbh->commit();
1182
1183   $main::lxdebug->leave_sub();
1184 }
1185
1186
1187 sub save_preferences {
1188   $main::lxdebug->enter_sub();
1189
1190   my ($self, $myconfig, $form) = @_;
1191
1192   my $dbh = $form->get_standard_dbh($myconfig);
1193
1194   my ($currency, $businessnumber) = selectrow_query($form, $dbh, qq|SELECT curr, businessnumber FROM defaults|);
1195
1196   # update name
1197   my $query = qq|UPDATE employee SET name = ? WHERE login = ?|;
1198   do_query($form, $dbh, $query, $form->{name}, $form->{login});
1199
1200   my $rc = $dbh->commit();
1201
1202   # save first currency in myconfig
1203   $currency               =~ s/:.*//;
1204   $form->{currency}       =  $currency;
1205
1206   $form->{businessnumber} =  $businessnumber;
1207
1208   $myconfig = new User($form->{login});
1209
1210   foreach my $item (keys %$form) {
1211     $myconfig->{$item} = $form->{$item};
1212   }
1213
1214   $myconfig->save_member;
1215
1216   my $auth = $main::auth;
1217
1218   $main::lxdebug->leave_sub();
1219
1220   return $rc;
1221 }
1222
1223 sub get_defaults {
1224   $main::lxdebug->enter_sub();
1225
1226   my $self     = shift;
1227   my %params   = @_;
1228
1229   my $myconfig = \%main::myconfig;
1230   my $form     = $main::form;
1231
1232   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
1233
1234   my $defaults = selectfirst_hashref_query($form, $dbh, qq|SELECT * FROM defaults|) || {};
1235
1236   $defaults->{weightunit} ||= 'kg';
1237
1238   $main::lxdebug->leave_sub();
1239
1240   return $defaults;
1241 }
1242
1243 sub defaultaccounts {
1244   $main::lxdebug->enter_sub();
1245
1246   my ($self, $myconfig, $form) = @_;
1247
1248   # connect to database
1249   my $dbh = $form->dbconnect($myconfig);
1250
1251   # get defaults from defaults table
1252   my $query = qq|SELECT * FROM defaults|;
1253   my $sth   = $dbh->prepare($query);
1254   $sth->execute || $form->dberror($query);
1255
1256   $form->{defaults}               = $sth->fetchrow_hashref("NAME_lc");
1257   $form->{defaults}{IC}           = $form->{defaults}{inventory_accno_id};
1258   $form->{defaults}{IC_income}    = $form->{defaults}{income_accno_id};
1259   $form->{defaults}{IC_expense}   = $form->{defaults}{expense_accno_id};
1260   $form->{defaults}{FX_gain}      = $form->{defaults}{fxgain_accno_id};
1261   $form->{defaults}{FX_loss}      = $form->{defaults}{fxloss_accno_id};
1262   $form->{defaults}{AR_paid}      = $form->{defaults}{ar_paid_accno_id};
1263
1264   $form->{defaults}{weightunit} ||= 'kg';
1265
1266   $sth->finish;
1267
1268   $query = qq|SELECT c.id, c.accno, c.description, c.link
1269               FROM chart c
1270               WHERE c.link LIKE '%IC%'
1271               ORDER BY c.accno|;
1272   $sth = $dbh->prepare($query);
1273   $sth->execute || $self->dberror($query);
1274
1275   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1276     foreach my $key (split(/:/, $ref->{link})) {
1277       if ($key =~ /IC/) {
1278         my $nkey = $key;
1279         if ($key =~ /cogs/) {
1280           $nkey = "IC_expense";
1281         }
1282         if ($key =~ /sale/) {
1283           $nkey = "IC_income";
1284         }
1285         %{ $form->{IC}{$nkey}{ $ref->{accno} } } = (
1286                                              id          => $ref->{id},
1287                                              description => $ref->{description}
1288         );
1289       }
1290     }
1291   }
1292   $sth->finish;
1293
1294   $query = qq|SELECT c.id, c.accno, c.description
1295               FROM chart c
1296               WHERE c.category = 'I'
1297               AND c.charttype = 'A'
1298               ORDER BY c.accno|;
1299   $sth = $dbh->prepare($query);
1300   $sth->execute || $self->dberror($query);
1301
1302   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1303     %{ $form->{IC}{FX_gain}{ $ref->{accno} } } = (
1304                                              id          => $ref->{id},
1305                                              description => $ref->{description}
1306     );
1307   }
1308   $sth->finish;
1309
1310   $query = qq|SELECT c.id, c.accno, c.description
1311               FROM chart c
1312               WHERE c.category = 'E'
1313               AND c.charttype = 'A'
1314               ORDER BY c.accno|;
1315   $sth = $dbh->prepare($query);
1316   $sth->execute || $self->dberror($query);
1317
1318   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1319     %{ $form->{IC}{FX_loss}{ $ref->{accno} } } = (
1320                                              id          => $ref->{id},
1321                                              description => $ref->{description}
1322     );
1323   }
1324   $sth->finish;
1325
1326   # now get the tax rates and numbers
1327   $query = qq|SELECT c.id, c.accno, c.description,
1328               t.rate * 100 AS rate, t.taxnumber
1329               FROM chart c, tax t
1330               WHERE c.id = t.chart_id|;
1331
1332   $sth = $dbh->prepare($query);
1333   $sth->execute || $form->dberror($query);
1334
1335   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1336     $form->{taxrates}{ $ref->{accno} }{id}          = $ref->{id};
1337     $form->{taxrates}{ $ref->{accno} }{description} = $ref->{description};
1338     $form->{taxrates}{ $ref->{accno} }{taxnumber}   = $ref->{taxnumber}
1339       if $ref->{taxnumber};
1340     $form->{taxrates}{ $ref->{accno} }{rate} = $ref->{rate} if $ref->{rate};
1341   }
1342   # Abfrage für Standard Umlaufvermögenskonto
1343   $query =
1344     qq|SELECT id, accno, description, link | .
1345     qq|FROM chart | .
1346     qq|WHERE link LIKE ? |.
1347     qq|ORDER BY accno|;
1348   $sth = prepare_execute_query($form, $dbh, $query, '%AR%');
1349   $sth->execute || $form->dberror($query);#
1350   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1351     foreach my $item (split(/:/, $ref->{link})) {
1352       if ($item eq "AR_paid") {
1353         %{ $form->{IC}{AR_paid}{ $ref->{accno} } } = (
1354                                              id          => $ref->{id},
1355                                              description => $ref->{description}
1356           );
1357       }
1358     }
1359   }
1360
1361   $sth->finish;
1362   $dbh->disconnect;
1363
1364   $main::lxdebug->leave_sub();
1365 }
1366
1367 sub closedto {
1368   $main::lxdebug->enter_sub();
1369
1370   my ($self, $myconfig, $form) = @_;
1371
1372   my $dbh = $form->dbconnect($myconfig);
1373
1374   my $query = qq|SELECT closedto, revtrans FROM defaults|;
1375   my $sth   = $dbh->prepare($query);
1376   $sth->execute || $form->dberror($query);
1377
1378   ($form->{closedto}, $form->{revtrans}) = $sth->fetchrow_array;
1379
1380   $sth->finish;
1381
1382   $dbh->disconnect;
1383
1384   $main::lxdebug->leave_sub();
1385 }
1386
1387 sub closebooks {
1388   $main::lxdebug->enter_sub();
1389
1390   my ($self, $myconfig, $form) = @_;
1391
1392   my $dbh = $form->dbconnect($myconfig);
1393
1394   my ($query, @values);
1395
1396   if ($form->{revtrans}) {
1397     $query = qq|UPDATE defaults SET closedto = NULL, revtrans = '1'|;
1398
1399   } elsif ($form->{closedto}) {
1400     $query = qq|UPDATE defaults SET closedto = ?, revtrans = '0'|;
1401     @values = (conv_date($form->{closedto}));
1402
1403   } else {
1404     $query = qq|UPDATE defaults SET closedto = NULL, revtrans = '0'|;
1405   }
1406
1407   # set close in defaults
1408   do_query($form, $dbh, $query, @values);
1409
1410   $dbh->disconnect;
1411
1412   $main::lxdebug->leave_sub();
1413 }
1414
1415 sub get_base_unit {
1416   my ($self, $units, $unit_name, $factor) = @_;
1417
1418   $factor = 1 unless ($factor);
1419
1420   my $unit = $units->{$unit_name};
1421
1422   if (!defined($unit) || !$unit->{"base_unit"} ||
1423       ($unit_name eq $unit->{"base_unit"})) {
1424     return ($unit_name, $factor);
1425   }
1426
1427   return AM->get_base_unit($units, $unit->{"base_unit"}, $factor * $unit->{"factor"});
1428 }
1429
1430 sub retrieve_units {
1431   $main::lxdebug->enter_sub();
1432
1433   my ($self, $myconfig, $form, $prefix) = @_;
1434
1435   my $dbh = $form->get_standard_dbh;
1436
1437   my $query = "SELECT *, base_unit AS original_base_unit FROM units";
1438
1439   my $sth = prepare_execute_query($form, $dbh, $query);
1440
1441   my $units = {};
1442   while (my $ref = $sth->fetchrow_hashref()) {
1443     $units->{$ref->{"name"}} = $ref;
1444   }
1445   $sth->finish();
1446
1447   my $query_lang = "SELECT id, template_code FROM language ORDER BY description";
1448   $sth = $dbh->prepare($query_lang);
1449   $sth->execute() || $form->dberror($query_lang);
1450   my @languages;
1451   while (my $ref = $sth->fetchrow_hashref()) {
1452     push(@languages, $ref);
1453   }
1454   $sth->finish();
1455
1456   $query_lang = "SELECT ul.localized, ul.localized_plural, l.id, l.template_code " .
1457     "FROM units_language ul " .
1458     "LEFT JOIN language l ON ul.language_id = l.id " .
1459     "WHERE ul.unit = ?";
1460   $sth = $dbh->prepare($query_lang);
1461
1462   foreach my $unit (values(%{$units})) {
1463     ($unit->{"${prefix}base_unit"}, $unit->{"${prefix}factor"}) = AM->get_base_unit($units, $unit->{"name"});
1464
1465     $unit->{"LANGUAGES"} = {};
1466     foreach my $lang (@languages) {
1467       $unit->{"LANGUAGES"}->{$lang->{"template_code"}} = { "template_code" => $lang->{"template_code"} };
1468     }
1469
1470     $sth->execute($unit->{"name"}) || $form->dberror($query_lang . " (" . $unit->{"name"} . ")");
1471     while (my $ref = $sth->fetchrow_hashref()) {
1472       map({ $unit->{"LANGUAGES"}->{$ref->{"template_code"}}->{$_} = $ref->{$_} } keys(%{$ref}));
1473     }
1474   }
1475   $sth->finish;
1476
1477   $main::lxdebug->leave_sub();
1478
1479   return $units;
1480 }
1481
1482 sub retrieve_all_units {
1483   $main::lxdebug->enter_sub();
1484
1485   my $self = shift;
1486
1487   if (!$main::all_units) {
1488     $main::all_units = $self->retrieve_units(\%main::myconfig, $main::form);
1489   }
1490
1491   $main::lxdebug->leave_sub();
1492
1493   return $main::all_units;
1494 }
1495
1496
1497 sub translate_units {
1498   $main::lxdebug->enter_sub();
1499
1500   my ($self, $form, $template_code, $unit, $amount) = @_;
1501
1502   my $units = $self->retrieve_units(\%main::myconfig, $form);
1503
1504   my $h = $units->{$unit}->{"LANGUAGES"}->{$template_code};
1505   my $new_unit = $unit;
1506   if ($h) {
1507     if (($amount != 1) && $h->{"localized_plural"}) {
1508       $new_unit = $h->{"localized_plural"};
1509     } elsif ($h->{"localized"}) {
1510       $new_unit = $h->{"localized"};
1511     }
1512   }
1513
1514   $main::lxdebug->leave_sub();
1515
1516   return $new_unit;
1517 }
1518
1519 sub units_in_use {
1520   $main::lxdebug->enter_sub();
1521
1522   my ($self, $myconfig, $form, $units) = @_;
1523
1524   my $dbh = $form->dbconnect($myconfig);
1525
1526   map({ $_->{"in_use"} = 0; } values(%{$units}));
1527
1528   foreach my $unit (values(%{$units})) {
1529     my $base_unit = $unit->{"original_base_unit"};
1530     while ($base_unit) {
1531       $units->{$base_unit}->{"in_use"} = 1;
1532       $units->{$base_unit}->{"DEPENDING_UNITS"} = [] unless ($units->{$base_unit}->{"DEPENDING_UNITS"});
1533       push(@{$units->{$base_unit}->{"DEPENDING_UNITS"}}, $unit->{"name"});
1534       $base_unit = $units->{$base_unit}->{"original_base_unit"};
1535     }
1536   }
1537
1538   foreach my $unit (values(%{$units})) {
1539     map({ $_ = $dbh->quote($_); } @{$unit->{"DEPENDING_UNITS"}});
1540
1541     foreach my $table (qw(parts invoice orderitems)) {
1542       my $query = "SELECT COUNT(*) FROM $table WHERE unit ";
1543
1544       if (0 == scalar(@{$unit->{"DEPENDING_UNITS"}})) {
1545         $query .= "= " . $dbh->quote($unit->{"name"});
1546       } else {
1547         $query .= "IN (" . $dbh->quote($unit->{"name"}) . "," .
1548           join(",", map({ $dbh->quote($_) } @{$unit->{"DEPENDING_UNITS"}})) . ")";
1549       }
1550
1551       my ($count) = $dbh->selectrow_array($query);
1552       $form->dberror($query) if ($dbh->err);
1553
1554       if ($count) {
1555         $unit->{"in_use"} = 1;
1556         last;
1557       }
1558     }
1559   }
1560
1561   $dbh->disconnect();
1562
1563   $main::lxdebug->leave_sub();
1564 }
1565
1566 sub convertible_units {
1567   $main::lxdebug->enter_sub();
1568
1569   my $self        = shift;
1570   my $units       = shift;
1571   my $filter_unit = shift;
1572   my $not_smaller = shift;
1573
1574   my $conv_units = [];
1575
1576   $filter_unit = $units->{$filter_unit};
1577
1578   foreach my $name (sort { lc $a cmp lc $b } keys %{ $units }) {
1579     my $unit = $units->{$name};
1580
1581     if (($unit->{base_unit} eq $filter_unit->{base_unit}) &&
1582         (!$not_smaller || ($unit->{factor} >= $filter_unit->{factor}))) {
1583       push @{$conv_units}, $unit;
1584     }
1585   }
1586
1587   my @sorted = sort { $b->{factor} <=> $a->{factor} } @{ $conv_units };
1588
1589   $main::lxdebug->leave_sub();
1590
1591   return \@sorted;
1592 }
1593
1594 # if $a is translatable to $b, return the factor between them.
1595 # else return 1
1596 sub convert_unit {
1597   $main::lxdebug->enter_sub(2);
1598   my ($this, $a, $b, $all_units) = @_;
1599
1600   $main::lxdebug->leave_sub(2) and return 0 unless $a && $b;
1601   $main::lxdebug->leave_sub(2) and return 0 unless $all_units->{$a} && $all_units->{$b};
1602   $main::lxdebug->leave_sub(2) and return 0 unless $all_units->{$a}{base_unit} eq $all_units->{$b}{base_unit};
1603   $main::lxdebug->leave_sub(2) and return $all_units->{$a}{factor} / $all_units->{$b}{factor};
1604 }
1605
1606 sub unit_select_data {
1607   $main::lxdebug->enter_sub();
1608
1609   my ($self, $units, $selected, $empty_entry, $convertible_into) = @_;
1610
1611   my $select = [];
1612
1613   if ($empty_entry) {
1614     push(@{$select}, { "name" => "", "base_unit" => "", "factor" => "", "selected" => "" });
1615   }
1616
1617   foreach my $unit (sort({ $units->{$a}->{"sortkey"} <=> $units->{$b}->{"sortkey"} } keys(%{$units}))) {
1618     if (!$convertible_into ||
1619         ($units->{$convertible_into} &&
1620          ($units->{$convertible_into}->{base_unit} eq $units->{$unit}->{base_unit}))) {
1621       push @{$select}, { "name"      => $unit,
1622                          "base_unit" => $units->{$unit}->{"base_unit"},
1623                          "factor"    => $units->{$unit}->{"factor"},
1624                          "selected"  => ($unit eq $selected) ? "selected" : "" };
1625     }
1626   }
1627
1628   $main::lxdebug->leave_sub();
1629
1630   return $select;
1631 }
1632
1633 sub unit_select_html {
1634   $main::lxdebug->enter_sub();
1635
1636   my ($self, $units, $name, $selected, $convertible_into) = @_;
1637
1638   my $select = "<select name=${name}>";
1639
1640   foreach my $unit (sort({ $units->{$a}->{"sortkey"} <=> $units->{$b}->{"sortkey"} } keys(%{$units}))) {
1641     if (!$convertible_into ||
1642         ($units->{$convertible_into} &&
1643          ($units->{$convertible_into}->{"base_unit"} eq $units->{$unit}->{"base_unit"}))) {
1644       $select .= "<option" . (($unit eq $selected) ? " selected" : "") . ">${unit}</option>";
1645     }
1646   }
1647   $select .= "</select>";
1648
1649   $main::lxdebug->leave_sub();
1650
1651   return $select;
1652 }
1653
1654 sub sum_with_unit {
1655   $main::lxdebug->enter_sub();
1656
1657   my $self  = shift;
1658
1659   my $units = $self->retrieve_all_units();
1660
1661   my $sum   = 0;
1662   my $base_unit;
1663
1664   while (2 <= scalar(@_)) {
1665     my $qty  = shift(@_);
1666     my $unit = $units->{shift(@_)};
1667
1668     croak "No unit defined with name $unit" if (!defined $unit);
1669
1670     if (!$base_unit) {
1671       $base_unit = $unit->{base_unit};
1672     } elsif ($base_unit ne $unit->{base_unit}) {
1673       croak "Adding values with incompatible base units $base_unit/$unit->{base_unit}";
1674     }
1675
1676     $sum += $qty * $unit->{factor};
1677   }
1678
1679   $main::lxdebug->leave_sub();
1680
1681   return wantarray ? ($sum, $base_unit) : $sum;
1682 }
1683
1684 sub add_unit {
1685   $main::lxdebug->enter_sub();
1686
1687   my ($self, $myconfig, $form, $name, $base_unit, $factor, $languages) = @_;
1688
1689   my $dbh = $form->dbconnect_noauto($myconfig);
1690
1691   my $query = qq|SELECT COALESCE(MAX(sortkey), 0) + 1 FROM units|;
1692   my ($sortkey) = selectrow_query($form, $dbh, $query);
1693
1694   $query = "INSERT INTO units (name, base_unit, factor, sortkey) " .
1695     "VALUES (?, ?, ?, ?)";
1696   do_query($form, $dbh, $query, $name, $base_unit, $factor, $sortkey);
1697
1698   if ($languages) {
1699     $query = "INSERT INTO units_language (unit, language_id, localized, localized_plural) VALUES (?, ?, ?, ?)";
1700     my $sth = $dbh->prepare($query);
1701     foreach my $lang (@{$languages}) {
1702       my @values = ($name, $lang->{"id"}, $lang->{"localized"}, $lang->{"localized_plural"});
1703       $sth->execute(@values) || $form->dberror($query . " (" . join(", ", @values) . ")");
1704     }
1705     $sth->finish();
1706   }
1707
1708   $dbh->commit();
1709   $dbh->disconnect();
1710
1711   $main::lxdebug->leave_sub();
1712 }
1713
1714 sub save_units {
1715   $main::lxdebug->enter_sub();
1716
1717   my ($self, $myconfig, $form, $units, $delete_units) = @_;
1718
1719   my $dbh = $form->dbconnect_noauto($myconfig);
1720
1721   my ($base_unit, $unit, $sth, $query);
1722
1723   $query = "DELETE FROM units_language";
1724   $dbh->do($query) || $form->dberror($query);
1725
1726   if ($delete_units && (0 != scalar(@{$delete_units}))) {
1727     $query = "DELETE FROM units WHERE name IN (";
1728     map({ $query .= "?," } @{$delete_units});
1729     substr($query, -1, 1) = ")";
1730     $dbh->do($query, undef, @{$delete_units}) ||
1731       $form->dberror($query . " (" . join(", ", @{$delete_units}) . ")");
1732   }
1733
1734   $query = "UPDATE units SET name = ?, base_unit = ?, factor = ? WHERE name = ?";
1735   $sth = $dbh->prepare($query);
1736
1737   my $query_lang = "INSERT INTO units_language (unit, language_id, localized, localized_plural) VALUES (?, ?, ?, ?)";
1738   my $sth_lang = $dbh->prepare($query_lang);
1739
1740   foreach $unit (values(%{$units})) {
1741     $unit->{"depth"} = 0;
1742     my $base_unit = $unit;
1743     while ($base_unit->{"base_unit"}) {
1744       $unit->{"depth"}++;
1745       $base_unit = $units->{$base_unit->{"base_unit"}};
1746     }
1747   }
1748
1749   foreach $unit (sort({ $a->{"depth"} <=> $b->{"depth"} } values(%{$units}))) {
1750     if ($unit->{"LANGUAGES"}) {
1751       foreach my $lang (@{$unit->{"LANGUAGES"}}) {
1752         next unless ($lang->{"id"} && $lang->{"localized"});
1753         my @values = ($unit->{"name"}, $lang->{"id"}, $lang->{"localized"}, $lang->{"localized_plural"});
1754         $sth_lang->execute(@values) || $form->dberror($query_lang . " (" . join(", ", @values) . ")");
1755       }
1756     }
1757
1758     next if ($unit->{"unchanged_unit"});
1759
1760     my @values = ($unit->{"name"}, $unit->{"base_unit"}, $unit->{"factor"}, $unit->{"old_name"});
1761     $sth->execute(@values) || $form->dberror($query . " (" . join(", ", @values) . ")");
1762   }
1763
1764   $sth->finish();
1765   $sth_lang->finish();
1766   $dbh->commit();
1767   $dbh->disconnect();
1768
1769   $main::lxdebug->leave_sub();
1770 }
1771
1772 sub taxes {
1773   $main::lxdebug->enter_sub();
1774
1775   my ($self, $myconfig, $form) = @_;
1776
1777   # connect to database
1778   my $dbh = $form->dbconnect($myconfig);
1779
1780   my $query = qq|SELECT
1781                    t.id,
1782                    t.taxkey,
1783                    t.taxdescription,
1784                    round(t.rate * 100, 2) AS rate,
1785                    (SELECT accno FROM chart WHERE id = chart_id) AS taxnumber,
1786                    (SELECT description FROM chart WHERE id = chart_id) AS account_description
1787                  FROM tax t
1788                  ORDER BY taxkey|;
1789
1790   my $sth = $dbh->prepare($query);
1791   $sth->execute || $form->dberror($query);
1792
1793   $form->{TAX} = [];
1794   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1795     push @{ $form->{TAX} }, $ref;
1796   }
1797
1798   $sth->finish;
1799   $dbh->disconnect;
1800
1801   $main::lxdebug->leave_sub();
1802 }
1803
1804 sub get_tax_accounts {
1805   $main::lxdebug->enter_sub();
1806
1807   my ($self, $myconfig, $form) = @_;
1808
1809   my $dbh = $form->dbconnect($myconfig);
1810
1811   # get Accounts from chart
1812   my $query = qq{ SELECT
1813                  id,
1814                  accno || ' - ' || description AS taxaccount
1815                FROM chart
1816                WHERE link LIKE '%_tax%'
1817                ORDER BY accno
1818              };
1819
1820   my $sth = $dbh->prepare($query);
1821   $sth->execute || $form->dberror($query);
1822
1823   $form->{ACCOUNTS} = [];
1824   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1825     push @{ $form->{ACCOUNTS} }, $ref;
1826   }
1827
1828   $sth->finish;
1829
1830   $dbh->disconnect;
1831
1832   $main::lxdebug->leave_sub();
1833 }
1834
1835 sub get_tax {
1836   $main::lxdebug->enter_sub();
1837
1838   my ($self, $myconfig, $form) = @_;
1839
1840   # connect to database
1841   my $dbh = $form->dbconnect($myconfig);
1842
1843   my $query = qq|SELECT
1844                    taxkey,
1845                    taxdescription,
1846                    round(rate * 100, 2) AS rate,
1847                    chart_id
1848                  FROM tax
1849                  WHERE id = ? |;
1850
1851   my $sth = $dbh->prepare($query);
1852   $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})");
1853
1854   my $ref = $sth->fetchrow_hashref("NAME_lc");
1855
1856   map { $form->{$_} = $ref->{$_} } keys %$ref;
1857
1858   $sth->finish;
1859
1860   # see if it is used by a taxkey
1861   $query = qq|SELECT count(*) FROM taxkeys
1862               WHERE tax_id = ? AND chart_id >0|;
1863
1864   ($form->{orphaned}) = selectrow_query($form, $dbh, $query, $form->{id});
1865
1866   $form->{orphaned} = !$form->{orphaned};
1867   $sth->finish;
1868
1869   if (!$form->{orphaned} ) {
1870     $query = qq|SELECT DISTINCT c.id, c.accno
1871                 FROM taxkeys tk
1872                 JOIN   tax t ON (t.id = tk.tax_id)
1873                 JOIN chart c ON (c.id = tk.chart_id)
1874                 WHERE tk.tax_id = ?|;
1875
1876     $sth = $dbh->prepare($query);
1877     $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})");
1878
1879     $form->{TAXINUSE} = [];
1880     while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
1881       push @{ $form->{TAXINUSE} }, $ref;
1882     }
1883
1884     $sth->finish;
1885   }
1886
1887   $dbh->disconnect;
1888
1889   $main::lxdebug->leave_sub();
1890 }
1891
1892 sub save_tax {
1893   $main::lxdebug->enter_sub();
1894
1895   my ($self, $myconfig, $form) = @_;
1896   my $query;
1897
1898   # connect to database
1899   my $dbh = $form->get_standard_dbh($myconfig);
1900
1901   $form->{rate} = $form->{rate} / 100;
1902
1903   my @values = ($form->{taxkey}, $form->{taxdescription}, $form->{rate}, $form->{chart_id}, $form->{chart_id} );
1904   if ($form->{id} ne "") {
1905     $query = qq|UPDATE tax SET
1906                   taxkey         = ?,
1907                   taxdescription = ?,
1908                   rate           = ?,
1909                   chart_id       = ?,
1910                   taxnumber      = (SELECT accno FROM chart WHERE id= ? )
1911                 WHERE id = ?|;
1912     push(@values, $form->{id});
1913
1914   } else {
1915     #ok
1916     $query = qq|INSERT INTO tax (
1917                   taxkey,
1918                   taxdescription,
1919                   rate,
1920                   chart_id,
1921                   taxnumber
1922                 )
1923                 VALUES (?, ?, ?, ?, (SELECT accno FROM chart WHERE id = ?) )|;
1924   }
1925   do_query($form, $dbh, $query, @values);
1926
1927   $dbh->commit();
1928
1929   $main::lxdebug->leave_sub();
1930 }
1931
1932 sub delete_tax {
1933   $main::lxdebug->enter_sub();
1934
1935   my ($self, $myconfig, $form) = @_;
1936   my $query;
1937
1938   # connect to database
1939   my $dbh = $form->get_standard_dbh($myconfig);
1940
1941   $query = qq|DELETE FROM tax
1942               WHERE id = ?|;
1943   do_query($form, $dbh, $query, $form->{id});
1944
1945   $dbh->commit();
1946
1947   $main::lxdebug->leave_sub();
1948 }
1949
1950 sub save_price_factor {
1951   $main::lxdebug->enter_sub();
1952
1953   my ($self, $myconfig, $form) = @_;
1954
1955   # connect to database
1956   my $dbh = $form->get_standard_dbh($myconfig);
1957
1958   my $query;
1959   my @values = ($form->{description}, conv_i($form->{factor}));
1960
1961   if ($form->{id}) {
1962     $query = qq|UPDATE price_factors SET description = ?, factor = ? WHERE id = ?|;
1963     push @values, conv_i($form->{id});
1964
1965   } else {
1966     $query = qq|INSERT INTO price_factors (description, factor, sortkey) VALUES (?, ?, (SELECT COALESCE(MAX(sortkey), 0) + 1 FROM price_factors))|;
1967   }
1968
1969   do_query($form, $dbh, $query, @values);
1970
1971   $dbh->commit();
1972
1973   $main::lxdebug->leave_sub();
1974 }
1975
1976 sub get_all_price_factors {
1977   $main::lxdebug->enter_sub();
1978
1979   my ($self, $myconfig, $form) = @_;
1980
1981   # connect to database
1982   my $dbh = $form->get_standard_dbh($myconfig);
1983
1984   $form->{PRICE_FACTORS} = selectall_hashref_query($form, $dbh, qq|SELECT * FROM price_factors ORDER BY sortkey|);
1985
1986   $main::lxdebug->leave_sub();
1987 }
1988
1989 sub get_price_factor {
1990   $main::lxdebug->enter_sub();
1991
1992   my ($self, $myconfig, $form) = @_;
1993
1994   # connect to database
1995   my $dbh = $form->get_standard_dbh($myconfig);
1996
1997   my $query = qq|SELECT description, factor,
1998                    ((SELECT COUNT(*) FROM parts      WHERE price_factor_id = ?) +
1999                     (SELECT COUNT(*) FROM invoice    WHERE price_factor_id = ?) +
2000                     (SELECT COUNT(*) FROM orderitems WHERE price_factor_id = ?)) = 0 AS orphaned
2001                  FROM price_factors WHERE id = ?|;
2002
2003   ($form->{description}, $form->{factor}, $form->{orphaned}) = selectrow_query($form, $dbh, $query, (conv_i($form->{id})) x 4);
2004
2005   $main::lxdebug->leave_sub();
2006 }
2007
2008 sub delete_price_factor {
2009   $main::lxdebug->enter_sub();
2010
2011   my ($self, $myconfig, $form) = @_;
2012
2013   # connect to database
2014   my $dbh = $form->get_standard_dbh($myconfig);
2015
2016   do_query($form, $dbh, qq|DELETE FROM price_factors WHERE id = ?|, conv_i($form->{id}));
2017   $dbh->commit();
2018
2019   $main::lxdebug->leave_sub();
2020 }
2021
2022 sub save_warehouse {
2023   $main::lxdebug->enter_sub();
2024
2025   my ($self, $myconfig, $form) = @_;
2026
2027   # connect to database
2028   my $dbh = $form->get_standard_dbh($myconfig);
2029
2030   my ($query, @values, $sth);
2031
2032   if (!$form->{id}) {
2033     $query        = qq|SELECT nextval('id')|;
2034     ($form->{id}) = selectrow_query($form, $dbh, $query);
2035
2036     $query        = qq|INSERT INTO warehouse (id, sortkey) VALUES (?, (SELECT COALESCE(MAX(sortkey), 0) + 1 FROM warehouse))|;
2037     do_query($form, $dbh, $query, $form->{id});
2038   }
2039
2040   do_query($form, $dbh, qq|UPDATE warehouse SET description = ?, invalid = ? WHERE id = ?|,
2041            $form->{description}, $form->{invalid} ? 't' : 'f', conv_i($form->{id}));
2042
2043   if (0 < $form->{number_of_new_bins}) {
2044     $query = qq|INSERT INTO bin (warehouse_id, description) VALUES (?, ?)|;
2045     $sth   = prepare_query($form, $dbh, $query);
2046
2047     foreach my $i (1..$form->{number_of_new_bins}) {
2048       do_statement($form, $sth, $query, conv_i($form->{id}), "$form->{prefix}${i}");
2049     }
2050
2051     $sth->finish();
2052   }
2053
2054   $dbh->commit();
2055
2056   $main::lxdebug->leave_sub();
2057 }
2058
2059 sub save_bins {
2060   $main::lxdebug->enter_sub();
2061
2062   my ($self, $myconfig, $form) = @_;
2063
2064   # connect to database
2065   my $dbh = $form->get_standard_dbh($myconfig);
2066
2067   my ($query, @values, $commit_necessary, $sth);
2068
2069   @values = map { $form->{"id_${_}"} } grep { $form->{"delete_${_}"} } (1..$form->{rowcount});
2070
2071   if (@values) {
2072     $query = qq|DELETE FROM bin WHERE id IN (| . join(', ', ('?') x scalar(@values)) . qq|)|;
2073     do_query($form, $dbh, $query, @values);
2074
2075     $commit_necessary = 1;
2076   }
2077
2078   $query = qq|UPDATE bin SET description = ? WHERE id = ?|;
2079   $sth   = prepare_query($form, $dbh, $query);
2080
2081   foreach my $row (1..$form->{rowcount}) {
2082     next if ($form->{"delete_${row}"});
2083
2084     do_statement($form, $sth, $query, $form->{"description_${row}"}, conv_i($form->{"id_${row}"}));
2085
2086     $commit_necessary = 1;
2087   }
2088
2089   $sth->finish();
2090
2091   $dbh->commit() if ($commit_necessary);
2092
2093   $main::lxdebug->leave_sub();
2094 }
2095
2096 sub delete_warehouse {
2097   $main::lxdebug->enter_sub();
2098
2099   my ($self, $myconfig, $form) = @_;
2100
2101   # connect to database
2102   my $dbh = $form->get_standard_dbh($myconfig);
2103
2104   my $id      = conv_i($form->{id});
2105   my $query   = qq|SELECT i.bin_id FROM inventory i WHERE i.bin_id IN (SELECT b.id FROM bin b WHERE b.warehouse_id = ?) LIMIT 1|;
2106   my ($count) = selectrow_query($form, $dbh, $query, $id);
2107
2108   if ($count) {
2109     $main::lxdebug->leave_sub();
2110     return 0;
2111   }
2112
2113   do_query($form, $dbh, qq|DELETE FROM bin       WHERE warehouse_id = ?|, conv_i($form->{id}));
2114   do_query($form, $dbh, qq|DELETE FROM warehouse WHERE id           = ?|, conv_i($form->{id}));
2115
2116   $dbh->commit();
2117
2118   $main::lxdebug->leave_sub();
2119
2120   return 1;
2121 }
2122
2123 sub get_all_warehouses {
2124   $main::lxdebug->enter_sub();
2125
2126   my ($self, $myconfig, $form) = @_;
2127
2128   # connect to database
2129   my $dbh = $form->get_standard_dbh($myconfig);
2130
2131   my $query = qq|SELECT w.id, w.description, w.invalid,
2132                    (SELECT COUNT(b.description) FROM bin b WHERE b.warehouse_id = w.id) AS number_of_bins
2133                  FROM warehouse w
2134                  ORDER BY w.sortkey|;
2135
2136   $form->{WAREHOUSES} = selectall_hashref_query($form, $dbh, $query);
2137
2138   $main::lxdebug->leave_sub();
2139 }
2140
2141 sub get_warehouse {
2142   $main::lxdebug->enter_sub();
2143
2144   my ($self, $myconfig, $form) = @_;
2145
2146   # connect to database
2147   my $dbh = $form->get_standard_dbh($myconfig);
2148
2149   my $id    = conv_i($form->{id});
2150   my $query = qq|SELECT w.description, w.invalid
2151                  FROM warehouse w
2152                  WHERE w.id = ?|;
2153
2154   my $ref   = selectfirst_hashref_query($form, $dbh, $query, $id);
2155
2156   map { $form->{$_} = $ref->{$_} } keys %{ $ref };
2157
2158   $query = qq|SELECT b.*, EXISTS
2159                 (SELECT i.warehouse_id
2160                  FROM inventory i
2161                  WHERE i.bin_id = b.id
2162                  LIMIT 1)
2163                 AS in_use
2164               FROM bin b
2165               WHERE b.warehouse_id = ?|;
2166
2167   $form->{BINS} = selectall_hashref_query($form, $dbh, $query, conv_i($form->{id}));
2168
2169   $main::lxdebug->leave_sub();
2170 }
2171
2172 1;