Emailversand: Anhangnamen auch bei Gutschriften vorbelegen.
[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 Data::Dumper;
41 use SL::DBUtils;
42
43 sub get_account {
44   $main::lxdebug->enter_sub();
45
46   my ($self, $myconfig, $form) = @_;
47
48   $form->{id} = "NULL" unless ($form->{id});
49
50   # connect to database
51   my $dbh = $form->dbconnect($myconfig);
52   my $query = qq§SELECT c.accno, c.description, c.charttype, c.gifi_accno,
53                  c.category,c.link, tk.taxkey_id, tk.pos_ustva, tk.tax_id,tk.tax_id||'--'||tk.taxkey_id AS tax, tk.startdate, c.pos_bilanz, c.pos_eur, c.new_chart_id, c.valid_from, c.pos_bwa
54                 FROM chart c LEFT JOIN taxkeys tk
55                 ON (c.id=tk.chart_id AND tk.id = (SELECT id from taxkeys where taxkeys.chart_id =c.id AND startdate<=current_date ORDER BY startdate desc LIMIT 1))
56                 WHERE c.id = $form->{id}§;
57
58
59   my $sth = $dbh->prepare($query);
60   $sth->execute || $form->dberror($query);
61
62   my $ref = $sth->fetchrow_hashref(NAME_lc);
63
64   foreach my $key (keys %$ref) {
65     $form->{"$key"} = $ref->{"$key"};
66   }
67
68   $sth->finish;
69
70   # get default accounts
71   $query = qq|SELECT inventory_accno_id, income_accno_id, expense_accno_id
72               FROM defaults|;
73   $sth = $dbh->prepare($query);
74   $sth->execute || $form->dberror($query);
75
76   $ref = $sth->fetchrow_hashref(NAME_lc);
77
78   map { $form->{$_} = $ref->{$_} } keys %ref;
79
80   $sth->finish;
81
82   # get taxkeys and description
83   $query = qq§SELECT id, taxkey,id||'--'||taxkey AS tax, taxdescription
84               FROM tax ORDER BY taxkey§;
85   $sth = $dbh->prepare($query);
86   $sth->execute || $form->dberror($query);
87
88   $form->{TAXKEY} = [];
89
90   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
91     push @{ $form->{TAXKEY} }, $ref;
92   }
93
94   $sth->finish;
95   if ($form->{id}) {
96
97     $where = " WHERE link='$form->{link}'";
98
99
100     # get new accounts
101     $query = qq|SELECT id, accno,description
102                 FROM chart $where|;
103     $sth = $dbh->prepare($query);
104     $sth->execute || $form->dberror($query);
105
106     while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
107       push @{ $form->{NEWACCOUNT} }, $ref;
108     }
109
110     $sth->finish;
111   }
112   # check if we have any transactions
113   $query = qq|SELECT a.trans_id FROM acc_trans a
114               WHERE a.chart_id = $form->{id}|;
115   $sth = $dbh->prepare($query);
116   $sth->execute || $form->dberror($query);
117
118   ($form->{orphaned}) = $sth->fetchrow_array;
119   $form->{orphaned} = !$form->{orphaned};
120   $sth->finish;
121
122   # check if new account is active
123   $form->{new_chart_valid} = 0;
124   if ($form->{new_chart_id}) {
125     $query = qq|SELECT current_date-valid_from FROM chart
126               WHERE id = $form->{id}|;
127     $sth = $dbh->prepare($query);
128     $sth->execute || $form->dberror($query);
129
130     my ($count) = $sth->fetchrow_array;
131     if ($count >=0) {
132       $form->{new_chart_valid} = 1;
133     }
134     $sth->finish;
135   }
136
137   $dbh->disconnect;
138
139   $main::lxdebug->leave_sub();
140 }
141
142 sub save_account {
143   $main::lxdebug->enter_sub();
144
145   my ($self, $myconfig, $form) = @_;
146
147   # connect to database, turn off AutoCommit
148   my $dbh = $form->dbconnect_noauto($myconfig);
149
150   # sanity check, can't have AR with AR_...
151   if ($form->{AR} || $form->{AP} || $form->{IC}) {
152     map { delete $form->{$_} }
153       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);
154   }
155
156   $form->{link} = "";
157   foreach my $item ($form->{AR},            $form->{AR_amount},
158                     $form->{AR_tax},        $form->{AR_paid},
159                     $form->{AP},            $form->{AP_amount},
160                     $form->{AP_tax},        $form->{AP_paid},
161                     $form->{IC},            $form->{IC_sale},
162                     $form->{IC_cogs},       $form->{IC_taxpart},
163                     $form->{IC_income},     $form->{IC_expense},
164                     $form->{IC_taxservice}, $form->{CT_tax}
165     ) {
166     $form->{link} .= "${item}:" if ($item);
167   }
168   chop $form->{link};
169
170   # if we have an id then replace the old record
171   $form->{description} =~ s/\'/\'\'/g;
172
173   # strip blanks from accno
174   map { $form->{$_} =~ s/ //g; } qw(accno);
175
176   my ($query, $sth);
177
178   if ($form->{id} eq "NULL") {
179     $form->{id} = "";
180   }
181
182   map({ $form->{$_} = "NULL" unless ($form->{$_}); }
183       qw(pos_ustva pos_bwa pos_bilanz pos_eur new_chart_id));
184   my($tax_id, $taxkey) = split /--/, $form->{tax};
185   $form->{valid_from} = ($form->{valid_from}) ? "'$form->{valid_from}'" : "NULL";
186   my $startdate = ($form->{startdate}) ? "'$form->{startdate}'" : "'1970-01-01'";
187   if ($form->{id} && $form->{orphaned}) {
188     $query = qq|UPDATE chart SET
189                 accno = '$form->{accno}',
190                 description = '$form->{description}',
191                 charttype = '$form->{charttype}',
192                 gifi_accno = '$form->{gifi_accno}',
193                 category = '$form->{category}',
194                 link = '$form->{link}',
195                 taxkey_id = $taxkey,
196                 pos_ustva = $form->{pos_ustva},
197                 pos_bwa   = $form->{pos_bwa},
198                 pos_bilanz = $form->{pos_bilanz},
199                 pos_eur = $form->{pos_eur},
200                 new_chart_id = $form->{new_chart_id},
201                 valid_from = $form->{valid_from}
202                 WHERE id = $form->{id}|;
203   } elsif ($form->{id} && !$form->{new_chart_valid}) {
204      $query = qq|UPDATE chart SET
205                 new_chart_id = $form->{new_chart_id},
206                 valid_from = $form->{valid_from}
207                 WHERE id = $form->{id}|;
208   } else {
209
210     $query = qq|INSERT INTO chart
211                 (accno, description, charttype, gifi_accno, category, link, taxkey_id, pos_ustva, pos_bwa, pos_bilanz,pos_eur, new_chart_id, valid_from)
212                 VALUES ('$form->{accno}', '$form->{description}',
213                 '$form->{charttype}', '$form->{gifi_accno}',
214                 '$form->{category}', '$form->{link}', $taxkey, $form->{pos_ustva}, $form->{pos_bwa}, $form->{pos_bilanz}, $form->{pos_eur}, $form->{new_chart_id}, $form->{valid_from})|;
215   }
216   $dbh->do($query) || $form->dberror($query);
217
218   #Save Taxes
219   if (!$form->{id}) {
220     $query = qq|INSERT INTO taxkeys (chart_id,tax_id,taxkey_id, pos_ustva, startdate) VALUES ((SELECT id FROM chart where accno='$form->{accno}'), $tax_id, $taxkey,$form->{pos_ustva}, $startdate)|;
221     $dbh->do($query) || $form->dberror($query);
222   } else {
223     $query = qq|DELETE FROM taxkeys WHERE chart_id=$form->{id} AND tax_id=$tax_id|;
224     $dbh->do($query) || $form->dberror($query);
225     $query = qq|INSERT INTO taxkeys (chart_id,tax_id,taxkey_id, pos_ustva, startdate) VALUES ($form->{id}, $tax_id, $taxkey,$form->{pos_ustva}, $startdate)|;
226     $dbh->do($query) || $form->dberror($query);
227   }
228
229 #   if ($form->{IC_taxpart} || $form->{IC_taxservice} || $form->{CT_tax}) {
230 #
231 #     my $chart_id = $form->{id};
232 #
233 #     unless ($form->{id}) {
234 #
235 #       # get id from chart
236 #       $query = qq|SELECT c.id
237 #                   FROM chart c
238 #                 WHERE c.accno = '$form->{accno}'|;
239 #       $sth = $dbh->prepare($query);
240 #       $sth->execute || $form->dberror($query);
241 #
242 #       ($chart_id) = $sth->fetchrow_array;
243 #       $sth->finish;
244 #     }
245 #
246 #     # add account if it doesn't exist in tax
247 #     $query = qq|SELECT t.chart_id
248 #                 FROM tax t
249 #               WHERE t.chart_id = $chart_id|;
250 #     $sth = $dbh->prepare($query);
251 #     $sth->execute || $form->dberror($query);
252 #
253 #     my ($tax_id) = $sth->fetchrow_array;
254 #     $sth->finish;
255 #
256 #     # add tax if it doesn't exist
257 #     unless ($tax_id) {
258 #       $query = qq|INSERT INTO tax (chart_id, rate)
259 #                   VALUES ($chart_id, 0)|;
260 #       $dbh->do($query) || $form->dberror($query);
261 #     }
262 #   } else {
263 #
264 #     # remove tax
265 #     if ($form->{id}) {
266 #       $query = qq|DELETE FROM tax
267 #                 WHERE chart_id = $form->{id}|;
268 #       $dbh->do($query) || $form->dberror($query);
269 #     }
270 #   }
271
272   # commit
273   my $rc = $dbh->commit;
274   $dbh->disconnect;
275
276   $main::lxdebug->leave_sub();
277
278   return $rc;
279 }
280
281 sub delete_account {
282   $main::lxdebug->enter_sub();
283
284   my ($self, $myconfig, $form) = @_;
285
286   # connect to database, turn off AutoCommit
287   my $dbh = $form->dbconnect_noauto($myconfig);
288
289   my $query = qq|SELECT count(*) FROM acc_trans a
290                  WHERE a.chart_id = $form->{id}|;
291   my $sth = $dbh->prepare($query);
292   $sth->execute || $form->dberror($query);
293
294   if ($sth->fetchrow_array) {
295     $sth->finish;
296     $dbh->disconnect;
297     $main::lxdebug->leave_sub();
298     return;
299   }
300   $sth->finish;
301
302   # delete chart of account record
303   $query = qq|DELETE FROM chart
304               WHERE id = $form->{id}|;
305   $dbh->do($query) || $form->dberror($query);
306
307   # set inventory_accno_id, income_accno_id, expense_accno_id to defaults
308   $query = qq|UPDATE parts
309               SET inventory_accno_id =
310                          (SELECT inventory_accno_id FROM defaults)
311               WHERE inventory_accno_id = $form->{id}|;
312   $dbh->do($query) || $form->dberror($query);
313
314   $query = qq|UPDATE parts
315               SET income_accno_id =
316                          (SELECT income_accno_id FROM defaults)
317               WHERE income_accno_id = $form->{id}|;
318   $dbh->do($query) || $form->dberror($query);
319
320   $query = qq|UPDATE parts
321               SET expense_accno_id =
322                          (SELECT expense_accno_id FROM defaults)
323               WHERE expense_accno_id = $form->{id}|;
324   $dbh->do($query) || $form->dberror($query);
325
326   foreach my $table (qw(partstax customertax vendortax tax)) {
327     $query = qq|DELETE FROM $table
328                 WHERE chart_id = $form->{id}|;
329     $dbh->do($query) || $form->dberror($query);
330   }
331
332   # commit and redirect
333   my $rc = $dbh->commit;
334   $dbh->disconnect;
335
336   $main::lxdebug->leave_sub();
337
338   return $rc;
339 }
340
341 sub gifi_accounts {
342   $main::lxdebug->enter_sub();
343
344   my ($self, $myconfig, $form) = @_;
345
346   # connect to database
347   my $dbh = $form->dbconnect($myconfig);
348
349   my $query = qq|SELECT accno, description
350                  FROM gifi
351                  ORDER BY accno|;
352
353   $sth = $dbh->prepare($query);
354   $sth->execute || $form->dberror($query);
355
356   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
357     push @{ $form->{ALL} }, $ref;
358   }
359
360   $sth->finish;
361   $dbh->disconnect;
362
363   $main::lxdebug->leave_sub();
364 }
365
366 sub get_gifi {
367   $main::lxdebug->enter_sub();
368
369   my ($self, $myconfig, $form) = @_;
370
371   # connect to database
372   my $dbh = $form->dbconnect($myconfig);
373
374   my $query = qq|SELECT g.accno, g.description
375                  FROM gifi g
376                  WHERE g.accno = '$form->{accno}'|;
377   my $sth = $dbh->prepare($query);
378   $sth->execute || $form->dberror($query);
379
380   my $ref = $sth->fetchrow_hashref(NAME_lc);
381
382   map { $form->{$_} = $ref->{$_} } keys %$ref;
383
384   $sth->finish;
385
386   # check for transactions
387   $query = qq|SELECT count(*) FROM acc_trans a, chart c, gifi g
388               WHERE c.gifi_accno = g.accno
389               AND a.chart_id = c.id
390               AND g.accno = '$form->{accno}'|;
391   $sth = $dbh->prepare($query);
392   $sth->execute || $form->dberror($query);
393
394   ($form->{orphaned}) = $sth->fetchrow_array;
395   $sth->finish;
396   $form->{orphaned} = !$form->{orphaned};
397
398   $dbh->disconnect;
399
400   $main::lxdebug->leave_sub();
401 }
402
403 sub save_gifi {
404   $main::lxdebug->enter_sub();
405
406   my ($self, $myconfig, $form) = @_;
407
408   # connect to database
409   my $dbh = $form->dbconnect($myconfig);
410
411   $form->{description} =~ s/\'/\'\'/g;
412
413   # id is the old account number!
414   if ($form->{id}) {
415     $query = qq|UPDATE gifi SET
416                 accno = '$form->{accno}',
417                 description = '$form->{description}'
418                 WHERE accno = '$form->{id}'|;
419   } else {
420     $query = qq|INSERT INTO gifi
421                 (accno, description)
422                 VALUES ('$form->{accno}', '$form->{description}')|;
423   }
424   $dbh->do($query) || $form->dberror($query);
425
426   $dbh->disconnect;
427
428   $main::lxdebug->leave_sub();
429 }
430
431 sub delete_gifi {
432   $main::lxdebug->enter_sub();
433
434   my ($self, $myconfig, $form) = @_;
435
436   # connect to database
437   my $dbh = $form->dbconnect($myconfig);
438
439   # id is the old account number!
440   $query = qq|DELETE FROM gifi
441               WHERE accno = '$form->{id}'|;
442   $dbh->do($query) || $form->dberror($query);
443
444   $dbh->disconnect;
445
446   $main::lxdebug->leave_sub();
447 }
448
449 sub warehouses {
450   $main::lxdebug->enter_sub();
451
452   my ($self, $myconfig, $form) = @_;
453
454   # connect to database
455   my $dbh = $form->dbconnect($myconfig);
456
457   my $query = qq|SELECT id, description
458                  FROM warehouse
459                  ORDER BY 2|;
460
461   $sth = $dbh->prepare($query);
462   $sth->execute || $form->dberror($query);
463
464   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
465     push @{ $form->{ALL} }, $ref;
466   }
467
468   $sth->finish;
469   $dbh->disconnect;
470
471   $main::lxdebug->leave_sub();
472 }
473
474 sub get_warehouse {
475   $main::lxdebug->enter_sub();
476
477   my ($self, $myconfig, $form) = @_;
478
479   # connect to database
480   my $dbh = $form->dbconnect($myconfig);
481
482   my $query = qq|SELECT w.description
483                  FROM warehouse w
484                  WHERE w.id = $form->{id}|;
485   my $sth = $dbh->prepare($query);
486   $sth->execute || $form->dberror($query);
487
488   my $ref = $sth->fetchrow_hashref(NAME_lc);
489
490   map { $form->{$_} = $ref->{$_} } keys %$ref;
491
492   $sth->finish;
493
494   # see if it is in use
495   $query = qq|SELECT count(*) FROM inventory i
496               WHERE i.warehouse_id = $form->{id}|;
497   $sth = $dbh->prepare($query);
498   $sth->execute || $form->dberror($query);
499
500   ($form->{orphaned}) = $sth->fetchrow_array;
501   $form->{orphaned} = !$form->{orphaned};
502   $sth->finish;
503
504   $dbh->disconnect;
505
506   $main::lxdebug->leave_sub();
507 }
508
509 sub save_warehouse {
510   $main::lxdebug->enter_sub();
511
512   my ($self, $myconfig, $form) = @_;
513
514   # connect to database
515   my $dbh = $form->dbconnect($myconfig);
516
517   $form->{description} =~ s/\'/\'\'/g;
518
519   if ($form->{id}) {
520     $query = qq|UPDATE warehouse SET
521                 description = '$form->{description}'
522                 WHERE id = $form->{id}|;
523   } else {
524     $query = qq|INSERT INTO warehouse
525                 (description)
526                 VALUES ('$form->{description}')|;
527   }
528   $dbh->do($query) || $form->dberror($query);
529
530   $dbh->disconnect;
531
532   $main::lxdebug->leave_sub();
533 }
534
535 sub delete_warehouse {
536   $main::lxdebug->enter_sub();
537
538   my ($self, $myconfig, $form) = @_;
539
540   # connect to database
541   my $dbh = $form->dbconnect($myconfig);
542
543   $query = qq|DELETE FROM warehouse
544               WHERE id = $form->{id}|;
545   $dbh->do($query) || $form->dberror($query);
546
547   $dbh->disconnect;
548
549   $main::lxdebug->leave_sub();
550 }
551
552 sub departments {
553   $main::lxdebug->enter_sub();
554
555   my ($self, $myconfig, $form) = @_;
556
557   # connect to database
558   my $dbh = $form->dbconnect($myconfig);
559
560   my $query = qq|SELECT d.id, d.description, d.role
561                  FROM department d
562                  ORDER BY 2|;
563
564   $sth = $dbh->prepare($query);
565   $sth->execute || $form->dberror($query);
566
567   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
568     push @{ $form->{ALL} }, $ref;
569   }
570
571   $sth->finish;
572   $dbh->disconnect;
573
574   $main::lxdebug->leave_sub();
575 }
576
577 sub get_department {
578   $main::lxdebug->enter_sub();
579
580   my ($self, $myconfig, $form) = @_;
581
582   # connect to database
583   my $dbh = $form->dbconnect($myconfig);
584
585   my $query = qq|SELECT d.description, d.role
586                  FROM department d
587                  WHERE d.id = $form->{id}|;
588   my $sth = $dbh->prepare($query);
589   $sth->execute || $form->dberror($query);
590
591   my $ref = $sth->fetchrow_hashref(NAME_lc);
592
593   map { $form->{$_} = $ref->{$_} } keys %$ref;
594
595   $sth->finish;
596
597   # see if it is in use
598   $query = qq|SELECT count(*) FROM dpt_trans d
599               WHERE d.department_id = $form->{id}|;
600   $sth = $dbh->prepare($query);
601   $sth->execute || $form->dberror($query);
602
603   ($form->{orphaned}) = $sth->fetchrow_array;
604   $form->{orphaned} = !$form->{orphaned};
605   $sth->finish;
606
607   $dbh->disconnect;
608
609   $main::lxdebug->leave_sub();
610 }
611
612 sub save_department {
613   $main::lxdebug->enter_sub();
614
615   my ($self, $myconfig, $form) = @_;
616
617   # connect to database
618   my $dbh = $form->dbconnect($myconfig);
619
620   $form->{description} =~ s/\'/\'\'/g;
621
622   if ($form->{id}) {
623     $query = qq|UPDATE department SET
624                 description = '$form->{description}',
625                 role = '$form->{role}'
626                 WHERE id = $form->{id}|;
627   } else {
628     $query = qq|INSERT INTO department
629                 (description, role)
630                 VALUES ('$form->{description}', '$form->{role}')|;
631   }
632   $dbh->do($query) || $form->dberror($query);
633
634   $dbh->disconnect;
635
636   $main::lxdebug->leave_sub();
637 }
638
639 sub delete_department {
640   $main::lxdebug->enter_sub();
641
642   my ($self, $myconfig, $form) = @_;
643
644   # connect to database
645   my $dbh = $form->dbconnect($myconfig);
646
647   $query = qq|DELETE FROM department
648               WHERE id = $form->{id}|;
649   $dbh->do($query) || $form->dberror($query);
650
651   $dbh->disconnect;
652
653   $main::lxdebug->leave_sub();
654 }
655
656 sub lead {
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|SELECT id, lead
665                  FROM leads
666                  ORDER BY 2|;
667
668   $sth = $dbh->prepare($query);
669   $sth->execute || $form->dberror($query);
670
671   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
672     push @{ $form->{ALL} }, $ref;
673   }
674
675   $sth->finish;
676   $dbh->disconnect;
677
678   $main::lxdebug->leave_sub();
679 }
680
681 sub get_lead {
682   $main::lxdebug->enter_sub();
683
684   my ($self, $myconfig, $form) = @_;
685
686   # connect to database
687   my $dbh = $form->dbconnect($myconfig);
688
689   my $query =
690     qq|SELECT l.id, l.lead
691                  FROM leads l
692                  WHERE l.id = $form->{id}|;
693   my $sth = $dbh->prepare($query);
694   $sth->execute || $form->dberror($query);
695
696   my $ref = $sth->fetchrow_hashref(NAME_lc);
697
698   map { $form->{$_} = $ref->{$_} } keys %$ref;
699
700   $sth->finish;
701
702   $dbh->disconnect;
703
704   $main::lxdebug->leave_sub();
705 }
706
707 sub save_lead {
708   $main::lxdebug->enter_sub();
709
710   my ($self, $myconfig, $form) = @_;
711
712   # connect to database
713   my $dbh = $form->dbconnect($myconfig);
714
715   $form->{lead} =~ s/\'/\'\'/g;
716
717   # id is the old record
718   if ($form->{id}) {
719     $query = qq|UPDATE leads SET
720                 lead = '$form->{description}'
721                 WHERE id = $form->{id}|;
722   } else {
723     $query = qq|INSERT INTO leads
724                 (lead)
725                 VALUES ('$form->{description}')|;
726   }
727   $dbh->do($query) || $form->dberror($query);
728
729   $dbh->disconnect;
730
731   $main::lxdebug->leave_sub();
732 }
733
734 sub delete_lead {
735   $main::lxdebug->enter_sub();
736
737   my ($self, $myconfig, $form) = @_;
738
739   # connect to database
740   my $dbh = $form->dbconnect($myconfig);
741
742   $query = qq|DELETE FROM leads
743               WHERE id = $form->{id}|;
744   $dbh->do($query) || $form->dberror($query);
745
746   $dbh->disconnect;
747
748   $main::lxdebug->leave_sub();
749 }
750
751 sub business {
752   $main::lxdebug->enter_sub();
753
754   my ($self, $myconfig, $form) = @_;
755
756   # connect to database
757   my $dbh = $form->dbconnect($myconfig);
758
759   my $query = qq|SELECT id, description, discount, customernumberinit, salesman
760                  FROM business
761                  ORDER BY 2|;
762
763   $sth = $dbh->prepare($query);
764   $sth->execute || $form->dberror($query);
765
766   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
767     push @{ $form->{ALL} }, $ref;
768   }
769
770   $sth->finish;
771   $dbh->disconnect;
772
773   $main::lxdebug->leave_sub();
774 }
775
776 sub get_business {
777   $main::lxdebug->enter_sub();
778
779   my ($self, $myconfig, $form) = @_;
780
781   # connect to database
782   my $dbh = $form->dbconnect($myconfig);
783
784   my $query =
785     qq|SELECT b.description, b.discount, b.customernumberinit, b.salesman
786                  FROM business b
787                  WHERE b.id = $form->{id}|;
788   my $sth = $dbh->prepare($query);
789   $sth->execute || $form->dberror($query);
790
791   my $ref = $sth->fetchrow_hashref(NAME_lc);
792
793   map { $form->{$_} = $ref->{$_} } keys %$ref;
794
795   $sth->finish;
796
797   $dbh->disconnect;
798
799   $main::lxdebug->leave_sub();
800 }
801
802 sub save_business {
803   $main::lxdebug->enter_sub();
804
805   my ($self, $myconfig, $form) = @_;
806
807   # connect to database
808   my $dbh = $form->dbconnect($myconfig);
809
810   $form->{description} =~ s/\'/\'\'/g;
811   $form->{discount} /= 100;
812   $form->{salesman} *= 1;
813
814   # id is the old record
815   if ($form->{id}) {
816     $query = qq|UPDATE business SET
817                 description = '$form->{description}',
818                 discount = $form->{discount},
819                 customernumberinit = '$form->{customernumberinit}',
820                 salesman = '$form->{salesman}'
821                 WHERE id = $form->{id}|;
822   } else {
823     $query = qq|INSERT INTO business
824                 (description, discount, customernumberinit, salesman)
825                 VALUES ('$form->{description}', $form->{discount}, '$form->{customernumberinit}', '$form->{salesman}')|;
826   }
827   $dbh->do($query) || $form->dberror($query);
828
829   $dbh->disconnect;
830
831   $main::lxdebug->leave_sub();
832 }
833
834 sub delete_business {
835   $main::lxdebug->enter_sub();
836
837   my ($self, $myconfig, $form) = @_;
838
839   # connect to database
840   my $dbh = $form->dbconnect($myconfig);
841
842   $query = qq|DELETE FROM business
843               WHERE id = $form->{id}|;
844   $dbh->do($query) || $form->dberror($query);
845
846   $dbh->disconnect;
847
848   $main::lxdebug->leave_sub();
849 }
850
851
852 sub language {
853   $main::lxdebug->enter_sub();
854
855   my ($self, $myconfig, $form, $return_list) = @_;
856
857   # connect to database
858   my $dbh = $form->dbconnect($myconfig);
859
860   my $query =
861     "SELECT id, description, template_code, article_code, " .
862     "  output_numberformat, output_dateformat, output_longdates " .
863     "FROM language ORDER BY description";
864
865   $sth = $dbh->prepare($query);
866   $sth->execute || $form->dberror($query);
867
868   my $ary = [];
869
870   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
871     push(@{ $ary }, $ref);
872   }
873
874   $sth->finish;
875   $dbh->disconnect;
876
877   $main::lxdebug->leave_sub();
878
879   if ($return_list) {
880     return @{$ary};
881   } else {
882     $form->{ALL} = $ary;
883   }
884 }
885
886 sub get_language {
887   $main::lxdebug->enter_sub();
888
889   my ($self, $myconfig, $form) = @_;
890
891   # connect to database
892   my $dbh = $form->dbconnect($myconfig);
893
894   my $query =
895     "SELECT description, template_code, article_code, " .
896     "  output_numberformat, output_dateformat, output_longdates " .
897     "FROM language WHERE id = ?";
898   my $sth = $dbh->prepare($query);
899   $sth->execute($form->{"id"}) || $form->dberror($query . " ($form->{id})");
900
901   my $ref = $sth->fetchrow_hashref(NAME_lc);
902
903   map { $form->{$_} = $ref->{$_} } keys %$ref;
904
905   $sth->finish;
906
907   $dbh->disconnect;
908
909   $main::lxdebug->leave_sub();
910 }
911
912 sub get_language_details {
913   $main::lxdebug->enter_sub();
914
915   my ($self, $myconfig, $form, $id) = @_;
916
917   # connect to database
918   my $dbh = $form->dbconnect($myconfig);
919
920   my $query =
921     "SELECT template_code, " .
922     "  output_numberformat, output_dateformat, output_longdates " .
923     "FROM language WHERE id = ?";
924   my @res = $dbh->selectrow_array($query, undef, $id);
925   $dbh->disconnect;
926
927   $main::lxdebug->leave_sub();
928
929   return @res;
930 }
931
932 sub save_language {
933   $main::lxdebug->enter_sub();
934
935   my ($self, $myconfig, $form) = @_;
936
937   # connect to database
938   my $dbh = $form->dbconnect($myconfig);
939   my (@values, $query);
940
941   map({ push(@values, $form->{$_}); }
942       qw(description template_code article_code
943          output_numberformat output_dateformat output_longdates));
944
945   # id is the old record
946   if ($form->{id}) {
947     $query =
948       "UPDATE language SET " .
949       "  description = ?, template_code = ?, article_code = ?, " .
950       "  output_numberformat = ?, output_dateformat = ?, " .
951       "  output_longdates = ? " .
952       "WHERE id = ?";
953     push(@values, $form->{id});
954   } else {
955     $query =
956       "INSERT INTO language (" .
957       "  description, template_code, article_code, " .
958       "  output_numberformat, output_dateformat, output_longdates" .
959       ") VALUES (?, ?, ?, ?, ?, ?)";
960   }
961   $dbh->do($query, undef, @values) ||
962     $form->dberror($query . " (" . join(", ", @values) . ")");
963
964   $dbh->disconnect;
965
966   $main::lxdebug->leave_sub();
967 }
968
969 sub delete_language {
970   $main::lxdebug->enter_sub();
971
972   my ($self, $myconfig, $form) = @_;
973
974   # connect to database
975   my $dbh = $form->dbconnect_noauto($myconfig);
976
977   foreach my $table (qw(translation_payment_terms units_language)) {
978     my $query = qq|DELETE FROM $table WHERE language_id = ?|;
979     do_query($form, $dbh, $query, $form->{"id"});
980   }
981
982   $query = "DELETE FROM language WHERE id = ?";
983   do_query($form, $dbh, $query, $form->{"id"});
984
985   $dbh->commit();
986   $dbh->disconnect;
987
988   $main::lxdebug->leave_sub();
989 }
990
991
992 sub buchungsgruppe {
993   $main::lxdebug->enter_sub();
994
995   my ($self, $myconfig, $form) = @_;
996
997   # connect to database
998   my $dbh = $form->dbconnect($myconfig);
999
1000   my $query = qq|SELECT id, description,
1001                  inventory_accno_id,
1002                  (SELECT accno FROM chart WHERE id = inventory_accno_id) AS inventory_accno,
1003                  income_accno_id_0,
1004                  (SELECT accno FROM chart WHERE id = income_accno_id_0) AS income_accno_0,
1005                  expense_accno_id_0,
1006                  (SELECT accno FROM chart WHERE id = expense_accno_id_0) AS expense_accno_0,
1007                  income_accno_id_1,
1008                  (SELECT accno FROM chart WHERE id = income_accno_id_1) AS income_accno_1,
1009                  expense_accno_id_1,
1010                  (SELECT accno FROM chart WHERE id = expense_accno_id_1) AS expense_accno_1,
1011                  income_accno_id_2,
1012                  (SELECT accno FROM chart WHERE id = income_accno_id_2) AS income_accno_2,
1013                  expense_accno_id_2,
1014                  (select accno FROM chart WHERE id = expense_accno_id_2) AS expense_accno_2,
1015                  income_accno_id_3,
1016                  (SELECT accno FROM chart WHERE id = income_accno_id_3) AS income_accno_3,
1017                  expense_accno_id_3,
1018                  (SELECT accno FROM chart WHERE id = expense_accno_id_3) AS expense_accno_3
1019                  FROM buchungsgruppen
1020                  ORDER BY sortkey|;
1021
1022   $sth = $dbh->prepare($query);
1023   $sth->execute || $form->dberror($query);
1024
1025   $form->{ALL} = [];
1026   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1027     push @{ $form->{ALL} }, $ref;
1028   }
1029
1030   $sth->finish;
1031   $dbh->disconnect;
1032
1033   $main::lxdebug->leave_sub();
1034 }
1035
1036 sub get_buchungsgruppe {
1037   $main::lxdebug->enter_sub();
1038
1039   my ($self, $myconfig, $form) = @_;
1040
1041   # connect to database
1042   my $dbh = $form->dbconnect($myconfig);
1043
1044   if ($form->{id}) {
1045     my $query =
1046       qq|SELECT description, inventory_accno_id,
1047          (SELECT accno FROM chart WHERE id = inventory_accno_id) AS inventory_accno,
1048          income_accno_id_0,
1049          (SELECT accno FROM chart WHERE id = income_accno_id_0) AS income_accno_0,
1050          expense_accno_id_0,
1051          (SELECT accno FROM chart WHERE id = expense_accno_id_0) AS expense_accno_0,
1052          income_accno_id_1,
1053          (SELECT accno FROM chart WHERE id = income_accno_id_1) AS income_accno_1,
1054          expense_accno_id_1,
1055          (SELECT accno FROM chart WHERE id = expense_accno_id_1) AS expense_accno_1,
1056          income_accno_id_2,
1057          (SELECT accno FROM chart WHERE id = income_accno_id_2) AS income_accno_2,
1058          expense_accno_id_2,
1059          (select accno FROM chart WHERE id = expense_accno_id_2) AS expense_accno_2,
1060          income_accno_id_3,
1061          (SELECT accno FROM chart WHERE id = income_accno_id_3) AS income_accno_3,
1062          expense_accno_id_3,
1063          (SELECT accno FROM chart WHERE id = expense_accno_id_3) AS expense_accno_3
1064          FROM buchungsgruppen
1065          WHERE id = ?|;
1066     my $sth = $dbh->prepare($query);
1067     $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})");
1068
1069     my $ref = $sth->fetchrow_hashref(NAME_lc);
1070
1071     map { $form->{$_} = $ref->{$_} } keys %$ref;
1072
1073     $sth->finish;
1074
1075     my $query =
1076       qq|SELECT count(id) = 0 AS orphaned
1077          FROM parts
1078          WHERE buchungsgruppen_id = ?|;
1079     ($form->{orphaned}) = $dbh->selectrow_array($query, undef, $form->{id});
1080     $form->dberror($query . " ($form->{id})") if ($dbh->err);
1081   }
1082
1083   $query = "SELECT inventory_accno_id, income_accno_id, expense_accno_id ".
1084     "FROM defaults";
1085   ($form->{"std_inventory_accno_id"}, $form->{"std_income_accno_id"},
1086    $form->{"std_expense_accno_id"}) = $dbh->selectrow_array($query);
1087
1088   my $module = "IC";
1089   $query = qq|SELECT c.accno, c.description, c.link, c.id,
1090               d.inventory_accno_id, d.income_accno_id, d.expense_accno_id
1091               FROM chart c, defaults d
1092               WHERE c.link LIKE '%$module%'
1093               ORDER BY c.accno|;
1094
1095
1096   my $sth = $dbh->prepare($query);
1097   $sth->execute || $form->dberror($query);
1098   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1099     foreach my $key (split(/:/, $ref->{link})) {
1100       if (!$form->{"std_inventory_accno_id"} && ($key eq "IC")) {
1101         $form->{"std_inventory_accno_id"} = $ref->{"id"};
1102       }
1103       if ($key =~ /$module/) {
1104         if (   ($ref->{id} eq $ref->{inventory_accno_id})
1105             || ($ref->{id} eq $ref->{income_accno_id})
1106             || ($ref->{id} eq $ref->{expense_accno_id})) {
1107           push @{ $form->{"${module}_links"}{$key} },
1108             { accno       => $ref->{accno},
1109               description => $ref->{description},
1110               selected    => "selected",
1111               id          => $ref->{id} };
1112         } else {
1113           push @{ $form->{"${module}_links"}{$key} },
1114             { accno       => $ref->{accno},
1115               description => $ref->{description},
1116               selected    => "",
1117               id          => $ref->{id} };
1118         }
1119       }
1120     }
1121   }
1122   $sth->finish;
1123
1124
1125   $dbh->disconnect;
1126
1127   $main::lxdebug->leave_sub();
1128 }
1129
1130 sub save_buchungsgruppe {
1131   $main::lxdebug->enter_sub();
1132
1133   my ($self, $myconfig, $form) = @_;
1134
1135   # connect to database
1136   my $dbh = $form->dbconnect($myconfig);
1137
1138   my @values = ($form->{description}, $form->{inventory_accno_id},
1139                 $form->{income_accno_id_0}, $form->{expense_accno_id_0},
1140                 $form->{income_accno_id_1}, $form->{expense_accno_id_1},
1141                 $form->{income_accno_id_2}, $form->{expense_accno_id_2},
1142                 $form->{income_accno_id_3}, $form->{expense_accno_id_3});
1143
1144   my $query;
1145
1146   # id is the old record
1147   if ($form->{id}) {
1148     $query = qq|UPDATE buchungsgruppen SET
1149                 description = ?, inventory_accno_id = ?,
1150                 income_accno_id_0 = ?, expense_accno_id_0 = ?,
1151                 income_accno_id_1 = ?, expense_accno_id_1 = ?,
1152                 income_accno_id_2 = ?, expense_accno_id_2 = ?,
1153                 income_accno_id_3 = ?, expense_accno_id_3 = ?
1154                 WHERE id = ?|;
1155     push(@values, $form->{id});
1156   } else {
1157     $query = qq|SELECT COALESCE(MAX(sortkey) + 1, 1) FROM buchungsgruppen|;
1158     my ($sortkey) = $dbh->selectrow_array($query);
1159     $form->dberror($query) if ($dbh->err);
1160     push(@values, $sortkey);
1161     $query = qq|INSERT INTO buchungsgruppen
1162                 (description, inventory_accno_id,
1163                 income_accno_id_0, expense_accno_id_0,
1164                 income_accno_id_1, expense_accno_id_1,
1165                 income_accno_id_2, expense_accno_id_2,
1166                 income_accno_id_3, expense_accno_id_3,
1167                 sortkey)
1168                 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)|;
1169   }
1170   do_query($form, $dbh, $query, @values);
1171
1172   $dbh->disconnect;
1173
1174   $main::lxdebug->leave_sub();
1175 }
1176
1177 sub delete_buchungsgruppe {
1178   $main::lxdebug->enter_sub();
1179
1180   my ($self, $myconfig, $form) = @_;
1181
1182   # connect to database
1183   my $dbh = $form->dbconnect($myconfig);
1184
1185   $query = qq|DELETE FROM buchungsgruppen WHERE id = ?|;
1186   do_query($form, $dbh, $query, $form->{id});
1187
1188   $dbh->disconnect;
1189
1190   $main::lxdebug->leave_sub();
1191 }
1192
1193 sub swap_sortkeys {
1194   $main::lxdebug->enter_sub();
1195
1196   my ($self, $myconfig, $form, $table) = @_;
1197
1198   # connect to database
1199   my $dbh = $form->dbconnect_noauto($myconfig);
1200
1201   my $query =
1202     qq|SELECT
1203        (SELECT sortkey FROM $table WHERE id = ?) AS sortkey1,
1204        (SELECT sortkey FROM $table WHERE id = ?) AS sortkey2|;
1205   my @values = ($form->{"id1"}, $form->{"id2"});
1206   my @sortkeys = selectrow_query($form, $dbh, $query, @values);
1207   $main::lxdebug->dump(0, "v", \@values);
1208   $main::lxdebug->dump(0, "s", \@sortkeys);
1209
1210   $query = qq|UPDATE $table SET sortkey = ? WHERE id = ?|;
1211   my $sth = $dbh->prepare($query);
1212   $sth->execute($sortkeys[1], $form->{"id1"}) ||
1213     $form->dberror($query . " ($sortkeys[1], $form->{id1})");
1214   $sth->execute($sortkeys[0], $form->{"id2"}) ||
1215     $form->dberror($query . " ($sortkeys[0], $form->{id2})");
1216   $sth->finish();
1217
1218   $dbh->commit();
1219   $dbh->disconnect;
1220
1221   $main::lxdebug->leave_sub();
1222 }
1223
1224 sub printer {
1225   $main::lxdebug->enter_sub();
1226
1227   my ($self, $myconfig, $form) = @_;
1228
1229   # connect to database
1230   my $dbh = $form->dbconnect($myconfig);
1231
1232   my $query = qq|SELECT id, printer_description, template_code, printer_command
1233                  FROM printers
1234                  ORDER BY 2|;
1235
1236   $sth = $dbh->prepare($query);
1237   $sth->execute || $form->dberror($query);
1238
1239   $form->{"ALL"} = [];
1240   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1241     push @{ $form->{ALL} }, $ref;
1242   }
1243
1244   $sth->finish;
1245   $dbh->disconnect;
1246
1247   $main::lxdebug->leave_sub();
1248 }
1249
1250 sub get_printer {
1251   $main::lxdebug->enter_sub();
1252
1253   my ($self, $myconfig, $form) = @_;
1254
1255   # connect to database
1256   my $dbh = $form->dbconnect($myconfig);
1257
1258   my $query =
1259     qq|SELECT p.printer_description, p.template_code, p.printer_command
1260                  FROM printers p
1261                  WHERE p.id = $form->{id}|;
1262   my $sth = $dbh->prepare($query);
1263   $sth->execute || $form->dberror($query);
1264
1265   my $ref = $sth->fetchrow_hashref(NAME_lc);
1266
1267   map { $form->{$_} = $ref->{$_} } keys %$ref;
1268
1269   $sth->finish;
1270
1271   $dbh->disconnect;
1272
1273   $main::lxdebug->leave_sub();
1274 }
1275
1276 sub save_printer {
1277   $main::lxdebug->enter_sub();
1278
1279   my ($self, $myconfig, $form) = @_;
1280
1281   # connect to database
1282   my $dbh = $form->dbconnect($myconfig);
1283
1284   $form->{printer_description} =~ s/\'/\'\'/g;
1285   $form->{printer_command} =~ s/\'/\'\'/g;
1286   $form->{template_code} =~ s/\'/\'\'/g;
1287
1288
1289   # id is the old record
1290   if ($form->{id}) {
1291     $query = qq|UPDATE printers SET
1292                 printer_description = '$form->{printer_description}',
1293                 template_code = '$form->{template_code}',
1294                 printer_command = '$form->{printer_command}'
1295                 WHERE id = $form->{id}|;
1296   } else {
1297     $query = qq|INSERT INTO printers
1298                 (printer_description, template_code, printer_command)
1299                 VALUES ('$form->{printer_description}', '$form->{template_code}', '$form->{printer_command}')|;
1300   }
1301   $dbh->do($query) || $form->dberror($query);
1302
1303   $dbh->disconnect;
1304
1305   $main::lxdebug->leave_sub();
1306 }
1307
1308 sub delete_printer {
1309   $main::lxdebug->enter_sub();
1310
1311   my ($self, $myconfig, $form) = @_;
1312
1313   # connect to database
1314   my $dbh = $form->dbconnect($myconfig);
1315
1316   $query = qq|DELETE FROM printers
1317               WHERE id = $form->{id}|;
1318   $dbh->do($query) || $form->dberror($query);
1319
1320   $dbh->disconnect;
1321
1322   $main::lxdebug->leave_sub();
1323 }
1324
1325 sub payment {
1326   $main::lxdebug->enter_sub();
1327
1328   my ($self, $myconfig, $form) = @_;
1329
1330   # connect to database
1331   my $dbh = $form->dbconnect($myconfig);
1332
1333   my $query = qq|SELECT * FROM payment_terms ORDER BY sortkey|;
1334
1335   $sth = $dbh->prepare($query);
1336   $sth->execute || $form->dberror($query);
1337
1338   $form->{ALL} = [];
1339   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1340     push @{ $form->{ALL} }, $ref;
1341   }
1342
1343   $sth->finish;
1344   $dbh->disconnect;
1345
1346   $main::lxdebug->leave_sub();
1347 }
1348
1349 sub get_payment {
1350   $main::lxdebug->enter_sub();
1351
1352   my ($self, $myconfig, $form) = @_;
1353
1354   # connect to database
1355   my $dbh = $form->dbconnect($myconfig);
1356
1357   my $query = qq|SELECT * FROM payment_terms WHERE id = ?|;
1358   my $sth = $dbh->prepare($query);
1359   $sth->execute($form->{"id"}) || $form->dberror($query . " ($form->{id})");
1360
1361   my $ref = $sth->fetchrow_hashref(NAME_lc);
1362   map { $form->{$_} = $ref->{$_} } keys %$ref;
1363   $sth->finish();
1364
1365   $query =
1366     qq|SELECT t.language_id, t.description_long, l.description AS language | .
1367     qq|FROM translation_payment_terms t | .
1368     qq|LEFT JOIN language l ON t.language_id = l.id | .
1369     qq|WHERE t.payment_terms_id = ? | .
1370     qq|UNION | .
1371     qq|SELECT l.id AS language_id, NULL AS description_long, | .
1372     qq|l.description AS language | .
1373     qq|FROM language l|;
1374   $sth = $dbh->prepare($query);
1375   $sth->execute($form->{"id"}) || $form->dberror($query . " ($form->{id})");
1376
1377   my %mapping;
1378   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1379     $mapping{ $ref->{"language_id"} } = $ref
1380       unless (defined($mapping{ $ref->{"language_id"} }));
1381   }
1382   $sth->finish;
1383
1384   $form->{"TRANSLATION"} = [sort({ $a->{"language"} cmp $b->{"language"} }
1385                                  values(%mapping))];
1386
1387   $dbh->disconnect;
1388
1389   $main::lxdebug->leave_sub();
1390 }
1391
1392 sub save_payment {
1393   $main::lxdebug->enter_sub();
1394
1395   my ($self, $myconfig, $form) = @_;
1396
1397   # connect to database
1398   my $dbh = $form->dbconnect_noauto($myconfig);
1399
1400   my $query;
1401
1402   if (!$form->{id}) {
1403     $query = qq|SELECT nextval('id'), COALESCE(MAX(sortkey) + 1, 1) | .
1404       qq|FROM payment_terms|;
1405     my $sortkey;
1406     ($form->{id}, $sortkey) = selectrow_query($form, $dbh, $query);
1407
1408     $query = qq|INSERT INTO payment_terms (id, sortkey) VALUES (?, ?)|;
1409     do_query($form, $dbh, $query, $form->{id}, $sortkey);
1410
1411   } else {
1412     $query =
1413       qq|DELETE FROM translation_payment_terms | .
1414       qq|WHERE payment_terms_id = ?|;
1415     do_query($form, $dbh, $query, $form->{"id"});
1416   }
1417
1418   $query = qq|UPDATE payment_terms SET
1419               description = ?, description_long = ?,
1420               ranking = ?,
1421               terms_netto = ?, terms_skonto = ?,
1422               percent_skonto = ?
1423               WHERE id = ?|;
1424   my @values = ($form->{description}, $form->{description_long},
1425                 $form->{ranking} * 1,
1426                 $form->{terms_netto} * 1, $form->{terms_skonto} * 1,
1427                 $form->{percent_skonto} * 1,
1428                 $form->{id});
1429   do_query($form, $dbh, $query, @values);
1430
1431   $query = qq|SELECT id FROM language|;
1432   my @language_ids;
1433   my $sth = $dbh->prepare($query);
1434   $sth->execute() || $form->dberror($query);
1435
1436   while (my ($id) = $sth->fetchrow_array()) {
1437     push(@language_ids, $id);
1438   }
1439   $sth->finish();
1440
1441   $query =
1442     qq|INSERT INTO translation_payment_terms | .
1443     qq|(language_id, payment_terms_id, description_long) | .
1444     qq|VALUES (?, ?, ?)|;
1445   $sth = $dbh->prepare($query);
1446
1447   foreach my $language_id (@language_ids) {
1448     do_statement($form, $sth, $query, $language_id, $form->{"id"},
1449                  $form->{"description_long_${language_id}"});
1450   }
1451   $sth->finish();
1452
1453   $dbh->commit();
1454   $dbh->disconnect;
1455
1456   $main::lxdebug->leave_sub();
1457 }
1458
1459 sub delete_payment {
1460   $main::lxdebug->enter_sub();
1461
1462   my ($self, $myconfig, $form) = @_;
1463
1464   # connect to database
1465   my $dbh = $form->dbconnect_noauto($myconfig);
1466
1467   my $query =
1468     qq|DELETE FROM translation_payment_terms WHERE payment_terms_id = ?|;
1469   do_query($form, $dbh, $query, $form->{"id"});
1470
1471   $query = qq|DELETE FROM payment_terms WHERE id = ?|;
1472   do_query($form, $dbh, $query, $form->{"id"});
1473
1474   $dbh->commit();
1475   $dbh->disconnect;
1476
1477   $main::lxdebug->leave_sub();
1478 }
1479
1480 sub sic {
1481   $main::lxdebug->enter_sub();
1482
1483   my ($self, $myconfig, $form) = @_;
1484
1485   # connect to database
1486   my $dbh = $form->dbconnect($myconfig);
1487
1488   my $query = qq|SELECT code, sictype, description
1489                  FROM sic
1490                  ORDER BY code|;
1491
1492   $sth = $dbh->prepare($query);
1493   $sth->execute || $form->dberror($query);
1494
1495   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1496     push @{ $form->{ALL} }, $ref;
1497   }
1498
1499   $sth->finish;
1500   $dbh->disconnect;
1501
1502   $main::lxdebug->leave_sub();
1503 }
1504
1505 sub get_sic {
1506   $main::lxdebug->enter_sub();
1507
1508   my ($self, $myconfig, $form) = @_;
1509
1510   # connect to database
1511   my $dbh = $form->dbconnect($myconfig);
1512
1513   my $query = qq|SELECT s.code, s.sictype, s.description
1514                  FROM sic s
1515                  WHERE s.code = '$form->{code}'|;
1516   my $sth = $dbh->prepare($query);
1517   $sth->execute || $form->dberror($query);
1518
1519   my $ref = $sth->fetchrow_hashref(NAME_lc);
1520
1521   map { $form->{$_} = $ref->{$_} } keys %$ref;
1522
1523   $sth->finish;
1524
1525   $dbh->disconnect;
1526
1527   $main::lxdebug->leave_sub();
1528 }
1529
1530 sub save_sic {
1531   $main::lxdebug->enter_sub();
1532
1533   my ($self, $myconfig, $form) = @_;
1534
1535   # connect to database
1536   my $dbh = $form->dbconnect($myconfig);
1537
1538   $form->{code}        =~ s/\'/\'\'/g;
1539   $form->{description} =~ s/\'/\'\'/g;
1540
1541   # if there is an id
1542   if ($form->{id}) {
1543     $query = qq|UPDATE sic SET
1544                 code = '$form->{code}',
1545                 sictype = '$form->{sictype}',
1546                 description = '$form->{description}'
1547                 WHERE code = '$form->{id}'|;
1548   } else {
1549     $query = qq|INSERT INTO sic
1550                 (code, sictype, description)
1551                 VALUES ('$form->{code}', '$form->{sictype}', '$form->{description}')|;
1552   }
1553   $dbh->do($query) || $form->dberror($query);
1554
1555   $dbh->disconnect;
1556
1557   $main::lxdebug->leave_sub();
1558 }
1559
1560 sub delete_sic {
1561   $main::lxdebug->enter_sub();
1562
1563   my ($self, $myconfig, $form) = @_;
1564
1565   # connect to database
1566   my $dbh = $form->dbconnect($myconfig);
1567
1568   $query = qq|DELETE FROM sic
1569               WHERE code = '$form->{code}'|;
1570   $dbh->do($query) || $form->dberror($query);
1571
1572   $dbh->disconnect;
1573
1574   $main::lxdebug->leave_sub();
1575 }
1576
1577 sub load_template {
1578   $main::lxdebug->enter_sub();
1579
1580   my ($self, $form) = @_;
1581
1582   open(TEMPLATE, "$form->{file}") or $form->error("$form->{file} : $!");
1583
1584   while (<TEMPLATE>) {
1585     $form->{body} .= $_;
1586   }
1587
1588   close(TEMPLATE);
1589
1590   $main::lxdebug->leave_sub();
1591 }
1592
1593 sub save_template {
1594   $main::lxdebug->enter_sub();
1595
1596   my ($self, $form) = @_;
1597
1598   open(TEMPLATE, ">$form->{file}") or $form->error("$form->{file} : $!");
1599
1600   # strip
1601   $form->{body} =~ s/\r\n/\n/g;
1602   print TEMPLATE $form->{body};
1603
1604   close(TEMPLATE);
1605
1606   $main::lxdebug->leave_sub();
1607 }
1608
1609 sub save_preferences {
1610   $main::lxdebug->enter_sub();
1611
1612   my ($self, $myconfig, $form, $memberfile, $userspath, $webdav) = @_;
1613
1614   map { ($form->{$_}) = split(/--/, $form->{$_}) }
1615     qw(inventory_accno income_accno expense_accno fxgain_accno fxloss_accno);
1616
1617   my @a;
1618   $form->{curr} =~ s/ //g;
1619   map { push(@a, uc pack "A3", $_) if $_ } split(/:/, $form->{curr});
1620   $form->{curr} = join ':', @a;
1621
1622   # connect to database
1623   my $dbh = $form->dbconnect_noauto($myconfig);
1624
1625   # these defaults are database wide
1626   # user specific variables are in myconfig
1627   # save defaults
1628   my $query = qq|UPDATE defaults SET
1629                  inventory_accno_id =
1630                      (SELECT c.id FROM chart c
1631                                 WHERE c.accno = '$form->{inventory_accno}'),
1632                  income_accno_id =
1633                      (SELECT c.id FROM chart c
1634                                 WHERE c.accno = '$form->{income_accno}'),
1635                  expense_accno_id =
1636                      (SELECT c.id FROM chart c
1637                                 WHERE c.accno = '$form->{expense_accno}'),
1638                  fxgain_accno_id =
1639                      (SELECT c.id FROM chart c
1640                                 WHERE c.accno = '$form->{fxgain_accno}'),
1641                  fxloss_accno_id =
1642                      (SELECT c.id FROM chart c
1643                                 WHERE c.accno = '$form->{fxloss_accno}'),
1644                  invnumber = '$form->{invnumber}',
1645                  cnnumber  = '$form->{cnnumber}',
1646                  sonumber = '$form->{sonumber}',
1647                  ponumber = '$form->{ponumber}',
1648                  sqnumber = '$form->{sqnumber}',
1649                  rfqnumber = '$form->{rfqnumber}',
1650                  customernumber = '$form->{customernumber}',
1651                  vendornumber = '$form->{vendornumber}',
1652                  articlenumber = '$form->{articlenumber}',
1653                  servicenumber = '$form->{servicenumber}',
1654                  yearend = '$form->{yearend}',
1655                  curr = '$form->{curr}',
1656                  businessnumber = '$form->{businessnumber}'
1657                 |;
1658   $dbh->do($query) || $form->dberror($query);
1659
1660   # update name
1661   my $name = $form->{name};
1662   $name =~ s/\'/\'\'/g;
1663   $query = qq|UPDATE employee
1664               SET name = '$name'
1665               WHERE login = '$form->{login}'|;
1666   $dbh->do($query) || $form->dberror($query);
1667
1668 #   foreach my $item (split(/ /, $form->{taxaccounts})) {
1669 #     $query = qq|UPDATE tax
1670 #               SET rate = | . ($form->{$item} / 100) . qq|,
1671 #               taxnumber = '$form->{"taxnumber_$item"}'
1672 #               WHERE chart_id = $item|;
1673 #     $dbh->do($query) || $form->dberror($query);
1674 #   }
1675
1676   my $rc = $dbh->commit;
1677   $dbh->disconnect;
1678
1679   # save first currency in myconfig
1680   $form->{currency} = substr($form->{curr}, 0, 3);
1681
1682   my $myconfig = new User "$memberfile", "$form->{login}";
1683
1684   foreach my $item (keys %$form) {
1685     $myconfig->{$item} = $form->{$item};
1686   }
1687
1688   $myconfig->save_member($memberfile, $userspath);
1689
1690   if ($webdav) {
1691     @webdavdirs =
1692       qw(angebote bestellungen rechnungen anfragen lieferantenbestellungen einkaufsrechnungen);
1693     foreach $directory (@webdavdirs) {
1694       $file = "webdav/" . $directory . "/webdav-user";
1695       if ($myconfig->{$directory}) {
1696         open(HTACCESS, "$file") or die "cannot open webdav-user $!\n";
1697         while (<HTACCESS>) {
1698           ($login, $password) = split(/:/, $_);
1699           if ($login ne $form->{login}) {
1700             $newfile .= $_;
1701           }
1702         }
1703         close(HTACCESS);
1704         open(HTACCESS, "> $file") or die "cannot open webdav-user $!\n";
1705         $newfile .= $myconfig->{login} . ":" . $myconfig->{password} . "\n";
1706         print(HTACCESS $newfile);
1707         close(HTACCESS);
1708       } else {
1709         $form->{$directory} = 0;
1710         open(HTACCESS, "$file") or die "cannot open webdav-user $!\n";
1711         while (<HTACCESS>) {
1712           ($login, $password) = split(/:/, $_);
1713           if ($login ne $form->{login}) {
1714             $newfile .= $_;
1715           }
1716         }
1717         close(HTACCESS);
1718         open(HTACCESS, "> $file") or die "cannot open webdav-user $!\n";
1719         print(HTACCESS $newfile);
1720         close(HTACCESS);
1721       }
1722     }
1723   }
1724
1725   $main::lxdebug->leave_sub();
1726
1727   return $rc;
1728 }
1729
1730 sub defaultaccounts {
1731   $main::lxdebug->enter_sub();
1732
1733   my ($self, $myconfig, $form) = @_;
1734
1735   # connect to database
1736   my $dbh = $form->dbconnect($myconfig);
1737
1738   # get defaults from defaults table
1739   my $query = qq|SELECT * FROM defaults|;
1740   my $sth   = $dbh->prepare($query);
1741   $sth->execute || $form->dberror($query);
1742
1743   $form->{defaults}             = $sth->fetchrow_hashref(NAME_lc);
1744   $form->{defaults}{IC}         = $form->{defaults}{inventory_accno_id};
1745   $form->{defaults}{IC_income}  = $form->{defaults}{income_accno_id};
1746   $form->{defaults}{IC_expense} = $form->{defaults}{expense_accno_id};
1747   $form->{defaults}{FX_gain}    = $form->{defaults}{fxgain_accno_id};
1748   $form->{defaults}{FX_loss}    = $form->{defaults}{fxloss_accno_id};
1749
1750   $sth->finish;
1751
1752   $query = qq|SELECT c.id, c.accno, c.description, c.link
1753               FROM chart c
1754               WHERE c.link LIKE '%IC%'
1755               ORDER BY c.accno|;
1756   $sth = $dbh->prepare($query);
1757   $sth->execute || $self->dberror($query);
1758
1759   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1760     foreach my $key (split(/:/, $ref->{link})) {
1761       if ($key =~ /IC/) {
1762         $nkey = $key;
1763         if ($key =~ /cogs/) {
1764           $nkey = "IC_expense";
1765         }
1766         if ($key =~ /sale/) {
1767           $nkey = "IC_income";
1768         }
1769         %{ $form->{IC}{$nkey}{ $ref->{accno} } } = (
1770                                              id          => $ref->{id},
1771                                              description => $ref->{description}
1772         );
1773       }
1774     }
1775   }
1776   $sth->finish;
1777
1778   $query = qq|SELECT c.id, c.accno, c.description
1779               FROM chart c
1780               WHERE c.category = 'I'
1781               AND c.charttype = 'A'
1782               ORDER BY c.accno|;
1783   $sth = $dbh->prepare($query);
1784   $sth->execute || $self->dberror($query);
1785
1786   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1787     %{ $form->{IC}{FX_gain}{ $ref->{accno} } } = (
1788                                              id          => $ref->{id},
1789                                              description => $ref->{description}
1790     );
1791   }
1792   $sth->finish;
1793
1794   $query = qq|SELECT c.id, c.accno, c.description
1795               FROM chart c
1796               WHERE c.category = 'E'
1797               AND c.charttype = 'A'
1798               ORDER BY c.accno|;
1799   $sth = $dbh->prepare($query);
1800   $sth->execute || $self->dberror($query);
1801
1802   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1803     %{ $form->{IC}{FX_loss}{ $ref->{accno} } } = (
1804                                              id          => $ref->{id},
1805                                              description => $ref->{description}
1806     );
1807   }
1808   $sth->finish;
1809
1810   # now get the tax rates and numbers
1811   $query = qq|SELECT c.id, c.accno, c.description,
1812               t.rate * 100 AS rate, t.taxnumber
1813               FROM chart c, tax t
1814               WHERE c.id = t.chart_id|;
1815
1816   $sth = $dbh->prepare($query);
1817   $sth->execute || $form->dberror($query);
1818
1819   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1820     $form->{taxrates}{ $ref->{accno} }{id}          = $ref->{id};
1821     $form->{taxrates}{ $ref->{accno} }{description} = $ref->{description};
1822     $form->{taxrates}{ $ref->{accno} }{taxnumber}   = $ref->{taxnumber}
1823       if $ref->{taxnumber};
1824     $form->{taxrates}{ $ref->{accno} }{rate} = $ref->{rate} if $ref->{rate};
1825   }
1826
1827   $sth->finish;
1828   $dbh->disconnect;
1829
1830   $main::lxdebug->leave_sub();
1831 }
1832
1833 sub backup {
1834   $main::lxdebug->enter_sub();
1835
1836   my ($self, $myconfig, $form, $userspath) = @_;
1837
1838   my $mail;
1839   my $err;
1840   my $boundary = time;
1841   my $tmpfile  =
1842     "$userspath/$boundary.$myconfig->{dbname}-$form->{dbversion}.sql";
1843   my $out = $form->{OUT};
1844   $form->{OUT} = ">$tmpfile";
1845
1846   if ($form->{media} eq 'email') {
1847
1848     use SL::Mailer;
1849     $mail = new Mailer;
1850
1851     $mail->{to}      = qq|"$myconfig->{name}" <$myconfig->{email}>|;
1852     $mail->{from}    = qq|"$myconfig->{name}" <$myconfig->{email}>|;
1853     $mail->{subject} =
1854       "Lx-Office Backup / $myconfig->{dbname}-$form->{dbversion}.sql";
1855     @{ $mail->{attachments} } = ($tmpfile);
1856     $mail->{version} = $form->{version};
1857     $mail->{fileid}  = "$boundary.";
1858
1859     $myconfig->{signature} =~ s/\\n/\r\n/g;
1860     $mail->{message} = "--\n$myconfig->{signature}";
1861
1862   }
1863
1864   open(OUT, "$form->{OUT}") or $form->error("$form->{OUT} : $!");
1865
1866   # get sequences, functions and triggers
1867   open(FH, "sql/lx-office.sql") or $form->error("sql/lx-office.sql : $!");
1868
1869   my @sequences = ();
1870   my @functions = ();
1871   my @triggers  = ();
1872   my @indices   = ();
1873   my %tablespecs;
1874
1875   my $query = "";
1876   my @quote_chars;
1877
1878   while (<FH>) {
1879
1880     # Remove DOS and Unix style line endings.
1881     s/[\r\n]//g;
1882
1883     # ignore comments or empty lines
1884     next if /^(--.*|\s+)$/;
1885
1886     for (my $i = 0; $i < length($_); $i++) {
1887       my $char = substr($_, $i, 1);
1888
1889       # Are we inside a string?
1890       if (@quote_chars) {
1891         if ($char eq $quote_chars[-1]) {
1892           pop(@quote_chars);
1893         }
1894         $query .= $char;
1895
1896       } else {
1897         if (($char eq "'") || ($char eq "\"")) {
1898           push(@quote_chars, $char);
1899
1900         } elsif ($char eq ";") {
1901
1902           # Query is complete. Check for triggers and functions.
1903           if ($query =~ /^create\s+function\s+\"?(\w+)\"?/i) {
1904             push(@functions, $query);
1905
1906           } elsif ($query =~ /^create\s+trigger\s+\"?(\w+)\"?/i) {
1907             push(@triggers, $query);
1908
1909           } elsif ($query =~ /^create\s+sequence\s+\"?(\w+)\"?/i) {
1910             push(@sequences, $1);
1911
1912           } elsif ($query =~ /^create\s+table\s+\"?(\w+)\"?/i) {
1913             $tablespecs{$1} = $query;
1914
1915           } elsif ($query =~ /^create\s+index\s+\"?(\w+)\"?/i) {
1916             push(@indices, $query);
1917
1918           }
1919
1920           $query = "";
1921           $char  = "";
1922         }
1923
1924         $query .= $char;
1925       }
1926     }
1927   }
1928   close(FH);
1929
1930   # connect to database
1931   my $dbh = $form->dbconnect($myconfig);
1932
1933   # get all the tables
1934   my @tables = $dbh->tables('', '', 'customer', '', { noprefix => 0 });
1935
1936   my $today = scalar localtime;
1937
1938   $myconfig->{dbhost} = 'localhost' unless $myconfig->{dbhost};
1939
1940   print OUT qq|-- Lx-Office Backup
1941 -- Dataset: $myconfig->{dbname}
1942 -- Version: $form->{dbversion}
1943 -- Host: $myconfig->{dbhost}
1944 -- Login: $form->{login}
1945 -- User: $myconfig->{name}
1946 -- Date: $today
1947 --
1948 -- set options
1949 $myconfig->{dboptions};
1950 --
1951 |;
1952
1953   print OUT "-- DROP Sequences\n";
1954   my $item;
1955   foreach $item (@sequences) {
1956     print OUT qq|DROP SEQUENCE $item;\n|;
1957   }
1958
1959   print OUT "-- DROP Triggers\n";
1960
1961   foreach $item (@triggers) {
1962     if ($item =~ /^create\s+trigger\s+\"?(\w+)\"?\s+.*on\s+\"?(\w+)\"?\s+/i) {
1963       print OUT qq|DROP TRIGGER "$1" ON "$2";\n|;
1964     }
1965   }
1966
1967   print OUT "-- DROP Functions\n";
1968
1969   foreach $item (@functions) {
1970     if ($item =~ /^create\s+function\s+\"?(\w+)\"?/i) {
1971       print OUT qq|DROP FUNCTION "$1" ();\n|;
1972     }
1973   }
1974
1975   foreach $table (@tables) {
1976     if (!($table =~ /^sql_.*/)) {
1977       my $query = qq|SELECT * FROM $table|;
1978
1979       my $sth = $dbh->prepare($query);
1980       $sth->execute || $form->dberror($query);
1981
1982       $query = "INSERT INTO $table (";
1983       map { $query .= qq|$sth->{NAME}->[$_],| }
1984         (0 .. $sth->{NUM_OF_FIELDS} - 1);
1985       chop $query;
1986
1987       $query .= ") VALUES";
1988
1989       if ($tablespecs{$table}) {
1990         print(OUT "--\n");
1991         print(OUT "DROP TABLE $table;\n");
1992         print(OUT $tablespecs{$table}, ";\n");
1993       } else {
1994         print(OUT "--\n");
1995         print(OUT "DELETE FROM $table;\n");
1996       }
1997       while (my @arr = $sth->fetchrow_array) {
1998
1999         $fields = "(";
2000         foreach my $item (@arr) {
2001           if (defined $item) {
2002             $item =~ s/\'/\'\'/g;
2003             $fields .= qq|'$item',|;
2004           } else {
2005             $fields .= 'NULL,';
2006           }
2007         }
2008
2009         chop $fields;
2010         $fields .= ")";
2011
2012         print OUT qq|$query $fields;\n|;
2013       }
2014
2015       $sth->finish;
2016     }
2017   }
2018
2019   # create indices, sequences, functions and triggers
2020
2021   print(OUT "-- CREATE Indices\n");
2022   map({ print(OUT "$_;\n"); } @indices);
2023
2024   print OUT "-- CREATE Sequences\n";
2025   foreach $item (@sequences) {
2026     $query = qq|SELECT last_value FROM $item|;
2027     $sth   = $dbh->prepare($query);
2028     $sth->execute || $form->dberror($query);
2029     my ($id) = $sth->fetchrow_array;
2030     $sth->finish;
2031
2032     print OUT qq|--
2033 CREATE SEQUENCE $item START $id;
2034 |;
2035   }
2036
2037   print OUT "-- CREATE Functions\n";
2038
2039   # functions
2040   map { print(OUT $_, ";\n"); } @functions;
2041
2042   print OUT "-- CREATE Triggers\n";
2043
2044   # triggers
2045   map { print(OUT $_, ";\n"); } @triggers;
2046
2047   close(OUT);
2048
2049   $dbh->disconnect;
2050
2051   # compress backup
2052   my @args = ("gzip", "$tmpfile");
2053   system(@args) == 0 or $form->error("$args[0] : $?");
2054
2055   $tmpfile .= ".gz";
2056
2057   if ($form->{media} eq 'email') {
2058     @{ $mail->{attachments} } = ($tmpfile);
2059     $err = $mail->send($out);
2060   }
2061
2062   if ($form->{media} eq 'file') {
2063
2064     open(IN,  "$tmpfile") or $form->error("$tmpfile : $!");
2065     open(OUT, ">-")       or $form->error("STDOUT : $!");
2066
2067     print OUT qq|Content-Type: application/x-tar-gzip;
2068 Content-Disposition: attachment; filename="$myconfig->{dbname}-$form->{dbversion}.sql.gz"
2069
2070 |;
2071
2072     while (<IN>) {
2073       print OUT $_;
2074     }
2075
2076     close(IN);
2077     close(OUT);
2078
2079   }
2080
2081   unlink "$tmpfile";
2082
2083   $main::lxdebug->leave_sub();
2084 }
2085
2086 sub closedto {
2087   $main::lxdebug->enter_sub();
2088
2089   my ($self, $myconfig, $form) = @_;
2090
2091   my $dbh = $form->dbconnect($myconfig);
2092
2093   my $query = qq|SELECT closedto, revtrans FROM defaults|;
2094   my $sth   = $dbh->prepare($query);
2095   $sth->execute || $form->dberror($query);
2096
2097   ($form->{closedto}, $form->{revtrans}) = $sth->fetchrow_array;
2098
2099   $sth->finish;
2100
2101   $dbh->disconnect;
2102
2103   $main::lxdebug->leave_sub();
2104 }
2105
2106 sub closebooks {
2107   $main::lxdebug->enter_sub();
2108
2109   my ($self, $myconfig, $form) = @_;
2110
2111   my $dbh = $form->dbconnect($myconfig);
2112
2113   if ($form->{revtrans}) {
2114
2115     $query = qq|UPDATE defaults SET closedto = NULL,
2116                                     revtrans = '1'|;
2117   } elsif ($form->{closedto}) {
2118
2119     $query = qq|UPDATE defaults SET closedto = '$form->{closedto}',
2120                                       revtrans = '0'|;
2121   } else {
2122
2123     $query = qq|UPDATE defaults SET closedto = NULL,
2124                                       revtrans = '0'|;
2125   }
2126
2127   # set close in defaults
2128   $dbh->do($query) || $form->dberror($query);
2129
2130   $dbh->disconnect;
2131
2132   $main::lxdebug->leave_sub();
2133 }
2134
2135 sub get_base_unit {
2136   my ($self, $units, $unit_name, $factor) = @_;
2137
2138   $factor = 1 unless ($factor);
2139
2140   my $unit = $units->{$unit_name};
2141
2142   if (!defined($unit) || !$unit->{"base_unit"} ||
2143       ($unit_name eq $unit->{"base_unit"})) {
2144     return ($unit_name, $factor);
2145   }
2146
2147   return AM->get_base_unit($units, $unit->{"base_unit"}, $factor * $unit->{"factor"});
2148 }
2149
2150 sub retrieve_units {
2151   $main::lxdebug->enter_sub();
2152
2153   my ($self, $myconfig, $form, $type, $prefix) = @_;
2154
2155   my $dbh = $form->dbconnect($myconfig);
2156
2157   my $query = "SELECT *, base_unit AS original_base_unit FROM units";
2158   my @values;
2159   if ($type) {
2160     $query .= " WHERE (type = ?)";
2161     @values = ($type);
2162   }
2163
2164   my $sth = $dbh->prepare($query);
2165   $sth->execute(@values) || $form->dberror($query . " (" . join(", ", @values) . ")");
2166
2167   my $units = {};
2168   while (my $ref = $sth->fetchrow_hashref()) {
2169     $units->{$ref->{"name"}} = $ref;
2170   }
2171   $sth->finish();
2172
2173   my $query_lang = "SELECT id, template_code FROM language ORDER BY description";
2174   $sth = $dbh->prepare($query_lang);
2175   $sth->execute() || $form->dberror($query_lang);
2176   my @languages;
2177   while ($ref = $sth->fetchrow_hashref()) {
2178     push(@languages, $ref);
2179   }
2180   $sth->finish();
2181
2182   $query_lang = "SELECT ul.localized, ul.localized_plural, l.id, l.template_code " .
2183     "FROM units_language ul " .
2184     "LEFT JOIN language l ON ul.language_id = l.id " .
2185     "WHERE ul.unit = ?";
2186   $sth = $dbh->prepare($query_lang);
2187
2188   foreach my $unit (values(%{$units})) {
2189     ($unit->{"${prefix}base_unit"}, $unit->{"${prefix}factor"}) = AM->get_base_unit($units, $unit->{"name"});
2190
2191     $unit->{"LANGUAGES"} = {};
2192     foreach my $lang (@languages) {
2193       $unit->{"LANGUAGES"}->{$lang->{"template_code"}} = { "template_code" => $lang->{"template_code"} };
2194     }
2195
2196     $sth->execute($unit->{"name"}) || $form->dberror($query_lang . " (" . $unit->{"name"} . ")");
2197     while ($ref = $sth->fetchrow_hashref()) {
2198       map({ $unit->{"LANGUAGES"}->{$ref->{"template_code"}}->{$_} = $ref->{$_} } keys(%{$ref}));
2199     }
2200   }
2201   $sth->finish();
2202
2203   $dbh->disconnect();
2204
2205   $main::lxdebug->leave_sub();
2206
2207   return $units;
2208 }
2209
2210 sub translate_units {
2211   $main::lxdebug->enter_sub();
2212
2213   my ($self, $form, $template_code, $unit, $amount) = @_;
2214
2215   my $units = $self->retrieve_units(\%main::myconfig, $form);
2216
2217   my $h = $units->{$unit}->{"LANGUAGES"}->{$template_code};
2218   my $new_unit = $unit;
2219   if ($h) {
2220     if (($amount != 1) && $h->{"localized_plural"}) {
2221       $new_unit = $h->{"localized_plural"};
2222     } elsif ($h->{"localized"}) {
2223       $new_unit = $h->{"localized"};
2224     }
2225   }
2226
2227   $main::lxdebug->leave_sub();
2228
2229   return $new_unit;
2230 }
2231
2232 sub units_in_use {
2233   $main::lxdebug->enter_sub();
2234
2235   my ($self, $myconfig, $form, $units) = @_;
2236
2237   my $dbh = $form->dbconnect($myconfig);
2238
2239   foreach my $unit (values(%{$units})) {
2240     my $base_unit = $unit->{"original_base_unit"};
2241     while ($base_unit) {
2242       $units->{$base_unit}->{"DEPENDING_UNITS"} = [] unless ($units->{$base_unit}->{"DEPENDING_UNITS"});
2243       push(@{$units->{$base_unit}->{"DEPENDING_UNITS"}}, $unit->{"name"});
2244       $base_unit = $units->{$base_unit}->{"original_base_unit"};
2245     }
2246   }
2247
2248   foreach my $unit (values(%{$units})) {
2249     $unit->{"in_use"} = 0;
2250     map({ $_ = $dbh->quote($_); } @{$unit->{"DEPENDING_UNITS"}});
2251
2252     foreach my $table (qw(parts invoice orderitems)) {
2253       my $query = "SELECT COUNT(*) FROM $table WHERE unit ";
2254
2255       if (0 == scalar(@{$unit->{"DEPENDING_UNITS"}})) {
2256         $query .= "= " . $dbh->quote($unit->{"name"});
2257       } else {
2258         $query .= "IN (" . $dbh->quote($unit->{"name"}) . "," . join(",", @{$unit->{"DEPENDING_UNITS"}}) . ")";
2259       }
2260
2261       my ($count) = $dbh->selectrow_array($query);
2262       $form->dberror($query) if ($dbh->err);
2263
2264       if ($count) {
2265         $unit->{"in_use"} = 1;
2266         last;
2267       }
2268     }
2269   }
2270
2271   $dbh->disconnect();
2272
2273   $main::lxdebug->leave_sub();
2274 }
2275
2276 sub unit_select_data {
2277   $main::lxdebug->enter_sub();
2278
2279   my ($self, $units, $selected, $empty_entry) = @_;
2280
2281   my $select = [];
2282
2283   if ($empty_entry) {
2284     push(@{$select}, { "name" => "", "base_unit" => "", "factor" => "", "selected" => "" });
2285   }
2286
2287   foreach my $unit (sort({ lc($a) cmp lc($b) } keys(%{$units}))) {
2288     push(@{$select}, { "name" => $unit,
2289                        "base_unit" => $units->{$unit}->{"base_unit"},
2290                        "factor" => $units->{$unit}->{"factor"},
2291                        "selected" => ($unit eq $selected) ? "selected" : "" });
2292   }
2293
2294   $main::lxdebug->leave_sub();
2295
2296   return $select;
2297 }
2298
2299 sub unit_select_html {
2300   $main::lxdebug->enter_sub();
2301
2302   my ($self, $units, $name, $selected, $convertible_into) = @_;
2303
2304   my $select = "<select name=${name}>";
2305
2306   foreach my $unit (sort({ lc($a) cmp lc($b) } keys(%{$units}))) {
2307     if (!$convertible_into ||
2308         ($units->{$convertible_into} &&
2309          ($units->{$convertible_into}->{"base_unit"} eq $units->{$unit}->{"base_unit"}))) {
2310       $select .= "<option" . (($unit eq $selected) ? " selected" : "") . ">${unit}</option>";
2311     }
2312   }
2313   $select .= "</select>";
2314
2315   $main::lxdebug->leave_sub();
2316
2317   return $select;
2318 }
2319
2320 sub add_unit {
2321   $main::lxdebug->enter_sub();
2322
2323   my ($self, $myconfig, $form, $name, $base_unit, $factor, $type, $languages) = @_;
2324
2325   my $dbh = $form->dbconnect_noauto($myconfig);
2326
2327   my $query = "INSERT INTO units (name, base_unit, factor, type) VALUES (?, ?, ?, ?)";
2328   $dbh->do($query, undef, $name, $base_unit, $factor, $type) || $form->dberror($query . " ($name, $base_unit, $factor, $type)");
2329
2330   if ($languages) {
2331     $query = "INSERT INTO units_language (unit, language_id, localized, localized_plural) VALUES (?, ?, ?, ?)";
2332     my $sth = $dbh->prepare($query);
2333     foreach my $lang (@{$languages}) {
2334       my @values = ($name, $lang->{"id"}, $lang->{"localized"}, $lang->{"localized_plural"});
2335       $sth->execute(@values) || $form->dberror($query . " (" . join(", ", @values) . ")");
2336     }
2337     $sth->finish();
2338   }
2339
2340   $dbh->commit();
2341   $dbh->disconnect();
2342
2343   $main::lxdebug->leave_sub();
2344 }
2345
2346 sub save_units {
2347   $main::lxdebug->enter_sub();
2348
2349   my ($self, $myconfig, $form, $type, $units, $delete_units) = @_;
2350
2351   my $dbh = $form->dbconnect_noauto($myconfig);
2352
2353   my ($base_unit, $unit, $sth, $query);
2354
2355   $query = "DELETE FROM units_language";
2356   $dbh->do($query) || $form->dberror($query);
2357
2358   if ($delete_units && (0 != scalar(@{$delete_units}))) {
2359     $query = "DELETE FROM units WHERE name IN (";
2360     map({ $query .= "?," } @{$delete_units});
2361     substr($query, -1, 1) = ")";
2362     $dbh->do($query, undef, @{$delete_units}) ||
2363       $form->dberror($query . " (" . join(", ", @{$delete_units}) . ")");
2364   }
2365
2366   $query = "UPDATE units SET name = ?, base_unit = ?, factor = ? WHERE name = ?";
2367   $sth = $dbh->prepare($query);
2368
2369   my $query_lang = "INSERT INTO units_language (unit, language_id, localized, localized_plural) VALUES (?, ?, ?, ?)";
2370   my $sth_lang = $dbh->prepare($query_lang);
2371
2372   foreach $unit (values(%{$units})) {
2373     $unit->{"depth"} = 0;
2374     my $base_unit = $unit;
2375     while ($base_unit->{"base_unit"}) {
2376       $unit->{"depth"}++;
2377       $base_unit = $units->{$base_unit->{"base_unit"}};
2378     }
2379   }
2380
2381   foreach $unit (sort({ $a->{"depth"} <=> $b->{"depth"} } values(%{$units}))) {
2382     if ($unit->{"LANGUAGES"}) {
2383       foreach my $lang (@{$unit->{"LANGUAGES"}}) {
2384         next unless ($lang->{"id"} && $lang->{"localized"});
2385         my @values = ($unit->{"name"}, $lang->{"id"}, $lang->{"localized"}, $lang->{"localized_plural"});
2386         $sth_lang->execute(@values) || $form->dberror($query_lang . " (" . join(", ", @values) . ")");
2387       }
2388     }
2389
2390     next if ($unit->{"unchanged_unit"});
2391
2392     my @values = ($unit->{"name"}, $unit->{"base_unit"}, $unit->{"factor"}, $unit->{"old_name"});
2393     $sth->execute(@values) || $form->dberror($query . " (" . join(", ", @values) . ")");
2394   }
2395
2396   $sth->finish();
2397   $sth_lang->finish();
2398   $dbh->commit();
2399   $dbh->disconnect();
2400
2401   $main::lxdebug->leave_sub();
2402 }
2403
2404 1;