+ $myconfig->save_member($memberfile);
+
+ my $auth = $main::auth;
+
+ if ($auth->can_change_password()
+ && defined $form->{new_password}
+ && ($form->{new_password} ne '********')) {
+ $auth->change_password($form->{login}, $form->{new_password});
+
+ $form->{password} = $form->{new_password};
+ $auth->set_session_value('password', $form->{password});
+ $auth->create_or_refresh_session();
+ }
+
+ if ($webdav) {
+ @webdavdirs =
+ qw(angebote bestellungen rechnungen anfragen lieferantenbestellungen einkaufsrechnungen);
+ foreach $directory (@webdavdirs) {
+ $file = "webdav/" . $directory . "/webdav-user";
+ if ($myconfig->{$directory}) {
+ open(HTACCESS, "$file") or die "cannot open webdav-user $!\n";
+ while (<HTACCESS>) {
+ ($login, $password) = split(/:/, $_);
+ if ($login ne $form->{login}) {
+ $newfile .= $_;
+ }
+ }
+ close(HTACCESS);
+ open(HTACCESS, "> $file") or die "cannot open webdav-user $!\n";
+ $newfile .= $myconfig->{login} . ":" . $myconfig->{password} . "\n";
+ print(HTACCESS $newfile);
+ close(HTACCESS);
+ } else {
+ $form->{$directory} = 0;
+ open(HTACCESS, "$file") or die "cannot open webdav-user $!\n";
+ while (<HTACCESS>) {
+ ($login, $password) = split(/:/, $_);
+ if ($login ne $form->{login}) {
+ $newfile .= $_;
+ }
+ }
+ close(HTACCESS);
+ open(HTACCESS, "> $file") or die "cannot open webdav-user $!\n";
+ print(HTACCESS $newfile);
+ close(HTACCESS);
+ }
+ }
+ }
+
+ $main::lxdebug->leave_sub();
+
+ return $rc;
+}
+
+sub defaultaccounts {
+ $main::lxdebug->enter_sub();
+
+ my ($self, $myconfig, $form) = @_;
+
+ # connect to database
+ my $dbh = $form->dbconnect($myconfig);
+
+ # get defaults from defaults table
+ my $query = qq|SELECT * FROM defaults|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ $form->{defaults} = $sth->fetchrow_hashref(NAME_lc);
+ $form->{defaults}{IC} = $form->{defaults}{inventory_accno_id};
+ $form->{defaults}{IC_income} = $form->{defaults}{income_accno_id};
+ $form->{defaults}{IC_expense} = $form->{defaults}{expense_accno_id};
+ $form->{defaults}{FX_gain} = $form->{defaults}{fxgain_accno_id};
+ $form->{defaults}{FX_loss} = $form->{defaults}{fxloss_accno_id};
+
+ $sth->finish;
+
+ $query = qq|SELECT c.id, c.accno, c.description, c.link
+ FROM chart c
+ WHERE c.link LIKE '%IC%'
+ ORDER BY c.accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ foreach my $key (split(/:/, $ref->{link})) {
+ if ($key =~ /IC/) {
+ $nkey = $key;
+ if ($key =~ /cogs/) {
+ $nkey = "IC_expense";
+ }
+ if ($key =~ /sale/) {
+ $nkey = "IC_income";
+ }
+ %{ $form->{IC}{$nkey}{ $ref->{accno} } } = (
+ id => $ref->{id},
+ description => $ref->{description}
+ );
+ }
+ }
+ }
+ $sth->finish;
+
+ $query = qq|SELECT c.id, c.accno, c.description
+ FROM chart c
+ WHERE c.category = 'I'
+ AND c.charttype = 'A'
+ ORDER BY c.accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ %{ $form->{IC}{FX_gain}{ $ref->{accno} } } = (
+ id => $ref->{id},
+ description => $ref->{description}
+ );
+ }
+ $sth->finish;
+
+ $query = qq|SELECT c.id, c.accno, c.description
+ FROM chart c
+ WHERE c.category = 'E'
+ AND c.charttype = 'A'
+ ORDER BY c.accno|;
+ $sth = $dbh->prepare($query);
+ $sth->execute || $self->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ %{ $form->{IC}{FX_loss}{ $ref->{accno} } } = (
+ id => $ref->{id},
+ description => $ref->{description}
+ );
+ }
+ $sth->finish;
+
+ # now get the tax rates and numbers
+ $query = qq|SELECT c.id, c.accno, c.description,
+ t.rate * 100 AS rate, t.taxnumber
+ FROM chart c, tax t
+ WHERE c.id = t.chart_id|;
+
+ $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
+ $form->{taxrates}{ $ref->{accno} }{id} = $ref->{id};
+ $form->{taxrates}{ $ref->{accno} }{description} = $ref->{description};
+ $form->{taxrates}{ $ref->{accno} }{taxnumber} = $ref->{taxnumber}
+ if $ref->{taxnumber};
+ $form->{taxrates}{ $ref->{accno} }{rate} = $ref->{rate} if $ref->{rate};
+ }
+
+ $sth->finish;
+ $dbh->disconnect;
+
+ $main::lxdebug->leave_sub();
+}
+
+sub closedto {
+ $main::lxdebug->enter_sub();
+
+ my ($self, $myconfig, $form) = @_;
+
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = qq|SELECT closedto, revtrans FROM defaults|;
+ my $sth = $dbh->prepare($query);
+ $sth->execute || $form->dberror($query);
+
+ ($form->{closedto}, $form->{revtrans}) = $sth->fetchrow_array;
+
+ $sth->finish;
+
+ $dbh->disconnect;
+
+ $main::lxdebug->leave_sub();
+}
+
+sub closebooks {
+ $main::lxdebug->enter_sub();
+
+ my ($self, $myconfig, $form) = @_;
+
+ my $dbh = $form->dbconnect($myconfig);
+
+ my ($query, @values);
+
+ if ($form->{revtrans}) {
+ $query = qq|UPDATE defaults SET closedto = NULL, revtrans = '1'|;
+
+ } elsif ($form->{closedto}) {
+ $query = qq|UPDATE defaults SET closedto = ?, revtrans = '0'|;
+ @values = (conv_date($form->{closedto}));
+
+ } else {
+ $query = qq|UPDATE defaults SET closedto = NULL, revtrans = '0'|;
+ }
+
+ # set close in defaults
+ do_query($form, $dbh, $query, @values);
+
+ $dbh->disconnect;
+
+ $main::lxdebug->leave_sub();
+}
+
+sub get_base_unit {
+ my ($self, $units, $unit_name, $factor) = @_;
+
+ $factor = 1 unless ($factor);
+
+ my $unit = $units->{$unit_name};
+
+ if (!defined($unit) || !$unit->{"base_unit"} ||
+ ($unit_name eq $unit->{"base_unit"})) {
+ return ($unit_name, $factor);
+ }
+
+ return AM->get_base_unit($units, $unit->{"base_unit"}, $factor * $unit->{"factor"});
+}
+
+sub retrieve_units {
+ $main::lxdebug->enter_sub();
+
+ my ($self, $myconfig, $form, $prefix) = @_;
+
+ my $dbh = $form->dbconnect($myconfig);
+
+ my $query = "SELECT *, base_unit AS original_base_unit FROM units";
+
+ my $sth = prepare_execute_query($form, $dbh, $query);
+
+ my $units = {};
+ while (my $ref = $sth->fetchrow_hashref()) {
+ $units->{$ref->{"name"}} = $ref;
+ }
+ $sth->finish();
+
+ my $query_lang = "SELECT id, template_code FROM language ORDER BY description";
+ $sth = $dbh->prepare($query_lang);
+ $sth->execute() || $form->dberror($query_lang);
+ my @languages;
+ while ($ref = $sth->fetchrow_hashref()) {
+ push(@languages, $ref);
+ }
+ $sth->finish();
+
+ $query_lang = "SELECT ul.localized, ul.localized_plural, l.id, l.template_code " .
+ "FROM units_language ul " .
+ "LEFT JOIN language l ON ul.language_id = l.id " .
+ "WHERE ul.unit = ?";
+ $sth = $dbh->prepare($query_lang);
+
+ foreach my $unit (values(%{$units})) {
+ ($unit->{"${prefix}base_unit"}, $unit->{"${prefix}factor"}) = AM->get_base_unit($units, $unit->{"name"});
+
+ $unit->{"LANGUAGES"} = {};
+ foreach my $lang (@languages) {
+ $unit->{"LANGUAGES"}->{$lang->{"template_code"}} = { "template_code" => $lang->{"template_code"} };
+ }
+
+ $sth->execute($unit->{"name"}) || $form->dberror($query_lang . " (" . $unit->{"name"} . ")");
+ while ($ref = $sth->fetchrow_hashref()) {
+ map({ $unit->{"LANGUAGES"}->{$ref->{"template_code"}}->{$_} = $ref->{$_} } keys(%{$ref}));
+ }
+ }
+ $sth->finish();
+
+ $dbh->disconnect();
+
+ $main::lxdebug->leave_sub();
+
+ return $units;
+}
+
+sub retrieve_all_units {
+ $main::lxdebug->enter_sub();
+
+ my $self = shift;
+
+ if (!$main::all_units) {
+ $main::all_units = $self->retrieve_units(\%main::myconfig, $main::form);
+ }
+
+ $main::lxdebug->leave_sub();
+
+ return $main::all_units;
+}
+
+
+sub translate_units {
+ $main::lxdebug->enter_sub();
+
+ my ($self, $form, $template_code, $unit, $amount) = @_;
+
+ my $units = $self->retrieve_units(\%main::myconfig, $form);
+
+ my $h = $units->{$unit}->{"LANGUAGES"}->{$template_code};
+ my $new_unit = $unit;
+ if ($h) {
+ if (($amount != 1) && $h->{"localized_plural"}) {
+ $new_unit = $h->{"localized_plural"};
+ } elsif ($h->{"localized"}) {
+ $new_unit = $h->{"localized"};
+ }
+ }
+
+ $main::lxdebug->leave_sub();
+
+ return $new_unit;
+}
+
+sub units_in_use {
+ $main::lxdebug->enter_sub();
+
+ my ($self, $myconfig, $form, $units) = @_;
+
+ my $dbh = $form->dbconnect($myconfig);
+
+ map({ $_->{"in_use"} = 0; } values(%{$units}));
+
+ foreach my $unit (values(%{$units})) {
+ my $base_unit = $unit->{"original_base_unit"};
+ while ($base_unit) {
+ $units->{$base_unit}->{"in_use"} = 1;
+ $units->{$base_unit}->{"DEPENDING_UNITS"} = [] unless ($units->{$base_unit}->{"DEPENDING_UNITS"});
+ push(@{$units->{$base_unit}->{"DEPENDING_UNITS"}}, $unit->{"name"});
+ $base_unit = $units->{$base_unit}->{"original_base_unit"};
+ }
+ }
+
+ foreach my $unit (values(%{$units})) {
+ map({ $_ = $dbh->quote($_); } @{$unit->{"DEPENDING_UNITS"}});
+
+ foreach my $table (qw(parts invoice orderitems)) {
+ my $query = "SELECT COUNT(*) FROM $table WHERE unit ";
+
+ if (0 == scalar(@{$unit->{"DEPENDING_UNITS"}})) {
+ $query .= "= " . $dbh->quote($unit->{"name"});
+ } else {
+ $query .= "IN (" . $dbh->quote($unit->{"name"}) . "," .
+ join(",", map({ $dbh->quote($_) } @{$unit->{"DEPENDING_UNITS"}})) . ")";
+ }
+
+ my ($count) = $dbh->selectrow_array($query);
+ $form->dberror($query) if ($dbh->err);
+
+ if ($count) {
+ $unit->{"in_use"} = 1;
+ last;
+ }
+ }
+ }
+
+ $dbh->disconnect();
+
+ $main::lxdebug->leave_sub();
+}
+
+sub convertible_units {
+ $main::lxdebug->enter_sub();
+
+ my $self = shift;
+ my $units = shift;
+ my $filter_unit = shift;
+ my $not_smaller = shift;
+
+ my $conv_units = [];
+
+ $filter_unit = $units->{$filter_unit};
+
+ foreach my $name (sort { lc $a cmp lc $b } keys %{ $units }) {
+ my $unit = $units->{$name};
+
+ if (($unit->{base_unit} eq $filter_unit->{base_unit}) &&
+ (!$not_smaller || ($unit->{factor} >= $filter_unit->{factor}))) {
+ push @{$conv_units}, $unit;
+ }
+ }
+
+ my @sorted = sort { $b->{factor} <=> $a->{factor} } @{ $conv_units };
+
+ $main::lxdebug->leave_sub();
+
+ return \@sorted;
+}
+
+# if $a is translatable to $b, return the factor between them.
+# else return 1
+sub convert_unit {
+ $main::lxdebug->enter_sub(2);
+ ($this, $a, $b, $all_units) = @_;
+
+ $main::lxdebug->leave_sub(2) and return 0 unless $all_units->{$a} && $all_units->{$b};
+ $main::lxdebug->leave_sub(2) and return 0 unless $all_units->{$a}{base_unit} eq $all_units->{$b}{base_unit};
+ $main::lxdebug->leave_sub(2) and return $all_units->{$a}{factor} / $all_units->{$b}{factor};
+}
+
+sub unit_select_data {
+ $main::lxdebug->enter_sub();
+
+ my ($self, $units, $selected, $empty_entry, $convertible_into) = @_;
+
+ my $select = [];
+
+ if ($empty_entry) {
+ push(@{$select}, { "name" => "", "base_unit" => "", "factor" => "", "selected" => "" });
+ }
+
+ foreach my $unit (sort({ $units->{$a}->{"sortkey"} <=> $units->{$b}->{"sortkey"} } keys(%{$units}))) {
+ if (!$convertible_into ||
+ ($units->{$convertible_into} &&
+ ($units->{$convertible_into}->{base_unit} eq $units->{$unit}->{base_unit}))) {
+ push @{$select}, { "name" => $unit,
+ "base_unit" => $units->{$unit}->{"base_unit"},
+ "factor" => $units->{$unit}->{"factor"},
+ "selected" => ($unit eq $selected) ? "selected" : "" };
+ }
+ }
+
+ $main::lxdebug->leave_sub();
+
+ return $select;
+}
+
+sub unit_select_html {
+ $main::lxdebug->enter_sub();
+
+ my ($self, $units, $name, $selected, $convertible_into) = @_;
+
+ my $select = "<select name=${name}>";
+
+ foreach my $unit (sort({ $units->{$a}->{"sortkey"} <=> $units->{$b}->{"sortkey"} } keys(%{$units}))) {
+ if (!$convertible_into ||
+ ($units->{$convertible_into} &&
+ ($units->{$convertible_into}->{"base_unit"} eq $units->{$unit}->{"base_unit"}))) {
+ $select .= "<option" . (($unit eq $selected) ? " selected" : "") . ">${unit}</option>";
+ }
+ }
+ $select .= "</select>";
+
+ $main::lxdebug->leave_sub();
+
+ return $select;
+}
+
+sub sum_with_unit {
+ $main::lxdebug->enter_sub();
+
+ my $self = shift;
+
+ my $units = $self->retrieve_all_units();
+
+ my $sum = 0;
+ my $base_unit;
+
+ while (2 <= scalar(@_)) {
+ my $qty = shift(@_);
+ my $unit = $units->{shift(@_)};
+
+ croak "No unit defined with name $unit" if (!defined $unit);
+
+ if (!$base_unit) {
+ $base_unit = $unit->{base_unit};
+ } elsif ($base_unit ne $unit->{base_unit}) {
+ croak "Adding values with incompatible base units $base_unit/$unit->{base_unit}";
+ }
+
+ $sum += $qty * $unit->{factor};
+ }
+
+ $main::lxdebug->leave_sub();
+
+ return wantarray ? ($sum, $baseunit) : $sum;
+}
+
+sub add_unit {
+ $main::lxdebug->enter_sub();
+
+ my ($self, $myconfig, $form, $name, $base_unit, $factor, $languages) = @_;
+
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my $query = qq|SELECT COALESCE(MAX(sortkey), 0) + 1 FROM units|;
+ my ($sortkey) = selectrow_query($form, $dbh, $query);
+
+ $query = "INSERT INTO units (name, base_unit, factor, sortkey) " .
+ "VALUES (?, ?, ?, ?)";
+ do_query($form, $dbh, $query, $name, $base_unit, $factor, $sortkey);
+
+ if ($languages) {
+ $query = "INSERT INTO units_language (unit, language_id, localized, localized_plural) VALUES (?, ?, ?, ?)";
+ my $sth = $dbh->prepare($query);
+ foreach my $lang (@{$languages}) {
+ my @values = ($name, $lang->{"id"}, $lang->{"localized"}, $lang->{"localized_plural"});
+ $sth->execute(@values) || $form->dberror($query . " (" . join(", ", @values) . ")");
+ }
+ $sth->finish();
+ }
+
+ $dbh->commit();
+ $dbh->disconnect();
+
+ $main::lxdebug->leave_sub();
+}
+
+sub save_units {
+ $main::lxdebug->enter_sub();
+
+ my ($self, $myconfig, $form, $units, $delete_units) = @_;
+
+ my $dbh = $form->dbconnect_noauto($myconfig);
+
+ my ($base_unit, $unit, $sth, $query);
+
+ $query = "DELETE FROM units_language";
+ $dbh->do($query) || $form->dberror($query);
+
+ if ($delete_units && (0 != scalar(@{$delete_units}))) {
+ $query = "DELETE FROM units WHERE name IN (";
+ map({ $query .= "?," } @{$delete_units});
+ substr($query, -1, 1) = ")";
+ $dbh->do($query, undef, @{$delete_units}) ||
+ $form->dberror($query . " (" . join(", ", @{$delete_units}) . ")");
+ }
+
+ $query = "UPDATE units SET name = ?, base_unit = ?, factor = ? WHERE name = ?";
+ $sth = $dbh->prepare($query);
+
+ my $query_lang = "INSERT INTO units_language (unit, language_id, localized, localized_plural) VALUES (?, ?, ?, ?)";
+ my $sth_lang = $dbh->prepare($query_lang);
+
+ foreach $unit (values(%{$units})) {
+ $unit->{"depth"} = 0;
+ my $base_unit = $unit;
+ while ($base_unit->{"base_unit"}) {
+ $unit->{"depth"}++;
+ $base_unit = $units->{$base_unit->{"base_unit"}};
+ }
+ }
+
+ foreach $unit (sort({ $a->{"depth"} <=> $b->{"depth"} } values(%{$units}))) {
+ if ($unit->{"LANGUAGES"}) {
+ foreach my $lang (@{$unit->{"LANGUAGES"}}) {
+ next unless ($lang->{"id"} && $lang->{"localized"});
+ my @values = ($unit->{"name"}, $lang->{"id"}, $lang->{"localized"}, $lang->{"localized_plural"});
+ $sth_lang->execute(@values) || $form->dberror($query_lang . " (" . join(", ", @values) . ")");
+ }
+ }
+
+ next if ($unit->{"unchanged_unit"});
+
+ my @values = ($unit->{"name"}, $unit->{"base_unit"}, $unit->{"factor"}, $unit->{"old_name"});
+ $sth->execute(@values) || $form->dberror($query . " (" . join(", ", @values) . ")");
+ }
+
+ $sth->finish();
+ $sth_lang->finish();
+ $dbh->commit();
+ $dbh->disconnect();
+