1 #=====================================================================
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
7 #=====================================================================
8 # SQL-Ledger Accounting
11 # Author: Dieter Simader
12 # Email: dsimader@sql-ledger.org
13 # Web: http://www.sql-ledger.org
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation; either version 2 of the License, or
20 # (at your option) any later version.
22 # This program is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 # GNU General Public License for more details.
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #=====================================================================
31 # user related functions
33 #=====================================================================
49 $main::lxdebug->enter_sub();
51 my ($type, $login) = @_;
56 my %user_data = $main::auth->read_user($login);
57 map { $self->{$_} = $user_data{$_} } keys %user_data;
60 $main::lxdebug->leave_sub();
66 $main::lxdebug->enter_sub();
73 # scan the locale directory and read in the LANGUAGE files
74 opendir(DIR, "locale");
76 my @dir = grep(!/(^\.\.?$|\..*)/, readdir(DIR));
78 foreach my $dir (@dir) {
79 next unless open(FH, "locale/$dir/LANGUAGE");
83 $cc{$dir} = "@language";
88 $main::lxdebug->leave_sub();
94 $main::lxdebug->enter_sub();
96 my ($self, $form) = @_;
103 if ($self->{login}) {
104 my %myconfig = $main::auth->read_user($self->{login});
106 # check if database is down
108 DBI->connect($myconfig{dbconnect}, $myconfig{dbuser},
110 or $self->error($DBI::errstr);
112 # we got a connection, check the version
113 my $query = qq|SELECT version FROM defaults|;
114 my $sth = $dbh->prepare($query);
115 $sth->execute || $form->dberror($query);
117 my ($dbversion) = $sth->fetchrow_array;
120 $self->create_employee_entry($form, $dbh, \%myconfig);
122 $self->create_schema_info_table($form, $dbh);
128 my $dbupdater = SL::DBUpgrade2->new($form, $myconfig{"dbdriver"});
129 my $controls = $dbupdater->parse_dbupdate_controls;
131 map({ $form->{$_} = $myconfig{$_} }
132 qw(dbname dbhost dbport dbdriver dbuser dbpasswd dbconnect dateformat));
134 if (update_available($myconfig{"dbdriver"}, $dbversion) ||
135 update2_available($form, $controls)) {
137 $form->{"stylesheet"} = "lx-office-erp.css";
138 $form->{"title"} = $main::locale->text("Dataset upgrade");
140 print $form->parse_html_template("dbupgrade/header");
142 $form->{dbupdate} = "db$myconfig{dbname}";
143 $form->{ $form->{dbupdate} } = 1;
145 if ($form->{"show_dbupdate_warning"}) {
146 print $form->parse_html_template("dbupgrade/warning");
151 if (!open(FH, ">$main::userspath/nologin")) {
152 $form->show_generic_error($main::locale->text('A temporary file could not be created. ' .
153 'Please verify that the directory "#1" is writeable by the webserver.',
158 # required for Oracle
159 $form->{dbdefault} = $sid;
161 # ignore HUP, QUIT in case the webserver times out
162 $SIG{HUP} = 'IGNORE';
163 $SIG{QUIT} = 'IGNORE';
165 $self->dbupdate($form);
166 $self->dbupdate2($form, $dbupdater);
171 unlink("$main::userspath/nologin");
174 $self->{"menustyle"} eq "v3" ? "menuv3.pl" :
175 $self->{"menustyle"} eq "neu" ? "menunew.pl" :
176 $self->{"menustyle"} eq "js" ? "menujs.pl" :
177 $self->{"menustyle"} eq "xml" ? "menuXML.pl" :
180 print $form->parse_html_template("dbupgrade/footer", { "menufile" => $menufile });
187 $main::lxdebug->leave_sub();
193 $main::lxdebug->enter_sub();
195 my ($form, $db) = @_;
198 'Pg' => { 'yy-mm-dd' => 'set DateStyle to \'ISO\'',
199 'yyyy-mm-dd' => 'set DateStyle to \'ISO\'',
200 'mm/dd/yy' => 'set DateStyle to \'SQL, US\'',
201 'mm-dd-yy' => 'set DateStyle to \'POSTGRES, US\'',
202 'dd/mm/yy' => 'set DateStyle to \'SQL, EUROPEAN\'',
203 'dd-mm-yy' => 'set DateStyle to \'POSTGRES, EUROPEAN\'',
204 'dd.mm.yy' => 'set DateStyle to \'GERMAN\''
207 'yy-mm-dd' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'YY-MM-DD\'',
208 'yyyy-mm-dd' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'YYYY-MM-DD\'',
209 'mm/dd/yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'MM/DD/YY\'',
210 'mm-dd-yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'MM-DD-YY\'',
211 'dd/mm/yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD/MM/YY\'',
212 'dd-mm-yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD-MM-YY\'',
213 'dd.mm.yy' => 'ALTER SESSION SET NLS_DATE_FORMAT = \'DD.MM.YY\'',
216 $form->{dboptions} = $dboptions{ $form->{dbdriver} }{ $form->{dateformat} };
218 if ($form->{dbdriver} eq 'Pg') {
219 $form->{dbconnect} = "dbi:Pg:dbname=$db";
222 if ($form->{dbdriver} eq 'Oracle') {
223 $form->{dbconnect} = "dbi:Oracle:sid=$form->{sid}";
226 if ($form->{dbhost}) {
227 $form->{dbconnect} .= ";host=$form->{dbhost}";
229 if ($form->{dbport}) {
230 $form->{dbconnect} .= ";port=$form->{dbport}";
233 $main::lxdebug->leave_sub();
237 $main::lxdebug->enter_sub();
239 my @drivers = DBI->available_drivers();
241 $main::lxdebug->leave_sub();
243 return (grep { /(Pg|Oracle)/ } @drivers);
247 $main::lxdebug->enter_sub();
249 my ($self, $form) = @_;
254 $form->{dbdefault} = $form->{dbuser} unless $form->{dbdefault};
255 $form->{sid} = $form->{dbdefault};
256 &dbconnect_vars($form, $form->{dbdefault});
259 DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
262 if ($form->{dbdriver} eq 'Pg') {
264 qq|SELECT datname FROM pg_database | .
265 qq|WHERE NOT datname IN ('template0', 'template1')|;
266 $sth = $dbh->prepare($query);
267 $sth->execute() || $form->dberror($query);
269 while (my ($db) = $sth->fetchrow_array) {
271 if ($form->{only_acc_db}) {
273 next if ($db =~ /^template/);
275 &dbconnect_vars($form, $db);
277 DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
281 qq|SELECT tablename FROM pg_tables | .
282 qq|WHERE (tablename = 'defaults') AND (tableowner = ?)|;
283 my $sth = $dbh->prepare($query);
284 $sth->execute($form->{dbuser}) ||
285 $form->dberror($query . " ($form->{dbuser})");
287 if ($sth->fetchrow_array) {
288 push(@dbsources, $db);
294 push(@dbsources, $db);
298 if ($form->{dbdriver} eq 'Oracle') {
299 if ($form->{only_acc_db}) {
301 qq|SELECT owner FROM dba_objects | .
302 qq|WHERE object_name = 'DEFAULTS' AND object_type = 'TABLE'|;
304 $query = qq|SELECT username FROM dba_users|;
307 $sth = $dbh->prepare($query);
308 $sth->execute || $form->dberror($query);
310 while (my ($db) = $sth->fetchrow_array) {
311 push(@dbsources, $db);
318 $main::lxdebug->leave_sub();
323 sub dbclusterencoding {
324 $main::lxdebug->enter_sub();
326 my ($self, $form) = @_;
328 $form->{dbdefault} ||= $form->{dbuser};
330 dbconnect_vars($form, $form->{dbdefault});
332 my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) || $form->dberror();
333 my $query = qq|SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = 'template0'|;
334 my ($cluster_encoding) = $dbh->selectrow_array($query);
337 $main::lxdebug->leave_sub();
339 return $cluster_encoding;
343 $main::lxdebug->enter_sub();
345 my ($self, $form) = @_;
347 $form->{sid} = $form->{dbdefault};
348 &dbconnect_vars($form, $form->{dbdefault});
350 DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
352 $form->{db} =~ s/\"//g;
354 'Pg' => qq|CREATE DATABASE "$form->{db}"|,
356 qq|CREATE USER "$form->{db}" DEFAULT TABLESPACE USERS | .
357 qq|TEMPORARY TABLESPACE TEMP IDENTIFIED BY "$form->{db}"|
364 push(@{$dboptions{"Pg"}}, "ENCODING = " . $dbh->quote($form->{"encoding"}))
365 if ($form->{"encoding"});
366 if ($form->{"dbdefault"}) {
367 my $dbdefault = $form->{"dbdefault"};
368 $dbdefault =~ s/[^a-zA-Z0-9_\-]//g;
369 push(@{$dboptions{"Pg"}}, "TEMPLATE = $dbdefault");
372 my $query = $dbcreate{$form->{dbdriver}};
373 $query .= " WITH " . join(" ", @{$dboptions{"Pg"}}) if (@{$dboptions{"Pg"}});
375 # Ignore errors if the database exists.
378 if ($form->{dbdriver} eq 'Oracle') {
379 $query = qq|GRANT CONNECT, RESOURCE TO "$form->{db}"|;
380 do_query($form, $dbh, $query);
384 # setup variables for the new database
385 if ($form->{dbdriver} eq 'Oracle') {
386 $form->{dbuser} = $form->{db};
387 $form->{dbpasswd} = $form->{db};
390 &dbconnect_vars($form, $form->{db});
392 $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
395 my $db_charset = $Common::db_encoding_to_charset{$form->{encoding}};
396 $db_charset ||= Common::DEFAULT_CHARSET;
398 my $dbupdater = SL::DBUpgrade2->new($form, $form->{dbdriver});
400 $dbupdater->process_query($dbh, "sql/lx-office.sql", undef, $db_charset);
402 # load chart of accounts
403 $dbupdater->process_query($dbh, "sql/$form->{chart}-chart.sql", undef, $db_charset);
405 $query = "UPDATE defaults SET coa = ?";
406 do_query($form, $dbh, $query, $form->{chart});
410 $main::lxdebug->leave_sub();
413 # Process a Perl script which updates the database.
414 # If the script returns 1 then the update was successful.
415 # Return code "2" means "needs more interaction; remove
416 # users/nologin and end current request".
417 # All other return codes are fatal errors.
418 sub process_perl_script {
419 $main::lxdebug->enter_sub();
421 my ($self, $form, $dbh, $filename, $version_or_control, $db_charset) = @_;
423 my $fh = IO::File->new($filename, "r") or $form->error("$filename : $!\n");
425 my $file_charset = Common::DEFAULT_CHARSET;
427 if (ref($version_or_control) eq "HASH") {
428 $file_charset = $version_or_control->{charset};
433 next if !/^--\s*\@charset:\s*(.+)/;
437 $fh->seek(0, SEEK_SET);
440 my $contents = join "", <$fh>;
443 $db_charset ||= Common::DEFAULT_CHARSET;
445 my $iconv = SL::Iconv::get_converter($file_charset, $db_charset);
449 # setup dbup_ export vars
450 my %dbup_myconfig = ();
451 map({ $dbup_myconfig{$_} = $form->{$_}; }
452 qw(dbname dbuser dbpasswd dbhost dbport dbconnect));
454 my $dbup_locale = $::locale;
456 my $result = eval($contents);
463 if (!defined($result)) {
464 print $form->parse_html_template("dbupgrade/error",
465 { "file" => $filename,
468 } elsif (1 != $result) {
469 unlink("users/nologin") if (2 == $result);
473 if (ref($version_or_control) eq "HASH") {
474 $dbh->do("INSERT INTO schema_info (tag, login) VALUES (" .
475 $dbh->quote($version_or_control->{"tag"}) . ", " .
476 $dbh->quote($form->{"login"}) . ")");
477 } elsif ($version_or_control) {
478 $dbh->do("UPDATE defaults SET version = " .
479 $dbh->quote($version_or_control));
483 $main::lxdebug->leave_sub();
487 $main::lxdebug->enter_sub();
489 my ($self, $form) = @_;
490 $form->{db} =~ s/\"//g;
491 my %dbdelete = ('Pg' => qq|DROP DATABASE "$form->{db}"|,
492 'Oracle' => qq|DROP USER "$form->{db}" CASCADE|);
494 $form->{sid} = $form->{dbdefault};
495 &dbconnect_vars($form, $form->{dbdefault});
497 DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
499 my $query = $dbdelete{$form->{dbdriver}};
500 do_query($form, $dbh, $query);
504 $main::lxdebug->leave_sub();
507 sub dbsources_unused {
508 $main::lxdebug->enter_sub();
510 my ($self, $form) = @_;
512 $form->{only_acc_db} = 1;
514 my %members = $main::auth->read_all_users();
515 my %dbexcl = map { $_ => 1 } grep { $_ } map { $_->{dbname} } values %members;
517 $dbexcl{$form->{dbdefault}} = 1;
518 $dbexcl{$main::auth->{DB_config}->{db}} = 1;
520 my @dbunused = grep { !$dbexcl{$_} } dbsources("", $form);
522 $main::lxdebug->leave_sub();
528 $main::lxdebug->enter_sub();
530 my ($self, $form) = @_;
532 my %members = $main::auth->read_all_users();
533 my $controls = SL::DBUpgrade2->new($form, $form->{dbdriver})->parse_dbupdate_controls;
535 my ($query, $sth, %dbs_needing_updates);
537 foreach my $login (grep /[a-z]/, keys %members) {
538 my $member = $members{$login};
540 map { $form->{$_} = $member->{$_} } qw(dbname dbuser dbpasswd dbhost dbport);
541 dbconnect_vars($form, $form->{dbname});
543 my $dbh = DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd});
549 $query = qq|SELECT version FROM defaults|;
550 $sth = prepare_query($form, $dbh, $query);
551 if ($sth->execute()) {
552 ($version) = $sth->fetchrow_array();
557 next unless $version;
559 if (update_available($form->{dbdriver}, $version) || update2_available($form, $controls)) {
561 map { $dbinfo->{$_} = $member->{$_} } grep /^db/, keys %{ $member };
562 $dbs_needing_updates{$member->{dbhost} . "::" . $member->{dbname}} = $dbinfo;
566 $main::lxdebug->leave_sub();
568 return values %dbs_needing_updates;
572 $main::lxdebug->enter_sub(2);
574 my (@v, $version, $i);
576 @v = split(/\./, $_[0]);
577 while (scalar(@v) < 4) {
581 for ($i = 0; $i < 4; $i++) {
586 $main::lxdebug->leave_sub(2);
590 sub cmp_script_version {
591 my ($a_from, $a_to, $b_from, $b_to);
592 my ($i, $res_a, $res_b);
593 my ($my_a, $my_b) = ($a, $b);
595 $my_a =~ s/.*-upgrade-//;
597 $my_b =~ s/.*-upgrade-//;
599 my ($my_a_from, $my_a_to) = split(/-/, $my_a);
600 my ($my_b_from, $my_b_to) = split(/-/, $my_b);
602 $res_a = calc_version($my_a_from);
603 $res_b = calc_version($my_b_from);
605 if ($res_a == $res_b) {
606 $res_a = calc_version($my_a_to);
607 $res_b = calc_version($my_b_to);
610 return $res_a <=> $res_b;
613 sub update_available {
614 my ($dbdriver, $cur_version) = @_;
618 opendir SQLDIR, "sql/${dbdriver}-upgrade" || error("", "sql/${dbdriver}-upgrade: $!");
619 my @upgradescripts = grep /${dbdriver}-upgrade-\Q$cur_version\E.*\.(sql|pl)$/, readdir SQLDIR;
622 return ($#upgradescripts > -1);
625 sub create_schema_info_table {
626 $main::lxdebug->enter_sub();
628 my ($self, $form, $dbh) = @_;
630 my $query = "SELECT tag FROM schema_info LIMIT 1";
631 if (!$dbh->do($query)) {
634 qq|CREATE TABLE schema_info (| .
637 qq| itime timestamp DEFAULT now(), | .
638 qq| PRIMARY KEY (tag))|;
639 $dbh->do($query) || $form->dberror($query);
642 $main::lxdebug->leave_sub();
646 $main::lxdebug->enter_sub();
648 my ($self, $form) = @_;
652 $form->{sid} = $form->{dbdefault};
654 my @upgradescripts = ();
658 if ($form->{dbupdate}) {
660 # read update scripts into memory
661 opendir(SQLDIR, "sql/" . $form->{dbdriver} . "-upgrade")
662 or &error("", "sql/" . $form->{dbdriver} . "-upgrade : $!");
664 sort(cmp_script_version
665 grep(/$form->{dbdriver}-upgrade-.*?\.(sql|pl)$/,
670 my $db_charset = $main::dbcharset;
671 $db_charset ||= Common::DEFAULT_CHARSET;
673 my $dbupdater = SL::DBUpgrade2->new($form, $form->{dbdriver});
675 foreach my $db (split(/ /, $form->{dbupdate})) {
677 next unless $form->{$db};
679 # strip db from dataset
681 &dbconnect_vars($form, $db);
684 DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
687 $dbh->do($form->{dboptions}) if ($form->{dboptions});
690 $query = qq|SELECT version FROM defaults|;
691 my ($version) = selectrow_query($form, $dbh, $query);
693 next unless $version;
695 $version = calc_version($version);
697 foreach my $upgradescript (@upgradescripts) {
698 my $a = $upgradescript;
699 $a =~ s/^\Q$form->{dbdriver}\E-upgrade-|\.(sql|pl)$//g;
702 my ($mindb, $maxdb) = split /-/, $a;
703 my $str_maxdb = $maxdb;
704 $mindb = calc_version($mindb);
705 $maxdb = calc_version($maxdb);
707 next if ($version >= $maxdb);
709 # if there is no upgrade script exit
710 last if ($version < $mindb);
713 $main::lxdebug->message(LXDebug->DEBUG2(), "Applying Update $upgradescript");
714 if ($file_type eq "sql") {
715 $dbupdater->process_query($dbh, "sql/" . $form->{"dbdriver"} . "-upgrade/$upgradescript", $str_maxdb, $db_charset);
717 $self->process_perl_script($form, $dbh, "sql/" . $form->{"dbdriver"} .
718 "-upgrade/$upgradescript", $str_maxdb, $db_charset);
730 $main::lxdebug->leave_sub();
736 $main::lxdebug->enter_sub();
738 my ($self, $form, $dbupdater) = @_;
740 $form->{sid} = $form->{dbdefault};
742 my @upgradescripts = ();
743 my ($query, $sth, $tag);
746 @upgradescripts = $dbupdater->sort_dbupdate_controls;
748 my $db_charset = $main::dbcharset;
749 $db_charset ||= Common::DEFAULT_CHARSET;
751 foreach my $db (split / /, $form->{dbupdate}) {
753 next unless $form->{$db};
755 # strip db from dataset
757 &dbconnect_vars($form, $db);
760 DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd})
763 $dbh->do($form->{dboptions}) if ($form->{dboptions});
765 map({ $_->{"applied"} = 0; } @upgradescripts);
767 $self->create_schema_info_table($form, $dbh);
769 $query = qq|SELECT tag FROM schema_info|;
770 $sth = $dbh->prepare($query);
771 $sth->execute() || $form->dberror($query);
772 while (($tag) = $sth->fetchrow_array()) {
773 $dbupdater->{all_controls}->{$tag}->{"applied"} = 1 if (defined($dbupdater->{all_controls}->{$tag}));
778 foreach (@upgradescripts) {
779 if (!$_->{"applied"}) {
785 next if ($all_applied);
787 foreach my $control (@upgradescripts) {
788 next if ($control->{"applied"});
790 $control->{description} = SL::Iconv::convert($control->{charset}, $db_charset, $control->{description});
792 $control->{"file"} =~ /\.(sql|pl)$/;
796 $main::lxdebug->message(LXDebug->DEBUG2(), "Applying Update $control->{file}");
797 print $form->parse_html_template("dbupgrade/upgrade_message2", $control);
799 if ($file_type eq "sql") {
800 $dbupdater->process_query($dbh, "sql/" . $form->{"dbdriver"} . "-upgrade2/$control->{file}", $control, $db_charset);
802 $self->process_perl_script($form, $dbh, "sql/" . $form->{"dbdriver"} .
803 "-upgrade2/$control->{file}", $control, $db_charset);
812 $main::lxdebug->leave_sub();
817 sub update2_available {
818 $main::lxdebug->enter_sub();
820 my ($form, $controls) = @_;
822 map({ $_->{"applied"} = 0; } values(%{$controls}));
824 dbconnect_vars($form, $form->{"dbname"});
827 DBI->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}) ||
830 my ($query, $tag, $sth);
832 $query = qq|SELECT tag FROM schema_info|;
833 $sth = $dbh->prepare($query);
834 if ($sth->execute()) {
835 while (($tag) = $sth->fetchrow_array()) {
836 $controls->{$tag}->{"applied"} = 1 if (defined($controls->{$tag}));
842 map({ $main::lxdebug->leave_sub() and return 1 if (!$_->{"applied"}) }
843 values(%{$controls}));
845 $main::lxdebug->leave_sub();
850 $main::lxdebug->enter_sub();
853 my $form = \%main::form;
855 # format dbconnect and dboptions string
856 dbconnect_vars($self, $self->{dbname});
858 map { $self->{$_} =~ s/\r//g; } qw(address signature);
860 $main::auth->save_user($self->{login}, map { $_, $self->{$_} } config_vars());
862 my $dbh = DBI->connect($self->{dbconnect}, $self->{dbuser}, $self->{dbpasswd});
864 $self->create_employee_entry($form, $dbh, $self, 1);
868 $main::lxdebug->leave_sub();
871 sub create_employee_entry {
872 $main::lxdebug->enter_sub();
877 my $myconfig = shift;
878 my $update_existing = shift;
880 if (!does_table_exist($dbh, 'employee')) {
881 $main::lxdebug->leave_sub();
885 # add login to employee table if it does not exist
886 # no error check for employee table, ignore if it does not exist
887 my ($id) = selectrow_query($form, $dbh, qq|SELECT id FROM employee WHERE login = ?|, $self->{login});
890 my $query = qq|INSERT INTO employee (login, name, workphone, role) VALUES (?, ?, ?, ?)|;
891 do_query($form, $dbh, $query, ($self->{login}, $myconfig->{name}, $myconfig->{tel}, "user"));
893 } elsif ($update_existing) {
894 my $query = qq|UPDATE employee SET name = ?, workphone = ?, role = 'user' WHERE id = ?|;
895 do_query($form, $dbh, $query, $myconfig->{name}, $myconfig->{tel}, $id);
898 $main::lxdebug->leave_sub();
902 $main::lxdebug->enter_sub();
904 my @conf = qw(address admin businessnumber company countrycode
905 currency dateformat dbconnect dbdriver dbhost dbport dboptions
906 dbname dbuser dbpasswd email fax name numberformat password
907 printer role sid signature stylesheet tel templates vclimit angebote
908 bestellungen rechnungen anfragen lieferantenbestellungen einkaufsrechnungen
909 taxnumber co_ustid duns menustyle template_format default_media
910 default_printer_id copies show_form_details favorites
911 pdonumber sdonumber hide_cvar_search_options mandatory_departments
914 $main::lxdebug->leave_sub();
920 $main::lxdebug->enter_sub();
922 my ($self, $msg) = @_;
924 $main::lxdebug->show_backtrace();
926 if ($ENV{HTTP_USER_AGENT}) {
927 print qq|Content-Type: text/html
929 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
931 <body bgcolor=ffffff>
933 <h2><font color=red>Error!</font></h2>
940 $main::lxdebug->leave_sub();