Uebernahme der kompletten Version, so wie sie Philip als "Demo-Version" gezeigt hat...
[kivitendo-erp.git] / SL / Form.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) 1998-2002
10 #
11 #  Author: Dieter Simader
12 #   Email: dsimader@sql-ledger.org
13 #     Web: http://www.sql-ledger.org
14 #
15 # Contributors: Thomas Bayen <bayen@gmx.de>
16 #               Antti Kaihola <akaihola@siba.fi>
17 #               Moritz Bunkus (tex code)
18 #
19 # This program is free software; you can redistribute it and/or modify
20 # it under the terms of the GNU General Public License as published by
21 # the Free Software Foundation; either version 2 of the License, or
22 # (at your option) any later version.
23 #
24 # This program is distributed in the hope that it will be useful,
25 # but WITHOUT ANY WARRANTY; without even the implied warranty of
26 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27 # GNU General Public License for more details.
28 # You should have received a copy of the GNU General Public License
29 # along with this program; if not, write to the Free Software
30 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #======================================================================
32 # Utilities for parsing forms
33 # and supporting routines for linking account numbers
34 # used in AR, AP and IS, IR modules
35 #
36 #======================================================================
37
38 package Form;
39 use Data::Dumper;
40
41 use Cwd;
42 use HTML::Template;
43 use SL::Template;
44 use CGI::Ajax;
45 use SL::Menu;
46 use CGI;
47
48 sub _input_to_hash {
49   $main::lxdebug->enter_sub(2);
50
51   my $input = $_[0];
52   my %in    = ();
53   my @pairs = split(/&/, $input);
54
55   foreach (@pairs) {
56     my ($name, $value) = split(/=/, $_, 2);
57     $in{$name} = unescape(undef, $value);
58   }
59
60   $main::lxdebug->leave_sub(2);
61
62   return %in;
63 }
64
65 sub _request_to_hash {
66   $main::lxdebug->enter_sub(2);
67
68   my ($input) = @_;
69   my ($i,        $loc,  $key,    $val);
70   my (%ATTACH,   $f,    $header, $header_body, $len, $buf);
71   my ($boundary, @list, $size,   $body, $x, $blah, $name);
72
73   if ($ENV{'CONTENT_TYPE'}
74       && ($ENV{'CONTENT_TYPE'} =~ /multipart\/form-data; boundary=(.+)$/)) {
75     $boundary = quotemeta('--' . $1);
76     @list     = split(/$boundary/, $input);
77
78     # For some reason there are always 2 extra, that are empty
79     $size = @list - 2;
80
81     for ($x = 1; $x <= $size; $x++) {
82       $header_body = $list[$x];
83       $header_body =~ /\r\n\r\n|\n\n/;
84
85       # Here we split the header and body
86       $header = $`;
87       $body   = $';    #'
88       $body =~ s/\r\n$//;
89
90       # Now we try to get the file name
91       $name = $header;
92       $name =~ /name=\"(.+)\"/;
93       ($name, $blah) = split(/\"/, $1);
94
95       # If the form name is not attach, then we need to parse this like
96       # regular form data
97       if ($name ne "attach") {
98         $body =~ s/%([0-9a-fA-Z]{2})/pack("c",hex($1))/eg;
99         $ATTACH{$name} = $body;
100
101         # Otherwise it is an attachment and we need to finish it up
102       } elsif ($name eq "attach") {
103         $header =~ /filename=\"(.+)\"/;
104         $ATTACH{'FILE_NAME'} = $1;
105         $ATTACH{'FILE_NAME'} =~ s/\"//g;
106         $ATTACH{'FILE_NAME'} =~ s/\s//g;
107         $ATTACH{'FILE_CONTENT'} = $body;
108
109         for ($i = $x; $list[$i]; $i++) {
110           $list[$i] =~ s/^.+name=$//;
111           $list[$i] =~ /\"(\w+)\"/;
112           $ATTACH{$1} = $';    #'
113         }
114       }
115     }
116
117     $main::lxdebug->leave_sub(2);
118     return %ATTACH;
119
120       } else {
121     $main::lxdebug->leave_sub(2);
122     return _input_to_hash($input);
123   }
124 }
125
126 sub new {
127   $main::lxdebug->enter_sub();
128
129   my $type = shift;
130
131   my $self = {};
132
133   read(STDIN, $_, $ENV{CONTENT_LENGTH});
134
135   if ($ENV{QUERY_STRING}) {
136     $_ = $ENV{QUERY_STRING};
137   }
138
139   if ($ARGV[0]) {
140     $_ = $ARGV[0];
141   }
142
143   my %parameters = _request_to_hash($_);
144   map({ $self->{$_} = $parameters{$_}; } keys(%parameters));
145
146   $self->{menubar} = 1 if $self->{path} =~ /lynx/i;
147
148   $self->{action} = lc $self->{action};
149   $self->{action} =~ s/( |-|,|\#)/_/g;
150
151   $self->{version}   = "2.4.0";
152
153   $main::lxdebug->leave_sub();
154
155   bless $self, $type;
156 }
157
158 sub debug {
159   $main::lxdebug->enter_sub();
160
161   my ($self) = @_;
162
163   print "\n";
164
165   map { print "$_ = $self->{$_}\n" } (sort keys %{$self});
166
167   $main::lxdebug->leave_sub();
168 }
169
170 sub escape {
171   $main::lxdebug->enter_sub(2);
172
173   my ($self, $str, $beenthere) = @_;
174
175   # for Apache 2 we escape strings twice
176   #if (($ENV{SERVER_SOFTWARE} =~ /Apache\/2/) && !$beenthere) {
177   #  $str = $self->escape($str, 1);
178   #}
179
180   $str =~ s/([^a-zA-Z0-9_.-])/sprintf("%%%02x", ord($1))/ge;
181
182   $main::lxdebug->leave_sub(2);
183
184   return $str;
185 }
186
187 sub unescape {
188   $main::lxdebug->enter_sub(2);
189
190   my ($self, $str) = @_;
191
192   $str =~ tr/+/ /;
193   $str =~ s/\\$//;
194
195   $str =~ s/%([0-9a-fA-Z]{2})/pack("c",hex($1))/eg;
196
197   $main::lxdebug->leave_sub(2);
198
199   return $str;
200 }
201
202 sub quote {
203   my ($self, $str) = @_;
204
205   if ($str && !ref($str)) {
206     $str =~ s/\"/&quot;/g;
207   }
208
209   $str;
210
211 }
212
213 sub unquote {
214   my ($self, $str) = @_;
215
216   if ($str && !ref($str)) {
217     $str =~ s/&quot;/\"/g;
218   }
219
220   $str;
221
222 }
223
224 sub hide_form {
225   my $self = shift;
226
227   if (@_) {
228     for (@_) {
229       print qq|<input type=hidden name="$_" value="|
230         . $self->quote($self->{$_})
231         . qq|">\n|;
232     }
233   } else {
234     delete $self->{header};
235     for (sort keys %$self) {
236       print qq|<input type=hidden name="$_" value="|
237         . $self->quote($self->{$_})
238         . qq|">\n|;
239     }
240   }
241
242 }
243
244 sub error {
245   $main::lxdebug->enter_sub();
246
247   my ($self, $msg) = @_;
248   if ($ENV{HTTP_USER_AGENT}) {
249     $msg =~ s/\n/<br>/g;
250     $self->show_generic_error($msg);
251
252   } else {
253
254     if ($self->{error_function}) {
255       &{ $self->{error_function} }($msg);
256     } else {
257       die "Error: $msg\n";
258     }
259   }
260
261   $main::lxdebug->leave_sub();
262 }
263
264 sub info {
265   $main::lxdebug->enter_sub();
266
267   my ($self, $msg) = @_;
268
269   if ($ENV{HTTP_USER_AGENT}) {
270     $msg =~ s/\n/<br>/g;
271
272     if (!$self->{header}) {
273       $self->header;
274       print qq|
275       <body>|;
276     }
277
278     print qq|
279
280     <p><b>$msg</b>
281     |;
282
283   } else {
284
285     if ($self->{info_function}) {
286       &{ $self->{info_function} }($msg);
287     } else {
288       print "$msg\n";
289     }
290   }
291
292   $main::lxdebug->leave_sub();
293 }
294
295 sub numtextrows {
296   $main::lxdebug->enter_sub();
297
298   my ($self, $str, $cols, $maxrows) = @_;
299
300   my $rows = 0;
301
302   map { $rows += int(((length) - 2) / $cols) + 1 } split /\r/, $str;
303
304   $maxrows = $rows unless defined $maxrows;
305
306   $main::lxdebug->leave_sub();
307
308   return ($rows > $maxrows) ? $maxrows : $rows;
309 }
310
311 sub dberror {
312   $main::lxdebug->enter_sub();
313
314   my ($self, $msg) = @_;
315
316   $self->error("$msg\n" . $DBI::errstr);
317
318   $main::lxdebug->leave_sub();
319 }
320
321 sub isblank {
322   $main::lxdebug->enter_sub();
323
324   my ($self, $name, $msg) = @_;
325
326   if ($self->{$name} =~ /^\s*$/) {
327     $self->error($msg);
328   }
329   $main::lxdebug->leave_sub();
330 }
331
332 sub header {
333   $main::lxdebug->enter_sub();
334
335   my ($self) = @_;
336
337   if ($self->{header}) {
338     $main::lxdebug->leave_sub();
339     return;
340   }
341
342   my ($stylesheet, $favicon, $charset);
343
344   if ($ENV{HTTP_USER_AGENT}) {
345
346     if ($self->{stylesheet} && (-f "css/$self->{stylesheet}")) {
347       $stylesheet =
348         qq|<LINK REL="stylesheet" HREF="css/$self->{stylesheet}" TYPE="text/css" TITLE="Lx-Office stylesheet">
349  |;
350     }
351
352     if ($self->{favicon} && (-f "$self->{favicon}")) {
353       $favicon =
354         qq|<LINK REL="shortcut icon" HREF="$self->{favicon}" TYPE="image/x-icon">
355   |;
356     }
357
358     if ($self->{charset}) {
359       $charset =
360         qq|<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=$self->{charset}">
361   |;
362     }
363     if ($self->{landscape}) {
364       $pagelayout = qq|<style type="text/css">
365                         \@page { size:landscape; }
366                         </style>|;
367     }
368     if ($self->{fokus}) {
369       $fokus = qq|<script type="text/javascript">
370 <!--
371 function fokus(){document.$self->{fokus}.focus();}
372 //-->
373 </script>|;
374     }
375
376     #Set Calendar
377     my $jsscript = "";
378     if ($self->{jsscript} == 1) {
379
380       $jsscript = qq|
381         <style type="text/css">\@import url(js/jscalendar/calendar-win2k-1.css);</style>
382         <script type="text/javascript" src="js/jscalendar/calendar.js"></script>
383         <script type="text/javascript" src="js/jscalendar/lang/calendar-de.js"></script>
384         <script type="text/javascript" src="js/jscalendar/calendar-setup.js"></script>
385         $self->{javascript}
386        |;
387     }
388
389     $self->{titlebar} =
390       ($self->{title})
391       ? "$self->{title} - $self->{titlebar}"
392       : $self->{titlebar};
393     $ajax = "";
394     foreach $item (@ { $self->{AJAX} }) {
395       $ajax .= $item->show_javascript();
396     }
397     print qq|Content-Type: text/html
398
399 <html>
400 <head>
401   <title>$self->{titlebar}</title>
402   $stylesheet
403   $pagelayout
404   $favicon
405   $charset
406   $jsscript
407   $ajax
408   $fokus
409   <script type="text/javascript" src="js/highlight_input.js"></script>
410   <link rel="stylesheet" type="text/css" href="css/tabcontent.css" />
411   
412   <script type="text/javascript" src="js/tabcontent.js">
413   
414   /***********************************************
415   * Tab Content script- Â© Dynamic Drive DHTML code library (www.dynamicdrive.com)
416   * This notice MUST stay intact for legal use
417   * Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
418   ***********************************************/
419   
420   </script>
421
422 </head>
423
424 |;
425   }
426   $self->{header} = 1;
427
428   $main::lxdebug->leave_sub();
429 }
430
431 sub parse_html_template {
432   $main::lxdebug->enter_sub();
433
434   my ($self, $file, $additional_params) = @_;
435   my $language;
436
437   if (!defined($main::myconfig) || !defined($main::myconfig{"countrycode"})) {
438     $language = $main::language;
439   } else {
440     $language = $main::myconfig{"countrycode"};
441   }
442
443   if (-f "templates/webpages/${file}_${language}.html") {
444     if ((-f ".developer") &&
445         (-f "templates/webpages/${file}_master.html") &&
446         ((stat("templates/webpages/${file}_master.html"))[9] >
447          (stat("templates/webpages/${file}_${language}.html"))[9])) {
448       my $info = "Developper information: templates/webpages/${file}_master.html is newer than the localized version.\n" .
449         "Please re-run 'locales.pl' in 'locale/${language}'.";
450       print(qq|<pre>$info</pre>|);
451       die($info);
452     }
453
454     $file = "templates/webpages/${file}_${language}.html";
455   } elsif (-f "templates/webpages/${file}.html") {
456     $file = "templates/webpages/${file}.html";
457   } else {
458     my $info = "Web page template '${file}' not found.\n" .
459       "Please re-run 'locales.pl' in 'locale/${language}'.";
460     print(qq|<pre>$info</pre>|);
461     die($info);
462   }
463
464   my $template = HTML::Template->new("filename" => $file,
465                                      "die_on_bad_params" => 0,
466                                      "strict" => 0,
467                                      "case_sensitive" => 1,
468                                      "loop_context_vars" => 1,
469                                      "global_vars" => 1);
470
471   $additional_params = {} unless ($additional_params);
472   if ($self->{"DEBUG"}) {
473     $additional_params->{"DEBUG"} = $self->{"DEBUG"};
474   }
475
476   if ($additional_params->{"DEBUG"}) {
477     $additional_params->{"DEBUG"} =
478       "<br><em>DEBUG INFORMATION:</em><pre>" . $additional_params->{"DEBUG"} . "</pre>";
479   }
480
481   if (%main::myconfig) {
482     map({ $additional_params->{"myconfig_${_}"} = $main::myconfig{$_}; } keys(%main::myconfig));
483     my $jsc_dateformat = $main::myconfig{"dateformat"};
484     $jsc_dateformat =~ s/d+/\%d/gi;
485     $jsc_dateformat =~ s/m+/\%m/gi;
486     $jsc_dateformat =~ s/y+/\%Y/gi;
487     $additional_params->{"myconfig_jsc_dateformat"} = $jsc_dateformat;
488   }
489
490   $additional_params->{"conf_jscalendar"} = $main::jscalendar;
491   $additional_params->{"conf_lizenzen"} = $main::lizenzen;
492   $additional_params->{"conf_latex_templates"} = $main::latex;
493   $additional_params->{"conf_opendocument_templates"} = $main::opendocument_templates;
494
495   my $menu;
496   if (-f $self->{"login"} . "_menu.ini") {
497     $menu = Menu->new($self->{"login"} . "_menu.ini");
498   } else {
499     $menu = Menu->new("menu.ini");
500   }
501   $menu->generate_acl("", $additional_params);
502
503   my @additional_param_names = keys(%{$additional_params});
504   foreach my $key ($template->param()) {
505     if (grep(/^${key}$/, @additional_param_names)) {
506       $template->param($key => $additional_params->{$key});
507     } else {
508       $template->param($key => $self->{$key});
509     }
510   }
511   my $output = $template->output();
512
513   $main::lxdebug->leave_sub();
514
515   return $output;
516 }
517
518 sub show_generic_error {
519   my ($self, $error, $title) = @_;
520
521   my $add_params = {};
522   $add_params->{"title"} = $title if ($title);
523   $self->{"label_error"} = $error;
524
525   $self->header();
526   print($self->parse_html_template("generic/error", $add_params));
527
528   die("Error: $error\n");
529 }
530
531 sub show_generic_information {
532   my ($self, $error, $title) = @_;
533
534   my $add_params = {};
535   $add_params->{"title"} = $title if ($title);
536   $self->{"label_information"} = $error;
537
538   $self->header();
539   print($self->parse_html_template("generic/information", $add_params));
540
541   die("Information: $error\n");
542 }
543
544 # write Trigger JavaScript-Code ($qty = quantity of Triggers)
545 # changed it to accept an arbitrary number of triggers - sschoeling
546 sub write_trigger {
547   $main::lxdebug->enter_sub();
548
549   my $self     = shift;
550   my $myconfig = shift;
551   my $qty      = shift;
552
553   # set dateform for jsscript
554   # default
555   $ifFormat = "%d.%m.%Y";
556   if ($myconfig->{dateformat} eq "dd.mm.yy") {
557     $ifFormat = "%d.%m.%Y";
558   } else {
559     if ($myconfig->{dateformat} eq "dd-mm-yy") {
560       $ifFormat = "%d-%m-%Y";
561     } else {
562       if ($myconfig->{dateformat} eq "dd/mm/yy") {
563         $ifFormat = "%d/%m/%Y";
564       } else {
565         if ($myconfig->{dateformat} eq "mm/dd/yy") {
566           $ifFormat = "%m/%d/%Y";
567         } else {
568           if ($myconfig->{dateformat} eq "mm-dd-yy") {
569             $ifFormat = "%m-%d-%Y";
570           } else {
571             if ($myconfig->{dateformat} eq "yyyy-mm-dd") {
572               $ifFormat = "%Y-%m-%d";
573             }
574           }
575         }
576       }
577     }
578   }
579
580   while ($#_ >= 2) {
581     push @triggers, qq|
582        Calendar.setup(
583       {
584       inputField : "| . (shift) . qq|",
585       ifFormat :"$ifFormat",
586       align : "| .  (shift) . qq|", 
587       button : "| . (shift) . qq|"
588       }
589       );
590        |;
591   }
592   my $jsscript = qq|
593        <script type="text/javascript">
594        <!--| . join("", @triggers) . qq|//-->
595         </script>
596         |;
597
598   $main::lxdebug->leave_sub();
599
600   return $jsscript;
601 }    #end sub write_trigger
602
603 sub redirect {
604   $main::lxdebug->enter_sub();
605
606   my ($self, $msg) = @_;
607
608   if ($self->{callback}) {
609
610     ($script, $argv) = split(/\?/, $self->{callback});
611     exec("perl", "$script", $argv);
612
613   } else {
614
615     $self->info($msg);
616     exit;
617   }
618
619   $main::lxdebug->leave_sub();
620 }
621
622 # sort of columns removed - empty sub
623 sub sort_columns {
624   $main::lxdebug->enter_sub();
625
626   my ($self, @columns) = @_;
627
628   $main::lxdebug->leave_sub();
629
630   return @columns;
631 }
632
633 sub format_amount {
634   $main::lxdebug->enter_sub(2);
635
636   my ($self, $myconfig, $amount, $places, $dash) = @_;
637
638   #Workaround for $format_amount calls without $places
639   if (!defined $places) {
640     (my $dec) = ($amount =~ /\.(\d+)/);
641     $places = length $dec;
642   }
643
644   if ($places =~ /\d/) {
645     $amount = $self->round_amount($amount, $places);
646   }
647
648   # is the amount negative
649   my $negative = ($amount < 0);
650   my $fillup   = "";
651
652   if ($amount != 0) {
653     if ($myconfig->{numberformat} && ($myconfig->{numberformat} ne '1000.00'))
654     {
655       my ($whole, $dec) = split /\./, "$amount";
656       $whole =~ s/-//;
657       $amount = join '', reverse split //, $whole;
658       $fillup = "0" x ($places - length($dec));
659
660       if ($myconfig->{numberformat} eq '1,000.00') {
661         $amount =~ s/\d{3,}?/$&,/g;
662         $amount =~ s/,$//;
663         $amount = join '', reverse split //, $amount;
664         $amount .= "\.$dec" . $fillup if ($places ne '' && $places * 1 != 0);
665       }
666
667       if ($myconfig->{numberformat} eq '1.000,00') {
668         $amount =~ s/\d{3,}?/$&./g;
669         $amount =~ s/\.$//;
670         $amount = join '', reverse split //, $amount;
671         $amount .= ",$dec" . $fillup if ($places ne '' && $places * 1 != 0);
672       }
673
674       if ($myconfig->{numberformat} eq '1000,00') {
675         $amount = "$whole";
676         $amount .= ",$dec" . $fillup if ($places ne '' && $places * 1 != 0);
677       }
678
679       if ($dash =~ /-/) {
680         $amount = ($negative) ? "($amount)" : "$amount";
681       } elsif ($dash =~ /DRCR/) {
682         $amount = ($negative) ? "$amount DR" : "$amount CR";
683       } else {
684         $amount = ($negative) ? "-$amount" : "$amount";
685       }
686     }
687   } else {
688     if ($dash eq "0" && $places) {
689       if ($myconfig->{numberformat} eq '1.000,00') {
690         $amount = "0" . "," . "0" x $places;
691       } else {
692         $amount = "0" . "." . "0" x $places;
693       }
694     } else {
695       $amount = ($dash ne "") ? "$dash" : "0";
696     }
697   }
698
699   $main::lxdebug->leave_sub(2);
700
701   return $amount;
702 }
703
704 sub parse_amount {
705   $main::lxdebug->enter_sub(2);
706
707   my ($self, $myconfig, $amount) = @_;
708
709   if ($myconfig->{in_numberformat} == 1) {
710     # Extra input number format 1000.00 or 1000,00
711     $amount =~ s/,/\./g;
712     $amount = scalar reverse $amount;
713     $amount =~ s/\./DOT/;
714     $amount =~ s/\.//g;
715     $amount =~ s/DOT/\./;
716     $amount = scalar reverse $amount;
717     $main::lxdebug->leave_sub(2);
718     return ($amount * 1);
719   }
720
721   if (   ($myconfig->{numberformat} eq '1.000,00')
722       || ($myconfig->{numberformat} eq '1000,00')) {
723     $amount =~ s/\.//g;
724     $amount =~ s/,/\./;
725   }
726
727   if ($myconfig->{numberformat} eq "1'000.00") {
728     $amount =~ s/\'//g;
729   }
730
731   $amount =~ s/,//g;
732
733   $main::lxdebug->leave_sub(2);
734
735   return ($amount * 1);
736 }
737
738 sub round_amount {
739   $main::lxdebug->enter_sub(2);
740
741   my ($self, $amount, $places) = @_;
742   my $round_amount;
743
744   # Rounding like "Kaufmannsrunden"
745   # Descr. http://de.wikipedia.org/wiki/Rundung
746   # Inspired by
747   # http://www.perl.com/doc/FAQs/FAQ/oldfaq-html/Q4.13.html
748   # Solves Bug: 189
749   # Udo Spallek
750   $amount = $amount * (10**($places));
751   $round_amount = int($amount + .5 * ($amount <=> 0)) / (10**($places));
752
753   $main::lxdebug->leave_sub(2);
754
755   return $round_amount;
756
757 }
758
759 sub parse_template {
760   $main::lxdebug->enter_sub();
761
762   my ($self, $myconfig, $userspath) = @_;
763   my $template;
764
765   $self->{"cwd"} = getcwd();
766   $self->{"tmpdir"} = $self->{cwd} . "/${userspath}";
767
768   if ($self->{"format"} =~ /(opendocument|oasis)/i) {
769     $template = OpenDocumentTemplate->new($self->{"IN"}, $self, $myconfig, $userspath);
770   } elsif ($self->{"format"} =~ /(postscript|pdf)/i) {
771     $ENV{"TEXINPUTS"} = ".:" . getcwd() . "/" . $myconfig->{"templates"} . ":" . $ENV{"TEXINPUTS"};
772     $template = LaTeXTemplate->new($self->{"IN"}, $self, $myconfig, $userspath);
773   } elsif (($self->{"format"} =~ /html/i) ||
774            (!$self->{"format"} && ($self->{"IN"} =~ /html$/i))) {
775     $template = HTMLTemplate->new($self->{"IN"}, $self, $myconfig, $userspath);
776   }
777
778   # Copy the notes from the invoice/sales order etc. back to the variable "notes" because that is where most templates expect it to be.
779   $self->{"notes"} = $self->{ $self->{"formname"} . "notes" };
780
781   map({ $self->{"employee_${_}"} = $myconfig->{$_}; }
782       qw(email tel fax name signature company address businessnumber));
783
784   $self->{copies} = 1 if (($self->{copies} *= 1) <= 0);
785
786   # OUT is used for the media, screen, printer, email
787   # for postscript we store a copy in a temporary file
788   my $fileid = time;
789   $self->{tmpfile} = "$userspath/${fileid}.$self->{IN}";
790   if ($template->uses_temp_file() || $self->{media} eq 'email') {
791     $out = $self->{OUT};
792     $self->{OUT} = ">$self->{tmpfile}";
793   }
794
795   if ($self->{OUT}) {
796     open(OUT, "$self->{OUT}") or $self->error("$self->{OUT} : $!");
797   } else {
798     open(OUT, ">-") or $self->error("STDOUT : $!");
799     $self->header;
800   }
801
802   if (!$template->parse(*OUT)) {
803     $self->cleanup();
804     $self->error("$self->{IN} : " . $template->get_error());
805   }
806
807   close(OUT);
808   
809   use Data::Dumper;
810   #print(STDERR Dumper($self));
811
812   if ($template->uses_temp_file() || $self->{media} eq 'email') {
813
814     if ($self->{media} eq 'email') {
815
816       use SL::Mailer;
817
818       my $mail = new Mailer;
819
820       map { $mail->{$_} = $self->{$_} }
821         qw(cc bcc subject message version format charset);
822       $mail->{to}     = qq|$self->{email}|;
823       $mail->{from}   = qq|"$myconfig->{name}" <$myconfig->{email}>|;
824       $mail->{fileid} = "$fileid.";
825
826       # if we send html or plain text inline
827       if (($self->{format} eq 'html') && ($self->{sendmode} eq 'inline')) {
828         $mail->{contenttype} = "text/html";
829
830         $mail->{message}       =~ s/\r\n/<br>\n/g;
831         $myconfig->{signature} =~ s/\\n/<br>\n/g;
832         $mail->{message} .= "<br>\n--<br>\n$myconfig->{signature}\n<br>";
833
834         open(IN, $self->{tmpfile})
835           or $self->error($self->cleanup . "$self->{tmpfile} : $!");
836         while (<IN>) {
837           $mail->{message} .= $_;
838         }
839
840         close(IN);
841
842       } else {
843
844         @{ $mail->{attachments} } = ($self->{tmpfile}) unless ($form->{do_not_attach});
845
846         $myconfig->{signature} =~ s/\\n/\r\n/g;
847         $mail->{message} .= "\r\n--\r\n$myconfig->{signature}";
848
849       }
850
851       my $err = $mail->send($out);
852       $self->error($self->cleanup . "$err") if ($err);
853
854     } else {
855
856       $self->{OUT} = $out;
857
858       my $numbytes = (-s $self->{tmpfile});
859       open(IN, $self->{tmpfile})
860         or $self->error($self->cleanup . "$self->{tmpfile} : $!");
861
862       $self->{copies} = 1 unless $self->{media} eq 'printer';
863
864       chdir("$self->{cwd}");
865       #print(STDERR "Kopien $self->{copies}\n");
866       #print(STDERR "OUT $self->{OUT}\n");
867       for my $i (1 .. $self->{copies}) {
868         if ($self->{OUT}) {
869           open(OUT, $self->{OUT})
870             or $self->error($self->cleanup . "$self->{OUT} : $!");
871         } else {
872
873           # launch application
874           print qq|Content-Type: | . $template->get_mime_type() . qq|
875 Content-Disposition: attachment; filename="$self->{tmpfile}"
876 Content-Length: $numbytes
877
878 |;
879
880           open(OUT, ">-") or $self->error($self->cleanup . "$!: STDOUT");
881
882         }
883
884         while (<IN>) {
885           print OUT $_;
886         }
887
888         close(OUT);
889
890         seek IN, 0, 0;
891       }
892
893       close(IN);
894     }
895
896   }
897
898   $self->cleanup;
899
900   chdir("$self->{cwd}");
901   $main::lxdebug->leave_sub();
902 }
903
904 sub cleanup {
905   $main::lxdebug->enter_sub();
906
907   my $self = shift;
908
909   chdir("$self->{tmpdir}");
910
911   my @err = ();
912   if (-f "$self->{tmpfile}.err") {
913     open(FH, "$self->{tmpfile}.err");
914     @err = <FH>;
915     close(FH);
916   }
917
918   if ($self->{tmpfile}) {
919     $self->{tmpfile} =~ s|.*/||g;
920     # strip extension
921     $self->{tmpfile} =~ s/\.\w+$//g;
922     my $tmpfile = $self->{tmpfile};
923     unlink(<$tmpfile.*>);
924   }
925
926   chdir("$self->{cwd}");
927
928   $main::lxdebug->leave_sub();
929
930   return "@err";
931 }
932
933 sub datetonum {
934   $main::lxdebug->enter_sub();
935
936   my ($self, $date, $myconfig) = @_;
937
938   if ($date && $date =~ /\D/) {
939
940     if ($myconfig->{dateformat} =~ /^yy/) {
941       ($yy, $mm, $dd) = split /\D/, $date;
942     }
943     if ($myconfig->{dateformat} =~ /^mm/) {
944       ($mm, $dd, $yy) = split /\D/, $date;
945     }
946     if ($myconfig->{dateformat} =~ /^dd/) {
947       ($dd, $mm, $yy) = split /\D/, $date;
948     }
949
950     $dd *= 1;
951     $mm *= 1;
952     $yy = ($yy < 70) ? $yy + 2000 : $yy;
953     $yy = ($yy >= 70 && $yy <= 99) ? $yy + 1900 : $yy;
954
955     $dd = "0$dd" if ($dd < 10);
956     $mm = "0$mm" if ($mm < 10);
957
958     $date = "$yy$mm$dd";
959   }
960
961   $main::lxdebug->leave_sub();
962
963   return $date;
964 }
965
966 # Database routines used throughout
967
968 sub dbconnect {
969   $main::lxdebug->enter_sub();
970
971   my ($self, $myconfig) = @_;
972
973   # connect to database
974   my $dbh =
975     DBI->connect($myconfig->{dbconnect},
976                  $myconfig->{dbuser}, $myconfig->{dbpasswd})
977     or $self->dberror;
978
979   # set db options
980   if ($myconfig->{dboptions}) {
981     $dbh->do($myconfig->{dboptions}) || $self->dberror($myconfig->{dboptions});
982   }
983
984   $main::lxdebug->leave_sub();
985
986   return $dbh;
987 }
988
989 sub dbconnect_noauto {
990   $main::lxdebug->enter_sub();
991
992   my ($self, $myconfig) = @_;
993
994   # connect to database
995   $dbh =
996     DBI->connect($myconfig->{dbconnect}, $myconfig->{dbuser},
997                  $myconfig->{dbpasswd}, { AutoCommit => 0 })
998     or $self->dberror;
999
1000   # set db options
1001   if ($myconfig->{dboptions}) {
1002     $dbh->do($myconfig->{dboptions}) || $self->dberror($myconfig->{dboptions});
1003   }
1004
1005   $main::lxdebug->leave_sub();
1006
1007   return $dbh;
1008 }
1009
1010 sub update_balance {
1011   $main::lxdebug->enter_sub();
1012
1013   my ($self, $dbh, $table, $field, $where, $value) = @_;
1014
1015   # if we have a value, go do it
1016   if ($value != 0) {
1017
1018     # retrieve balance from table
1019     my $query = "SELECT $field FROM $table WHERE $where FOR UPDATE";
1020     my $sth   = $dbh->prepare($query);
1021
1022     $sth->execute || $self->dberror($query);
1023     my ($balance) = $sth->fetchrow_array;
1024     $sth->finish;
1025
1026     $balance += $value;
1027
1028     # update balance
1029     $query = "UPDATE $table SET $field = $balance WHERE $where";
1030     $dbh->do($query) || $self->dberror($query);
1031   }
1032   $main::lxdebug->leave_sub();
1033 }
1034
1035 sub update_exchangerate {
1036   $main::lxdebug->enter_sub();
1037
1038   my ($self, $dbh, $curr, $transdate, $buy, $sell) = @_;
1039
1040   # some sanity check for currency
1041   if ($curr eq '') {
1042     $main::lxdebug->leave_sub();
1043     return;
1044   }
1045
1046   my $query = qq|SELECT e.curr FROM exchangerate e
1047                  WHERE e.curr = '$curr'
1048                  AND e.transdate = '$transdate'
1049                  FOR UPDATE|;
1050   my $sth = $dbh->prepare($query);
1051   $sth->execute || $self->dberror($query);
1052
1053   my $set;
1054   if ($buy != 0 && $sell != 0) {
1055     $set = "buy = $buy, sell = $sell";
1056   } elsif ($buy != 0) {
1057     $set = "buy = $buy";
1058   } elsif ($sell != 0) {
1059     $set = "sell = $sell";
1060   }
1061
1062   if ($sth->fetchrow_array) {
1063     $query = qq|UPDATE exchangerate
1064                 SET $set
1065                 WHERE curr = '$curr'
1066                 AND transdate = '$transdate'|;
1067   } else {
1068     $query = qq|INSERT INTO exchangerate (curr, buy, sell, transdate)
1069                 VALUES ('$curr', $buy, $sell, '$transdate')|;
1070   }
1071   $sth->finish;
1072   $dbh->do($query) || $self->dberror($query);
1073
1074   $main::lxdebug->leave_sub();
1075 }
1076
1077 sub save_exchangerate {
1078   $main::lxdebug->enter_sub();
1079
1080   my ($self, $myconfig, $currency, $transdate, $rate, $fld) = @_;
1081
1082   my $dbh = $self->dbconnect($myconfig);
1083
1084   my ($buy, $sell) = (0, 0);
1085   $buy  = $rate if $fld eq 'buy';
1086   $sell = $rate if $fld eq 'sell';
1087
1088   $self->update_exchangerate($dbh, $currency, $transdate, $buy, $sell);
1089
1090   $dbh->disconnect;
1091
1092   $main::lxdebug->leave_sub();
1093 }
1094
1095 sub get_exchangerate {
1096   $main::lxdebug->enter_sub();
1097
1098   my ($self, $dbh, $curr, $transdate, $fld) = @_;
1099
1100   unless ($transdate) {
1101     $main::lxdebug->leave_sub();
1102     return "";
1103   }
1104
1105   my $query = qq|SELECT e.$fld FROM exchangerate e
1106                  WHERE e.curr = '$curr'
1107                  AND e.transdate = '$transdate'|;
1108   my $sth = $dbh->prepare($query);
1109   $sth->execute || $self->dberror($query);
1110
1111   my ($exchangerate) = $sth->fetchrow_array;
1112   $sth->finish;
1113
1114   if ($exchangerate == 0) {
1115     $exchangerate = 1;
1116   }
1117
1118   $main::lxdebug->leave_sub();
1119
1120   return $exchangerate;
1121 }
1122
1123 sub set_payment_options {
1124   $main::lxdebug->enter_sub();
1125
1126   my ($self, $myconfig, $transdate) = @_;
1127
1128   if ($self->{payment_id}) {
1129
1130     my $dbh = $self->dbconnect($myconfig);
1131
1132
1133     my $query = qq|SELECT p.terms_netto, p.terms_skonto, p.percent_skonto, p.description_long FROM payment_terms p
1134                   WHERE p.id = $self->{payment_id}|;
1135     my $sth = $dbh->prepare($query);
1136     $sth->execute || $self->dberror($query);
1137   
1138     ($self->{terms_netto}, $self->{terms_skonto}, $self->{percent_skonto}, $self->{payment_terms}) = $sth->fetchrow_array;
1139
1140     $sth->finish;
1141     my $query = qq|SELECT date '$transdate' + $self->{terms_netto} AS netto_date,date '$transdate' + $self->{terms_skonto} AS skonto_date  FROM payment_terms
1142                   LIMIT 1|;
1143     my $sth = $dbh->prepare($query);
1144     $sth->execute || $self->dberror($query);    
1145     ($self->{netto_date}, $self->{skonto_date}) = $sth->fetchrow_array;
1146     $sth->finish;
1147
1148     $self->{skonto_amount} = $self->format_amount($myconfig, ($self->parse_amount($myconfig, $self->{subtotal}) * $self->{percent_skonto}), 2);
1149
1150     $self->{payment_terms} =~ s/<%netto_date%>/$self->{netto_date}/g;
1151     $self->{payment_terms} =~ s/<%skonto_date%>/$self->{skonto_date}/g;
1152     $self->{payment_terms} =~ s/<%skonto_amount%>/$self->{skonto_amount}/g;
1153
1154     $dbh->disconnect;
1155   }
1156
1157   $main::lxdebug->leave_sub();
1158
1159 }
1160
1161 sub check_exchangerate {
1162   $main::lxdebug->enter_sub();
1163
1164   my ($self, $myconfig, $currency, $transdate, $fld) = @_;
1165
1166   unless ($transdate) {
1167     $main::lxdebug->leave_sub();
1168     return "";
1169   }
1170
1171   my $dbh = $self->dbconnect($myconfig);
1172
1173   my $query = qq|SELECT e.$fld FROM exchangerate e
1174                  WHERE e.curr = '$currency'
1175                  AND e.transdate = '$transdate'|;
1176   my $sth = $dbh->prepare($query);
1177   $sth->execute || $self->dberror($query);
1178
1179   my ($exchangerate) = $sth->fetchrow_array;
1180   $sth->finish;
1181   $dbh->disconnect;
1182
1183   $main::lxdebug->leave_sub();
1184
1185   return $exchangerate;
1186 }
1187
1188 sub get_template_language {
1189   $main::lxdebug->enter_sub();
1190
1191   my ($self, $myconfig) = @_;
1192
1193   my $template_code = "";
1194
1195   if ($self->{language_id}) {
1196
1197     my $dbh = $self->dbconnect($myconfig);
1198
1199
1200     my $query = qq|SELECT l.template_code FROM language l
1201                   WHERE l.id = $self->{language_id}|;
1202     my $sth = $dbh->prepare($query);
1203     $sth->execute || $self->dberror($query);
1204   
1205     ($template_code) = $sth->fetchrow_array;
1206     $sth->finish;
1207     $dbh->disconnect;
1208   }
1209
1210   $main::lxdebug->leave_sub();
1211
1212   return $template_code;
1213 }
1214
1215 sub get_printer_code {
1216   $main::lxdebug->enter_sub();
1217
1218   my ($self, $myconfig) = @_;
1219
1220   my $template_code = "";
1221
1222   if ($self->{printer_id}) {
1223
1224     my $dbh = $self->dbconnect($myconfig);
1225
1226
1227     my $query = qq|SELECT p.template_code,p.printer_command FROM printers p
1228                   WHERE p.id = $self->{printer_id}|;
1229     my $sth = $dbh->prepare($query);
1230     $sth->execute || $self->dberror($query);
1231   
1232     ($template_code, $self->{printer_command}) = $sth->fetchrow_array;
1233     $sth->finish;
1234     $dbh->disconnect;
1235   }
1236
1237   $main::lxdebug->leave_sub();
1238
1239   return $template_code;
1240 }
1241
1242 sub get_shipto {
1243   $main::lxdebug->enter_sub();
1244
1245   my ($self, $myconfig) = @_;
1246
1247   my $template_code = "";
1248
1249   if ($self->{shipto_id}) {
1250
1251     my $dbh = $self->dbconnect($myconfig);
1252
1253
1254     my $query = qq|SELECT s.* FROM shipto s
1255                   WHERE s.id = $self->{shipto_id}|;
1256     my $sth = $dbh->prepare($query);
1257     $sth->execute || $self->dberror($query);
1258     $ref = $sth->fetchrow_hashref(NAME_lc);
1259     map { $form->{$_} = $ref->{$_} } keys %$ref;
1260     $sth->finish;  
1261     $dbh->disconnect;
1262   }
1263
1264   $main::lxdebug->leave_sub();
1265
1266 }
1267
1268 sub add_shipto {
1269   $main::lxdebug->enter_sub();
1270
1271   my ($self, $dbh, $id, $module) = @_;
1272 ##LINET
1273   my $shipto;
1274   foreach my $item (
1275     qw(name department_1 department_2 street zipcode city country contact phone fax email)
1276     ) {
1277     if ($self->{"shipto$item"}) {
1278       $shipto = 1 if ($self->{$item} ne $self->{"shipto$item"});
1279     }
1280     $self->{"shipto$item"} =~ s/\'/\'\'/g;
1281   }
1282
1283   if ($shipto) {
1284     if ($self->{shipto_id}) {
1285       my $query = qq| UPDATE shipto set
1286                       shiptoname = '$self->{shiptoname}',
1287                       shiptodepartment_1 = '$self->{shiptodepartment_1}',
1288                       shiptodepartment_2 = '$self->{shiptodepartment_2}',
1289                       shiptostreet = '$self->{shiptostreet}',
1290                       shiptozipcode = '$self->{shiptozipcode}',
1291                       shiptocity = '$self->{shiptocity}',
1292                       shiptocountry = '$self->{shiptocountry}',
1293                       shiptocontact = '$self->{shiptocontact}',
1294                       shiptophone = '$self->{shiptophone}',
1295                       shiptofax = '$self->{shiptofax}',
1296                       shiptoemail = '$self->{shiptoemail}'
1297                       WHERE id = $self->{shipto_id}|;
1298       $dbh->do($query) || $self->dberror($query);
1299     } else {
1300       my $query =
1301       qq|INSERT INTO shipto (trans_id, shiptoname, shiptodepartment_1, shiptodepartment_2, shiptostreet,
1302                    shiptozipcode, shiptocity, shiptocountry, shiptocontact,
1303                    shiptophone, shiptofax, shiptoemail, module) VALUES ($id,
1304                    '$self->{shiptoname}', '$self->{shiptodepartment_1}', '$self->{shiptodepartment_2}', '$self->{shiptostreet}',
1305                    '$self->{shiptozipcode}', '$self->{shiptocity}',
1306                    '$self->{shiptocountry}', '$self->{shiptocontact}',
1307                    '$self->{shiptophone}', '$self->{shiptofax}',
1308                    '$self->{shiptoemail}', '$module')|;
1309       $dbh->do($query) || $self->dberror($query);
1310     }
1311   }
1312 ##/LINET
1313   $main::lxdebug->leave_sub();
1314 }
1315
1316 sub get_employee {
1317   $main::lxdebug->enter_sub();
1318
1319   my ($self, $dbh) = @_;
1320
1321   my $query = qq|SELECT e.id, e.name FROM employee e
1322                  WHERE e.login = '$self->{login}'|;
1323   my $sth = $dbh->prepare($query);
1324   $sth->execute || $self->dberror($query);
1325
1326   ($self->{employee_id}, $self->{employee}) = $sth->fetchrow_array;
1327   $self->{employee_id} *= 1;
1328
1329   $sth->finish;
1330
1331   $main::lxdebug->leave_sub();
1332 }
1333
1334 # get other contact for transaction and form - html/tex
1335 sub get_contact {
1336   $main::lxdebug->enter_sub();
1337
1338   my ($self, $dbh, $id) = @_;
1339
1340   my $query = qq|SELECT c.*
1341               FROM contacts c
1342               WHERE cp_id=$id|;
1343   $sth = $dbh->prepare($query);
1344   $sth->execute || $self->dberror($query);
1345
1346   $ref = $sth->fetchrow_hashref(NAME_lc);
1347
1348   push @{ $self->{$_} }, $ref;
1349
1350   $sth->finish;
1351   $main::lxdebug->leave_sub();
1352 }
1353
1354 # get contacts for id, if no contact return {"","","","",""}
1355 sub get_contacts {
1356   $main::lxdebug->enter_sub();
1357
1358   my ($self, $dbh, $id) = @_;
1359
1360   my $query = qq|SELECT c.cp_id, c.cp_cv_id, c.cp_name, c.cp_givenname, c.cp_abteilung
1361               FROM contacts c
1362               WHERE cp_cv_id=$id|;
1363   my $sth = $dbh->prepare($query);
1364   $sth->execute || $self->dberror($query);
1365
1366   my $i = 0;
1367   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1368     push @{ $self->{all_contacts} }, $ref;
1369     $i++;
1370   }
1371
1372   if ($i == 0) {
1373     push @{ $self->{all_contacts} }, { { "", "", "", "", "", "" } };
1374   }
1375   $sth->finish;
1376   $main::lxdebug->leave_sub();
1377 }
1378
1379 # this sub gets the id and name from $table
1380 sub get_name {
1381   $main::lxdebug->enter_sub();
1382
1383   my ($self, $myconfig, $table) = @_;
1384
1385   # connect to database
1386   my $dbh = $self->dbconnect($myconfig);
1387
1388   my $name           = $self->like(lc $self->{$table});
1389   my $customernumber = $self->like(lc $self->{customernumber});
1390
1391   if ($self->{customernumber} ne "") {
1392     $query = qq~SELECT c.id, c.name,
1393                   c.street || ' ' || c.zipcode || ' ' || c.city || ' ' || c.country AS address
1394                   FROM $table c
1395                   WHERE (lower(c.customernumber) LIKE '$customernumber') AND (not c.obsolete)
1396                   ORDER BY c.name~;
1397   } else {
1398     $query = qq~SELECT c.id, c.name,
1399                  c.street || ' ' || c.zipcode || ' ' || c.city || ' ' || c.country AS address
1400                  FROM $table c
1401                  WHERE (lower(c.name) LIKE '$name') AND (not c.obsolete)
1402                  ORDER BY c.name~;
1403   }
1404
1405   if ($self->{openinvoices}) {
1406     $query = qq~SELECT DISTINCT c.id, c.name,
1407                 c.street || ' ' || c.zipcode || ' ' || c.city || ' ' || c.country AS address
1408                 FROM $self->{arap} a
1409                 JOIN $table c ON (a.${table}_id = c.id)
1410                 WHERE NOT a.amount = a.paid
1411                 AND lower(c.name) LIKE '$name'
1412                 ORDER BY c.name~;
1413   }
1414   my $sth = $dbh->prepare($query);
1415
1416   $sth->execute || $self->dberror($query);
1417
1418   my $i = 0;
1419   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1420     push(@{ $self->{name_list} }, $ref);
1421     $i++;
1422   }
1423   $sth->finish;
1424   $dbh->disconnect;
1425
1426   $main::lxdebug->leave_sub();
1427
1428   return $i;
1429 }
1430
1431 # the selection sub is used in the AR, AP, IS, IR and OE module
1432 #
1433 sub all_vc {
1434   $main::lxdebug->enter_sub();
1435
1436   my ($self, $myconfig, $table, $module) = @_;
1437
1438   my $ref;
1439   my $dbh = $self->dbconnect($myconfig);
1440
1441   my $query = qq|SELECT count(*) FROM $table|;
1442   my $sth   = $dbh->prepare($query);
1443   $sth->execute || $self->dberror($query);
1444   my ($count) = $sth->fetchrow_array;
1445   $sth->finish;
1446
1447   # build selection list
1448   if ($count < $myconfig->{vclimit}) {
1449     $query = qq|SELECT id, name
1450                 FROM $table WHERE not obsolete
1451                 ORDER BY name|;
1452     $sth = $dbh->prepare($query);
1453     $sth->execute || $self->dberror($query);
1454
1455     while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1456       push @{ $self->{"all_$table"} }, $ref;
1457     }
1458
1459     $sth->finish;
1460
1461   }
1462
1463   # get self
1464   $self->get_employee($dbh);
1465
1466   # setup sales contacts
1467   $query = qq|SELECT e.id, e.name
1468               FROM employee e
1469               WHERE e.sales = '1'
1470               AND NOT e.id = $self->{employee_id}|;
1471   $sth = $dbh->prepare($query);
1472   $sth->execute || $self->dberror($query);
1473
1474   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1475     push @{ $self->{all_employees} }, $ref;
1476   }
1477   $sth->finish;
1478
1479   # this is for self
1480   push @{ $self->{all_employees} },
1481     { id   => $self->{employee_id},
1482       name => $self->{employee} };
1483
1484   # sort the whole thing
1485   @{ $self->{all_employees} } =
1486     sort { $a->{name} cmp $b->{name} } @{ $self->{all_employees} };
1487
1488   if ($module eq 'AR') {
1489
1490     # prepare query for departments
1491     $query = qq|SELECT d.id, d.description
1492                 FROM department d
1493                 WHERE d.role = 'P'
1494                 ORDER BY 2|;
1495
1496   } else {
1497     $query = qq|SELECT d.id, d.description
1498                 FROM department d
1499                 ORDER BY 2|;
1500   }
1501
1502   $sth = $dbh->prepare($query);
1503   $sth->execute || $self->dberror($query);
1504
1505   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1506     push @{ $self->{all_departments} }, $ref;
1507   }
1508   $sth->finish;
1509
1510   # get languages
1511   $query = qq|SELECT id, description
1512               FROM language
1513               ORDER BY 1|;
1514   $sth = $dbh->prepare($query);
1515   $sth->execute || $form->dberror($query);
1516
1517   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1518     push @{ $self->{languages} }, $ref;
1519   }
1520   $sth->finish;
1521
1522   # get printer
1523   $query = qq|SELECT printer_description, id
1524               FROM printers
1525               ORDER BY 1|;
1526   $sth = $dbh->prepare($query);
1527   $sth->execute || $form->dberror($query);
1528
1529   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1530     push @{ $self->{printers} }, $ref;
1531   }
1532   $sth->finish;
1533
1534
1535   # get payment terms
1536   $query = qq|SELECT id, description
1537               FROM payment_terms
1538               ORDER BY 1|;
1539   $sth = $dbh->prepare($query);
1540   $sth->execute || $form->dberror($query);
1541
1542   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1543     push @{ $self->{payment_terms} }, $ref;
1544   }
1545   $sth->finish;
1546   $dbh->disconnect;
1547   $main::lxdebug->leave_sub();
1548 }
1549
1550
1551 sub language_payment {
1552   $main::lxdebug->enter_sub();
1553
1554   my ($self, $myconfig) = @_;
1555   undef $self->{languages};
1556   undef $self->{payment_terms};
1557   undef $self->{printers};
1558
1559   my $ref;
1560   my $dbh = $self->dbconnect($myconfig);
1561   # get languages
1562   my $query = qq|SELECT id, description
1563               FROM language
1564               ORDER BY 1|;
1565   my $sth = $dbh->prepare($query);
1566   $sth->execute || $form->dberror($query);
1567
1568   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1569     push @{ $self->{languages} }, $ref;
1570   }
1571   $sth->finish;
1572
1573   # get printer
1574   $query = qq|SELECT printer_description, id
1575               FROM printers
1576               ORDER BY 1|;
1577   $sth = $dbh->prepare($query);
1578   $sth->execute || $form->dberror($query);
1579
1580   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1581     push @{ $self->{printers} }, $ref;
1582   }
1583   $sth->finish;
1584
1585   # get payment terms
1586   $query = qq|SELECT id, description
1587               FROM payment_terms
1588               ORDER BY 1|;
1589   $sth = $dbh->prepare($query);
1590   $sth->execute || $form->dberror($query);
1591
1592   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
1593     push @{ $self->{payment_terms} }, $ref;
1594   }
1595   $sth->finish;
1596
1597   # get buchungsgruppen
1598   $query = qq|SELECT id, description
1599               FROM buchungsgruppen|;
1600   $sth = $dbh->prepare($query);
1601   $sth->execute || $form->dberror($query);
1602
1603   $self->{BUCHUNGSGRUPPEN} = [];
1604   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1605     push @{ $self->{BUCHUNGSGRUPPEN} }, $ref;
1606   }
1607   $sth->finish;
1608
1609   # get adr
1610   $query = qq|SELECT id, adr_description, adr_code
1611               FROM adr|;
1612   $sth = $dbh->prepare($query);
1613   $sth->execute || $form->dberror($query);
1614
1615
1616   $self->{ADR} = [];
1617   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1618     push @{ $self->{ADR} }, $ref;
1619   }
1620   $sth->finish;
1621   $dbh->disconnect;
1622   $main::lxdebug->leave_sub();
1623 }
1624
1625 # this is only used for reports
1626 sub all_departments {
1627   $main::lxdebug->enter_sub();
1628
1629   my ($self, $myconfig, $table) = @_;
1630
1631   my $dbh   = $self->dbconnect($myconfig);
1632   my $where = "1 = 1";
1633
1634   if (defined $table) {
1635     if ($table eq 'customer') {
1636       $where = " d.role = 'P'";
1637     }
1638   }
1639
1640   my $query = qq|SELECT d.id, d.description
1641                  FROM department d
1642                  WHERE $where
1643                  ORDER BY 2|;
1644   my $sth = $dbh->prepare($query);
1645   $sth->execute || $self->dberror($query);
1646
1647   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1648     push @{ $self->{all_departments} }, $ref;
1649   }
1650   $sth->finish;
1651
1652   $dbh->disconnect;
1653
1654   $main::lxdebug->leave_sub();
1655 }
1656
1657 sub create_links {
1658   $main::lxdebug->enter_sub();
1659
1660   my ($self, $module, $myconfig, $table) = @_;
1661
1662   $self->all_vc($myconfig, $table, $module);
1663
1664   # get last customers or vendors
1665   my ($query, $sth);
1666
1667   my $dbh = $self->dbconnect($myconfig);
1668
1669   my %xkeyref = ();
1670
1671   # now get the account numbers
1672   $query = qq|SELECT c.accno, c.description, c.link, c.taxkey_id
1673               FROM chart c
1674               WHERE c.link LIKE '%$module%'
1675               ORDER BY c.accno|;
1676
1677   $sth = $dbh->prepare($query);
1678   $sth->execute || $self->dberror($query);
1679
1680   $self->{accounts} = "";
1681   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1682
1683     foreach my $key (split /:/, $ref->{link}) {
1684       if ($key =~ /$module/) {
1685
1686         # cross reference for keys
1687         $xkeyref{ $ref->{accno} } = $key;
1688
1689         push @{ $self->{"${module}_links"}{$key} },
1690           { accno       => $ref->{accno},
1691             description => $ref->{description},
1692             taxkey      => $ref->{taxkey_id} };
1693
1694         $self->{accounts} .= "$ref->{accno} " unless $key =~ /tax/;
1695       }
1696     }
1697   }
1698   $sth->finish;
1699
1700   # get taxkeys and description
1701   $query = qq|SELECT taxkey, taxdescription
1702               FROM tax|;
1703   $sth = $dbh->prepare($query);
1704   $sth->execute || $self->dberror($query);
1705
1706   $ref = $sth->fetchrow_hashref(NAME_lc);
1707
1708   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1709     push @{ $self->{TAXKEY} }, $ref;
1710   }
1711
1712   $sth->finish;
1713
1714
1715   # get tax zones
1716   $query = qq|SELECT id, description
1717               FROM tax_zones|;
1718   $sth = $dbh->prepare($query);
1719   $sth->execute || $form->dberror($query);
1720
1721
1722   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1723     push @{ $self->{TAXZONE} }, $ref;
1724   }
1725   $sth->finish;
1726
1727   if (($module eq "AP") || ($module eq "AR")) {
1728
1729     # get tax rates and description
1730     $query = qq| SELECT * FROM tax t|;
1731     $sth   = $dbh->prepare($query);
1732     $sth->execute || $self->dberror($query);
1733     $self->{TAX} = ();
1734     while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1735       push @{ $self->{TAX} }, $ref;
1736     }
1737     $sth->finish;
1738   }
1739
1740   if ($self->{id}) {
1741     my $arap = ($table eq 'customer') ? 'ar' : 'ap';
1742
1743     $query = qq|SELECT a.cp_id, a.invnumber, a.transdate,
1744                 a.${table}_id, a.datepaid, a.duedate, a.ordnumber,
1745                 a.taxincluded, a.curr AS currency, a.notes, a.intnotes,
1746                 c.name AS $table, a.department_id, d.description AS department,
1747                 a.amount AS oldinvtotal, a.paid AS oldtotalpaid,
1748                 a.employee_id, e.name AS employee, a.gldate, a.type
1749                 FROM $arap a
1750                 JOIN $table c ON (a.${table}_id = c.id)
1751                 LEFT JOIN employee e ON (e.id = a.employee_id)
1752                 LEFT JOIN department d ON (d.id = a.department_id)
1753                 WHERE a.id = $self->{id}|;
1754     $sth = $dbh->prepare($query);
1755     $sth->execute || $self->dberror($query);
1756
1757     $ref = $sth->fetchrow_hashref(NAME_lc);
1758     foreach $key (keys %$ref) {
1759       $self->{$key} = $ref->{$key};
1760     }
1761     $sth->finish;
1762
1763     # get amounts from individual entries
1764     $query = qq|SELECT c.accno, c.description, a.source, a.amount, a.memo,
1765                 a.transdate, a.cleared, a.project_id, p.projectnumber, a.taxkey, t.rate
1766                 FROM acc_trans a
1767                 JOIN chart c ON (c.id = a.chart_id)
1768                 LEFT JOIN project p ON (p.id = a.project_id)
1769                 LEFT Join tax t ON (a.taxkey = t.taxkey)
1770                 WHERE a.trans_id = $self->{id}
1771                 AND a.fx_transaction = '0'
1772                 ORDER BY a.oid,a.transdate|;
1773     $sth = $dbh->prepare($query);
1774     $sth->execute || $self->dberror($query);
1775
1776     my $fld = ($table eq 'customer') ? 'buy' : 'sell';
1777
1778     # get exchangerate for currency
1779     $self->{exchangerate} =
1780       $self->get_exchangerate($dbh, $self->{currency}, $self->{transdate},
1781                               $fld);
1782     my $index = 0;
1783
1784     # store amounts in {acc_trans}{$key} for multiple accounts
1785     while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1786       $ref->{exchangerate} =
1787         $self->get_exchangerate($dbh, $self->{currency}, $ref->{transdate},
1788                                 $fld);
1789       if (!($xkeyref{ $ref->{accno} } =~ /tax/)) {
1790         $index++;
1791       }
1792       if (($xkeyref{ $ref->{accno} } =~ /paid/) && ($self->{type} eq "credit_note")) {
1793         $ref->{amount} *= -1;
1794       }
1795       $ref->{index} = $index;
1796
1797       push @{ $self->{acc_trans}{ $xkeyref{ $ref->{accno} } } }, $ref;
1798     }
1799     $sth->finish;
1800
1801     $query = qq|SELECT d.curr AS currencies, d.closedto, d.revtrans,
1802                   (SELECT c.accno FROM chart c
1803                    WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
1804                   (SELECT c.accno FROM chart c
1805                    WHERE d.fxloss_accno_id = c.id) AS fxloss_accno
1806                 FROM defaults d|;
1807     $sth = $dbh->prepare($query);
1808     $sth->execute || $self->dberror($query);
1809
1810     $ref = $sth->fetchrow_hashref(NAME_lc);
1811     map { $self->{$_} = $ref->{$_} } keys %$ref;
1812     $sth->finish;
1813
1814   } else {
1815
1816     # get date
1817     $query = qq|SELECT current_date AS transdate,
1818                 d.curr AS currencies, d.closedto, d.revtrans,
1819                   (SELECT c.accno FROM chart c
1820                    WHERE d.fxgain_accno_id = c.id) AS fxgain_accno,
1821                   (SELECT c.accno FROM chart c
1822                    WHERE d.fxloss_accno_id = c.id) AS fxloss_accno
1823                 FROM defaults d|;
1824     $sth = $dbh->prepare($query);
1825     $sth->execute || $self->dberror($query);
1826
1827     $ref = $sth->fetchrow_hashref(NAME_lc);
1828     map { $self->{$_} = $ref->{$_} } keys %$ref;
1829     $sth->finish;
1830
1831     if ($self->{"$self->{vc}_id"}) {
1832
1833       # only setup currency
1834       ($self->{currency}) = split /:/, $self->{currencies};
1835
1836     } else {
1837
1838       $self->lastname_used($dbh, $myconfig, $table, $module);
1839
1840       my $fld = ($table eq 'customer') ? 'buy' : 'sell';
1841
1842       # get exchangerate for currency
1843       $self->{exchangerate} =
1844         $self->get_exchangerate($dbh, $self->{currency}, $self->{transdate},
1845                                 $fld);
1846
1847     }
1848
1849   }
1850
1851   $dbh->disconnect;
1852
1853   $main::lxdebug->leave_sub();
1854 }
1855
1856 sub lastname_used {
1857   $main::lxdebug->enter_sub();
1858
1859   my ($self, $dbh, $myconfig, $table, $module) = @_;
1860
1861   my $arap  = ($table eq 'customer') ? "ar" : "ap";
1862   my $where = "1 = 1";
1863
1864   if ($self->{type} =~ /_order/) {
1865     $arap  = 'oe';
1866     $where = "quotation = '0'";
1867   }
1868   if ($self->{type} =~ /_quotation/) {
1869     $arap  = 'oe';
1870     $where = "quotation = '1'";
1871   }
1872
1873   my $query = qq|SELECT MAX(id) FROM $arap
1874                               WHERE $where
1875                               AND ${table}_id > 0|;
1876   my $sth = $dbh->prepare($query);
1877   $sth->execute || $self->dberror($query);
1878
1879   my ($trans_id) = $sth->fetchrow_array;
1880   $sth->finish;
1881
1882   $trans_id *= 1;
1883   $query = qq|SELECT ct.name, a.curr, a.${table}_id,
1884               current_date + ct.terms AS duedate, a.department_id,
1885               d.description AS department
1886               FROM $arap a
1887               JOIN $table ct ON (a.${table}_id = ct.id)
1888               LEFT JOIN department d ON (a.department_id = d.id)
1889               WHERE a.id = $trans_id|;
1890   $sth = $dbh->prepare($query);
1891   $sth->execute || $self->dberror($query);
1892
1893   ($self->{$table},  $self->{currency},      $self->{"${table}_id"},
1894    $self->{duedate}, $self->{department_id}, $self->{department})
1895     = $sth->fetchrow_array;
1896   $sth->finish;
1897
1898   $main::lxdebug->leave_sub();
1899 }
1900
1901 sub current_date {
1902   $main::lxdebug->enter_sub();
1903
1904   my ($self, $myconfig, $thisdate, $days) = @_;
1905
1906   my $dbh = $self->dbconnect($myconfig);
1907   my ($sth, $query);
1908
1909   $days *= 1;
1910   if ($thisdate) {
1911     my $dateformat = $myconfig->{dateformat};
1912     $dateformat .= "yy" if $myconfig->{dateformat} !~ /^y/;
1913
1914     $query = qq|SELECT to_date('$thisdate', '$dateformat') + $days AS thisdate
1915                 FROM defaults|;
1916     $sth = $dbh->prepare($query);
1917     $sth->execute || $self->dberror($query);
1918   } else {
1919     $query = qq|SELECT current_date AS thisdate
1920                 FROM defaults|;
1921     $sth = $dbh->prepare($query);
1922     $sth->execute || $self->dberror($query);
1923   }
1924
1925   ($thisdate) = $sth->fetchrow_array;
1926   $sth->finish;
1927
1928   $dbh->disconnect;
1929
1930   $main::lxdebug->leave_sub();
1931
1932   return $thisdate;
1933 }
1934
1935 sub like {
1936   $main::lxdebug->enter_sub();
1937
1938   my ($self, $string) = @_;
1939
1940   if ($string !~ /%/) {
1941     $string = "%$string%";
1942   }
1943
1944   $string =~ s/\'/\'\'/g;
1945
1946   $main::lxdebug->leave_sub();
1947
1948   return $string;
1949 }
1950
1951 sub redo_rows {
1952   $main::lxdebug->enter_sub();
1953
1954   my ($self, $flds, $new, $count, $numrows) = @_;
1955
1956   my @ndx = ();
1957
1958   map { push @ndx, { num => $new->[$_ - 1]->{runningnumber}, ndx => $_ } }
1959     (1 .. $count);
1960
1961   my $i = 0;
1962
1963   # fill rows
1964   foreach my $item (sort { $a->{num} <=> $b->{num} } @ndx) {
1965     $i++;
1966     $j = $item->{ndx} - 1;
1967     map { $self->{"${_}_$i"} = $new->[$j]->{$_} } @{$flds};
1968   }
1969
1970   # delete empty rows
1971   for $i ($count + 1 .. $numrows) {
1972     map { delete $self->{"${_}_$i"} } @{$flds};
1973   }
1974
1975   $main::lxdebug->leave_sub();
1976 }
1977
1978 sub update_status {
1979   $main::lxdebug->enter_sub();
1980
1981   my ($self, $myconfig) = @_;
1982
1983   my ($i, $id);
1984
1985   my $dbh = $self->dbconnect_noauto($myconfig);
1986
1987   my $query = qq|DELETE FROM status
1988                  WHERE formname = '$self->{formname}'
1989                  AND trans_id = ?|;
1990   my $sth = $dbh->prepare($query) || $self->dberror($query);
1991
1992   if ($self->{formname} =~ /(check|receipt)/) {
1993     for $i (1 .. $self->{rowcount}) {
1994       $sth->execute($self->{"id_$i"} * 1) || $self->dberror($query);
1995       $sth->finish;
1996     }
1997   } else {
1998     $sth->execute($self->{id}) || $self->dberror($query);
1999     $sth->finish;
2000   }
2001
2002   my $printed = ($self->{printed} =~ /$self->{formname}/) ? "1" : "0";
2003   my $emailed = ($self->{emailed} =~ /$self->{formname}/) ? "1" : "0";
2004
2005   my %queued = split / /, $self->{queued};
2006
2007   if ($self->{formname} =~ /(check|receipt)/) {
2008
2009     # this is a check or receipt, add one entry for each lineitem
2010     my ($accno) = split /--/, $self->{account};
2011     $query = qq|INSERT INTO status (trans_id, printed, spoolfile, formname,
2012                 chart_id) VALUES (?, '$printed',
2013                 '$queued{$self->{formname}}', '$self->{prinform}',
2014                 (SELECT c.id FROM chart c WHERE c.accno = '$accno'))|;
2015     $sth = $dbh->prepare($query) || $self->dberror($query);
2016
2017     for $i (1 .. $self->{rowcount}) {
2018       if ($self->{"checked_$i"}) {
2019         $sth->execute($self->{"id_$i"}) || $self->dberror($query);
2020         $sth->finish;
2021       }
2022     }
2023   } else {
2024     $query = qq|INSERT INTO status (trans_id, printed, emailed,
2025                 spoolfile, formname)
2026                 VALUES ($self->{id}, '$printed', '$emailed',
2027                 '$queued{$self->{formname}}', '$self->{formname}')|;
2028     $dbh->do($query) || $self->dberror($query);
2029   }
2030
2031   $dbh->commit;
2032   $dbh->disconnect;
2033
2034   $main::lxdebug->leave_sub();
2035 }
2036
2037 sub save_status {
2038   $main::lxdebug->enter_sub();
2039
2040   my ($self, $dbh) = @_;
2041
2042   my ($query, $printed, $emailed);
2043
2044   my $formnames  = $self->{printed};
2045   my $emailforms = $self->{emailed};
2046
2047   my $query = qq|DELETE FROM status
2048                  WHERE formname = '$self->{formname}'
2049                  AND trans_id = $self->{id}|;
2050   $dbh->do($query) || $self->dberror($query);
2051
2052   # this only applies to the forms
2053   # checks and receipts are posted when printed or queued
2054
2055   if ($self->{queued}) {
2056     my %queued = split / /, $self->{queued};
2057
2058     foreach my $formname (keys %queued) {
2059       $printed = ($self->{printed} =~ /$self->{formname}/) ? "1" : "0";
2060       $emailed = ($self->{emailed} =~ /$self->{formname}/) ? "1" : "0";
2061
2062       $query = qq|INSERT INTO status (trans_id, printed, emailed,
2063                   spoolfile, formname)
2064                   VALUES ($self->{id}, '$printed', '$emailed',
2065                   '$queued{$formname}', '$formname')|;
2066       $dbh->do($query) || $self->dberror($query);
2067
2068       $formnames  =~ s/$self->{formname}//;
2069       $emailforms =~ s/$self->{formname}//;
2070
2071     }
2072   }
2073
2074   # save printed, emailed info
2075   $formnames  =~ s/^ +//g;
2076   $emailforms =~ s/^ +//g;
2077
2078   my %status = ();
2079   map { $status{$_}{printed} = 1 } split / +/, $formnames;
2080   map { $status{$_}{emailed} = 1 } split / +/, $emailforms;
2081
2082   foreach my $formname (keys %status) {
2083     $printed = ($formnames  =~ /$self->{formname}/) ? "1" : "0";
2084     $emailed = ($emailforms =~ /$self->{formname}/) ? "1" : "0";
2085
2086     $query = qq|INSERT INTO status (trans_id, printed, emailed, formname)
2087                 VALUES ($self->{id}, '$printed', '$emailed', '$formname')|;
2088     $dbh->do($query) || $self->dberror($query);
2089   }
2090
2091   $main::lxdebug->leave_sub();
2092 }
2093
2094 sub update_defaults {
2095   $main::lxdebug->enter_sub();
2096
2097   my ($self, $myconfig, $fld) = @_;
2098
2099   my $dbh   = $self->dbconnect_noauto($myconfig);
2100   my $query = qq|SELECT $fld FROM defaults FOR UPDATE|;
2101   my $sth   = $dbh->prepare($query);
2102
2103   $sth->execute || $self->dberror($query);
2104   my ($var) = $sth->fetchrow_array;
2105   $sth->finish;
2106
2107   $var++;
2108
2109   $query = qq|UPDATE defaults
2110               SET $fld = '$var'|;
2111   $dbh->do($query) || $self->dberror($query);
2112
2113   $dbh->commit;
2114   $dbh->disconnect;
2115
2116   $main::lxdebug->leave_sub();
2117
2118   return $var;
2119 }
2120
2121 sub update_business {
2122   $main::lxdebug->enter_sub();
2123
2124   my ($self, $myconfig, $business_id) = @_;
2125
2126   my $dbh   = $self->dbconnect_noauto($myconfig);
2127   my $query =
2128     qq|SELECT customernumberinit FROM business  WHERE id=$business_id FOR UPDATE|;
2129   my $sth = $dbh->prepare($query);
2130
2131   $sth->execute || $self->dberror($query);
2132   my ($var) = $sth->fetchrow_array;
2133   $sth->finish;
2134   if ($var ne "") {
2135     $var++;
2136   }
2137   $query = qq|UPDATE business
2138               SET customernumberinit = '$var' WHERE id=$business_id|;
2139   $dbh->do($query) || $self->dberror($query);
2140
2141   $dbh->commit;
2142   $dbh->disconnect;
2143
2144   $main::lxdebug->leave_sub();
2145
2146   return $var;
2147 }
2148
2149 sub get_salesman {
2150   $main::lxdebug->enter_sub();
2151
2152   my ($self, $myconfig, $salesman) = @_;
2153
2154   my $dbh   = $self->dbconnect($myconfig);
2155   my $query =
2156     qq|SELECT id, name FROM customer  WHERE (customernumber ilike '%$salesman%' OR name ilike '%$salesman%') AND business_id in (SELECT id from business WHERE salesman)|;
2157   my $sth = $dbh->prepare($query);
2158   $sth->execute || $self->dberror($query);
2159
2160   my $i = 0;
2161   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
2162     push(@{ $self->{salesman_list} }, $ref);
2163     $i++;
2164   }
2165   $dbh->commit;
2166   $main::lxdebug->leave_sub();
2167
2168   return $i;
2169 }
2170
2171 sub get_partsgroup {
2172   $main::lxdebug->enter_sub();
2173
2174   my ($self, $myconfig, $p) = @_;
2175
2176   my $dbh = $self->dbconnect($myconfig);
2177
2178   my $query = qq|SELECT DISTINCT pg.id, pg.partsgroup
2179                  FROM partsgroup pg
2180                  JOIN parts p ON (p.partsgroup_id = pg.id)|;
2181
2182   if ($p->{searchitems} eq 'part') {
2183     $query .= qq|
2184                  WHERE p.inventory_accno_id > 0|;
2185   }
2186   if ($p->{searchitems} eq 'service') {
2187     $query .= qq|
2188                  WHERE p.inventory_accno_id IS NULL|;
2189   }
2190   if ($p->{searchitems} eq 'assembly') {
2191     $query .= qq|
2192                  WHERE p.assembly = '1'|;
2193   }
2194   if ($p->{searchitems} eq 'labor') {
2195     $query .= qq|
2196                  WHERE p.inventory_accno_id > 0 AND p.income_accno_id IS NULL|;
2197   }
2198
2199   $query .= qq|
2200                  ORDER BY partsgroup|;
2201
2202   if ($p->{all}) {
2203     $query = qq|SELECT id, partsgroup FROM partsgroup
2204                 ORDER BY partsgroup|;
2205   }
2206
2207   if ($p->{language_code}) {
2208     $query = qq|SELECT DISTINCT pg.id, pg.partsgroup,
2209                 t.description AS translation
2210                 FROM partsgroup pg
2211                 JOIN parts p ON (p.partsgroup_id = pg.id)
2212                 LEFT JOIN translation t ON (t.trans_id = pg.id AND t.language_code = '$p->{language_code}')
2213                 ORDER BY translation|;
2214   }
2215
2216   my $sth = $dbh->prepare($query);
2217   $sth->execute || $self->dberror($query);
2218
2219   $self->{all_partsgroup} = ();
2220   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
2221     push @{ $self->{all_partsgroup} }, $ref;
2222   }
2223   $sth->finish;
2224   $dbh->disconnect;
2225   $main::lxdebug->leave_sub();
2226 }
2227
2228 sub get_pricegroup {
2229   $main::lxdebug->enter_sub();
2230
2231   my ($self, $myconfig, $p) = @_;
2232
2233   my $dbh = $self->dbconnect($myconfig);
2234
2235   my $query = qq|SELECT p.id, p.pricegroup
2236                  FROM pricegroup p|;
2237
2238   $query .= qq|
2239                  ORDER BY pricegroup|;
2240
2241   if ($p->{all}) {
2242     $query = qq|SELECT id, pricegroup FROM pricegroup
2243                 ORDER BY pricegroup|;
2244   }
2245
2246   my $sth = $dbh->prepare($query);
2247   $sth->execute || $self->dberror($query);
2248
2249   $self->{all_pricegroup} = ();
2250   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
2251     push @{ $self->{all_pricegroup} }, $ref;
2252   }
2253   $sth->finish;
2254   $dbh->disconnect;
2255
2256   $main::lxdebug->leave_sub();
2257 }
2258
2259 sub audittrail {
2260   my ($self, $dbh, $myconfig, $audittrail) = @_;
2261
2262   # table, $reference, $formname, $action, $id, $transdate) = @_;
2263
2264   my $query;
2265   my $rv;
2266   my $disconnect;
2267
2268   if (!$dbh) {
2269     $dbh        = $self->dbconnect($myconfig);
2270     $disconnect = 1;
2271   }
2272
2273   # if we have an id add audittrail, otherwise get a new timestamp
2274
2275   if ($audittrail->{id}) {
2276
2277     $query = qq|SELECT audittrail FROM defaults|;
2278
2279     if ($dbh->selectrow_array($query)) {
2280       my ($null, $employee_id) = $self->get_employee($dbh);
2281
2282       if ($self->{audittrail} && !$myconfig) {
2283         chop $self->{audittrail};
2284
2285         my @a = split /\|/, $self->{audittrail};
2286         my %newtrail = ();
2287         my $key;
2288         my $i;
2289         my @flds = qw(tablename reference formname action transdate);
2290
2291         # put into hash and remove dups
2292         while (@a) {
2293           $key = "$a[2]$a[3]";
2294           $i   = 0;
2295           $newtrail{$key} = { map { $_ => $a[$i++] } @flds };
2296           splice @a, 0, 5;
2297         }
2298
2299         $query = qq|INSERT INTO audittrail (trans_id, tablename, reference,
2300                     formname, action, employee_id, transdate)
2301                     VALUES ($audittrail->{id}, ?, ?,
2302                     ?, ?, $employee_id, ?)|;
2303         my $sth = $dbh->prepare($query) || $self->dberror($query);
2304
2305         foreach $key (
2306           sort {
2307             $newtrail{$a}{transdate} cmp $newtrail{$b}{transdate}
2308           } keys %newtrail
2309           ) {
2310           $i = 1;
2311           for (@flds) { $sth->bind_param($i++, $newtrail{$key}{$_}) }
2312
2313           $sth->execute || $self->dberror;
2314           $sth->finish;
2315         }
2316       }
2317
2318       if ($audittrail->{transdate}) {
2319         $query = qq|INSERT INTO audittrail (trans_id, tablename, reference,
2320                     formname, action, employee_id, transdate) VALUES (
2321                     $audittrail->{id}, '$audittrail->{tablename}', |
2322           . $dbh->quote($audittrail->{reference}) . qq|,
2323                     '$audittrail->{formname}', '$audittrail->{action}',
2324                     $employee_id, '$audittrail->{transdate}')|;
2325       } else {
2326         $query = qq|INSERT INTO audittrail (trans_id, tablename, reference,
2327                     formname, action, employee_id) VALUES ($audittrail->{id},
2328                     '$audittrail->{tablename}', |
2329           . $dbh->quote($audittrail->{reference}) . qq|,
2330                     '$audittrail->{formname}', '$audittrail->{action}',
2331                     $employee_id)|;
2332       }
2333       $dbh->do($query);
2334     }
2335   } else {
2336
2337     $query = qq|SELECT current_timestamp FROM defaults|;
2338     my ($timestamp) = $dbh->selectrow_array($query);
2339
2340     $rv =
2341       "$audittrail->{tablename}|$audittrail->{reference}|$audittrail->{formname}|$audittrail->{action}|$timestamp|";
2342   }
2343
2344   $dbh->disconnect if $disconnect;
2345
2346   $rv;
2347
2348 }
2349
2350 package Locale;
2351
2352 sub new {
2353   $main::lxdebug->enter_sub();
2354
2355   my ($type, $country, $NLS_file) = @_;
2356   my $self = {};
2357
2358   %self = ();
2359   if ($country && -d "locale/$country") {
2360     $self->{countrycode} = $country;
2361     eval { require "locale/$country/$NLS_file"; };
2362   }
2363
2364   $self->{NLS_file} = $NLS_file;
2365
2366   push @{ $self->{LONG_MONTH} },
2367     ("January",   "February", "March",    "April",
2368      "May ",      "June",     "July",     "August",
2369      "September", "October",  "November", "December");
2370   push @{ $self->{SHORT_MONTH} },
2371     (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec));
2372
2373   $main::lxdebug->leave_sub();
2374
2375   bless $self, $type;
2376 }
2377
2378 sub text {
2379   my ($self, $text) = @_;
2380
2381   return (exists $self{texts}{$text}) ? $self{texts}{$text} : $text;
2382 }
2383
2384 sub findsub {
2385   $main::lxdebug->enter_sub();
2386
2387   my ($self, $text) = @_;
2388
2389   if (exists $self{subs}{$text}) {
2390     $text = $self{subs}{$text};
2391   } else {
2392     if ($self->{countrycode} && $self->{NLS_file}) {
2393       Form->error(
2394          "$text not defined in locale/$self->{countrycode}/$self->{NLS_file}");
2395     }
2396   }
2397
2398   $main::lxdebug->leave_sub();
2399
2400   return $text;
2401 }
2402
2403 sub date {
2404   $main::lxdebug->enter_sub();
2405
2406   my ($self, $myconfig, $date, $longformat) = @_;
2407
2408   my $longdate  = "";
2409   my $longmonth = ($longformat) ? 'LONG_MONTH' : 'SHORT_MONTH';
2410
2411   if ($date) {
2412
2413     # get separator
2414     $spc = $myconfig->{dateformat};
2415     $spc =~ s/\w//g;
2416     $spc = substr($spc, 1, 1);
2417
2418     if ($date =~ /\D/) {
2419       if ($myconfig->{dateformat} =~ /^yy/) {
2420         ($yy, $mm, $dd) = split /\D/, $date;
2421       }
2422       if ($myconfig->{dateformat} =~ /^mm/) {
2423         ($mm, $dd, $yy) = split /\D/, $date;
2424       }
2425       if ($myconfig->{dateformat} =~ /^dd/) {
2426         ($dd, $mm, $yy) = split /\D/, $date;
2427       }
2428     } else {
2429       $date = substr($date, 2);
2430       ($yy, $mm, $dd) = ($date =~ /(..)(..)(..)/);
2431     }
2432
2433     $dd *= 1;
2434     $mm--;
2435     $yy = ($yy < 70) ? $yy + 2000 : $yy;
2436     $yy = ($yy >= 70 && $yy <= 99) ? $yy + 1900 : $yy;
2437
2438     if ($myconfig->{dateformat} =~ /^dd/) {
2439       if (defined $longformat && $longformat == 0) {
2440         $mm++;
2441         $dd = "0$dd" if ($dd < 10);
2442         $mm = "0$mm" if ($mm < 10);
2443         $longdate = "$dd$spc$mm$spc$yy";
2444       } else {
2445         $longdate = "$dd";
2446         $longdate .= ($spc eq '.') ? ". " : " ";
2447         $longdate .= &text($self, $self->{$longmonth}[$mm]) . " $yy";
2448       }
2449     } elsif ($myconfig->{dateformat} eq "yyyy-mm-dd") {
2450
2451       # Use German syntax with the ISO date style "yyyy-mm-dd" because
2452       # Lx-Office is mainly used in Germany or German speaking countries.
2453       if (defined $longformat && $longformat == 0) {
2454         $mm++;
2455         $dd = "0$dd" if ($dd < 10);
2456         $mm = "0$mm" if ($mm < 10);
2457         $longdate = "$yy-$mm-$dd";
2458       } else {
2459         $longdate = "$dd. ";
2460         $longdate .= &text($self, $self->{$longmonth}[$mm]) . " $yy";
2461       }
2462     } else {
2463       if (defined $longformat && $longformat == 0) {
2464         $mm++;
2465         $dd = "0$dd" if ($dd < 10);
2466         $mm = "0$mm" if ($mm < 10);
2467         $longdate = "$mm$spc$dd$spc$yy";
2468       } else {
2469         $longdate = &text($self, $self->{$longmonth}[$mm]) . " $dd, $yy";
2470       }
2471     }
2472
2473   }
2474
2475   $main::lxdebug->leave_sub();
2476
2477   return $longdate;
2478 }
2479
2480 sub parse_date {
2481   $main::lxdebug->enter_sub();
2482
2483   my ($self, $myconfig, $date, $longformat) = @_;
2484
2485   unless ($date) {
2486     $main::lxdebug->leave_sub();
2487     return ();
2488   }
2489
2490   # get separator
2491   $spc = $myconfig->{dateformat};
2492   $spc =~ s/\w//g;
2493   $spc = substr($spc, 1, 1);
2494
2495   if ($date =~ /\D/) {
2496     if ($myconfig->{dateformat} =~ /^yy/) {
2497       ($yy, $mm, $dd) = split /\D/, $date;
2498     } elsif ($myconfig->{dateformat} =~ /^mm/) {
2499       ($mm, $dd, $yy) = split /\D/, $date;
2500     } elsif ($myconfig->{dateformat} =~ /^dd/) {
2501       ($dd, $mm, $yy) = split /\D/, $date;
2502     }
2503   } else {
2504     $date = substr($date, 2);
2505     ($yy, $mm, $dd) = ($date =~ /(..)(..)(..)/);
2506   }
2507
2508   $dd *= 1;
2509   $mm *= 1;
2510   $yy = ($yy < 70) ? $yy + 2000 : $yy;
2511   $yy = ($yy >= 70 && $yy <= 99) ? $yy + 1900 : $yy;
2512
2513   $main::lxdebug->leave_sub();
2514   return ($yy, $mm, $dd);
2515 }
2516
2517 1;