From: Michael Wagner Date: Fri, 12 Aug 2022 11:53:09 +0000 (+0200) Subject: Merge branch 'b-3.6.1' of ../kivitendo-erp_20220811 X-Git-Tag: kivitendo-mebil_0.1-0~10 X-Git-Url: http://wagnertech.de/git?a=commitdiff_plain;h=53593baa211863fbf66540cf1bcc36c8fb37257f;hp=deb4d2dbb676d7d6f69dfe7815d6e0cb09bd4a44;p=kivitendo-erp.git Merge branch 'b-3.6.1' of ../kivitendo-erp_20220811 Conflicts: SL/Controller/Mebil.pm VERSION locale/de/all menus/user/00-erp.yaml --- diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..0ba85d8b7 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,39 @@ +module.exports = { + "env": { + "browser": true, + "es6": true, + "jquery": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2015 + }, + "rules": { + "indent": [ + "error", + 2 + ], + "linebreak-style": [ + "error", + "unix" + ], + "semi": [ + "error", + "always" + ], + "no-console": [ + "error", + { + "allow": [ + "warn", + "error" + ], + } + ] + }, + "globals": { + "namespace": true, + "kivi": true + }, +}; + diff --git a/.gitignore b/.gitignore index 7ade8b1cc..5c8f7d824 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ /users/pid/ /users/session_files/ /users/templates-cache/ +/users/templates-cache-for-tests/ /users/xvfb_display /webdav/* crm diff --git a/.htaccess b/.htaccess index 66862278a..106aeb458 100644 --- a/.htaccess +++ b/.htaccess @@ -1,11 +1,16 @@ -### Choose a character set (just in case you like to change it here) -### uncommit the line you wish to activate -#AddDefaultCharset ISO-8859-15 +# Should always be the default #AddDefaultCharset UTF-8 ### simple access control by client ip -### uncomment the lines starting with Order ..., Deny ... and Allow ... -### examples: "Allow from 192.168" or "Allow from 192.168.1" or "Allow from 192.168.178" or "Allow from 217.84.201.2" -#Order deny,allow -#Deny from all -#Allow from 192.168 +### uncomment the lines starting with until last +### examples for Apache >= 2.4: "Require ip 192.168" or "Require ip 192.168.1" or "Require ip 192.168.178" or "Require ip 217.84.201.2" +# +# # Apache 2.4 +# Require ip 192.168 +# + + + RewriteEngine On + RewriteRule .*/(\.git|config)/.*$ - [F,NC] + + diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 000000000..bff88db9f --- /dev/null +++ b/.jshintrc @@ -0,0 +1,12 @@ +{ + "laxcomma" : true, // tolerate "," at the beginning of lines + "laxbreak" : true, // tolerate "+" at the beginning of lines + "jquery": true, // assume jquery is loaded + "asi" : true, // tolerate satements without ";" yet + "eqeqeq" : false, // don't require === for comparisons yet + // "strict" : true + + "globals" : { + "predef": [ "kivi" ] + } +} diff --git a/.mailmap b/.mailmap new file mode 100644 index 000000000..bfb19e55b --- /dev/null +++ b/.mailmap @@ -0,0 +1,42 @@ +Bernd Bleßmann +Bernd Bleßmann +Bernd Bleßmann bernd +Christian Wittmer ChrisWi +Geoffrey Richardson +Geoffrey Richardson G. Richardson +Geoffrey Richardson +Geoffrey Richardson +Geoffrey Richardson grichardson +Holger Lindemann +Holger Lindemann +Jan Büren +Jan Büren +Jan Büren +Jan Büren +Jan Büren +Jan Büren +Jan Büren +Jan Büren +Jan Büren +Joachim Zach +Marei Peischl Marei (peiTeX) +Marei Peischl Marei Peischl (peiTeX) +Martin Helmling +Martin Helmling +Martin Helmling Martin Helmling martin.helmling@octosoft.eu +Martin Helmling Martin Helmling mh@waldpark.octosoft.eu +Moritz Bunkus +Moritz Bunkus +Niclas Zimmermann +Rolf Eike Beer Rolf Eike Beer +Roman Karuschka R. Karuschka +Roman Karuschka Roman Karushka +Roman Karuschka roman +Sven Schöling +Sven Schöling +Timo Eickmeyer T. Eickmeyer +Waldemar Toews +Wulf Coulmann Wulf +Wulf Coulmann root +Wulf Coulmann wulf@coulmann.de +Wulf Coulmann wulf@coulmann.de diff --git a/Devel/REPL/Plugin/AutoloadModules.pm b/Devel/REPL/Plugin/AutoloadModules.pm new file mode 100644 index 000000000..e36ee9654 --- /dev/null +++ b/Devel/REPL/Plugin/AutoloadModules.pm @@ -0,0 +1,29 @@ +package Devel::REPL::Plugin::AutoloadModules; + +use Moose::Role; +use namespace::clean -except => [ 'meta' ]; +use Data::Dumper; + +has 'autoloaded' => ( is => 'rw', isa => 'HashRef', default => sub { {} } ); + +my $re = qr/Runtime error: Can.t locate object method "\w+" via package "\w+" \(perhaps you forgot to load "(\w+)"\?\)/; +around 'execute' => sub { + my $orig = shift; + my $self = shift; + + my @re = $self->$orig(@_); # original call + + return @re unless defined $re[0] && $re[0] =~ /$re/; # if there is no "perhaps you forgot" error, just return + my $module = $1; # save the missing package name + + return @re if $self->autoloaded->{$module}; # if we tried to load it before, give up and return the error + + $self->autoloaded->{$module} = 1; # make sure we don't try this again + $self->eval("use SL::$module"); # try to load the missing module + + @re = $self->$orig(@_); # try again + + return @re; +}; + +1; diff --git a/Devel/REPL/Plugin/PermanentHistory.pm b/Devel/REPL/Plugin/PermanentHistory.pm new file mode 100644 index 000000000..3a46b56cf --- /dev/null +++ b/Devel/REPL/Plugin/PermanentHistory.pm @@ -0,0 +1,39 @@ +package Devel::REPL::Plugin::PermanentHistory; + +use Moose::Role; +use namespace::clean -except => [ 'meta' ]; +use File::Slurp; +use Data::Dumper; + +has 'history_file' => ( is => 'rw' ); + +sub load_history { + my $self = shift; + my $file = shift; + + $self->history_file( $file ); + + return unless $self->history_file && -f $self->history_file; + + my @history = + map { chomp; $_ } + read_file($self->history_file); +# print Dumper(\@history); + $self->history( \@history ); + $self->term->addhistory($_) for @history; +} + +before 'DESTROY' => sub { + my $self = shift; + + return unless $self->history_file; + + write_file $self->history_file, + map { $_, $/ } + grep $_, + grep { !/^quit\b/ } + @{ $self->history }; +}; + +1; + diff --git a/SL/.htaccess b/SL/.htaccess index 0a9a0473a..cde5b4437 100644 --- a/SL/.htaccess +++ b/SL/.htaccess @@ -1,2 +1,9 @@ -Order Allow,Deny -Deny from all + + # Apache 2.4 + Require all denied + + + # Apache 2.2 + Order deny,allow + Deny from all + diff --git a/SL/AM.pm b/SL/AM.pm index cbbfae03f..2d8ed4cff 100644 --- a/SL/AM.pm +++ b/SL/AM.pm @@ -25,7 +25,8 @@ # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1335, USA. #====================================================================== # # Administration module @@ -46,172 +47,107 @@ use SL::DB::AuthUser; use SL::DB::Default; use SL::DB::Employee; use SL::DB::Chart; +use SL::DB::Customer; +use SL::DB::Part; +use SL::DB::Vendor; +use SL::DB; use SL::GenericTranslations; +use SL::Helper::UserPreferences::DisplayPreferences; +use SL::Helper::UserPreferences::PositionsScrollbar; +use SL::Helper::UserPreferences::PartPickerSearch; +use SL::Helper::UserPreferences::TimeRecording; +use SL::Helper::UserPreferences::UpdatePositions; use strict; sub get_account { $main::lxdebug->enter_sub(); - my ($self, $myconfig, $form) = @_; - - # connect to database - my $dbh = $form->dbconnect($myconfig); - my $query = qq{ - SELECT c.accno, c.description, c.charttype, c.category, - c.link, c.pos_bilanz, c.pos_eur, c.new_chart_id, c.valid_from, - c.pos_bwa, datevautomatik, - tk.taxkey_id, tk.pos_ustva, tk.tax_id, - tk.tax_id || '--' || tk.taxkey_id AS tax, tk.startdate - FROM chart c - LEFT JOIN taxkeys tk - ON (c.id=tk.chart_id AND tk.id = - (SELECT id FROM taxkeys - WHERE taxkeys.chart_id = c.id AND startdate <= current_date - ORDER BY startdate DESC LIMIT 1)) - WHERE c.id = ? - }; - - - $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query"); - my $sth = $dbh->prepare($query); - $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})"); - - my $ref = $sth->fetchrow_hashref("NAME_lc"); + # fetch chart-related data and set form fields + # get_account is called by add_account in am.pl + # always sets $form->{TAXKEY} and default_accounts + # loads chart data when $form->{id} is passed - foreach my $key (keys %$ref) { - $form->{"$key"} = $ref->{"$key"}; - } - - $sth->finish; + my ($self, $myconfig, $form) = @_; # get default accounts - $query = qq|SELECT inventory_accno_id, income_accno_id, expense_accno_id - FROM defaults|; - $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query"); - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - $ref = $sth->fetchrow_hashref("NAME_lc"); - - map { $form->{$_} = $ref->{$_} } keys %{ $ref }; - - $sth->finish; - - - - # get taxkeys and description - $query = qq{ - SELECT - id, - (SELECT accno FROM chart WHERE id=tax.chart_id) AS chart_accno, - taxkey, - id||'--'||taxkey AS tax, - taxdescription, - rate - FROM tax ORDER BY taxkey - }; - $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query"); - $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); + map { $form->{$_} = $::instance_conf->{$_} } qw(inventory_accno_id income_accno_id expense_accno_id); + require SL::DB::Tax; + my $taxes = SL::DB::Manager::Tax->get_all( with_objects => ['chart'] , sort_by => 'taxkey' ); $form->{TAXKEY} = []; + foreach my $tk ( @{$taxes} ) { + push @{ $form->{TAXKEY} }, { id => $tk->id, + chart_accno => $tk->chart_id ? $tk->chart->accno : undef, + taxkey => $tk->taxkey, + tax => $tk->id . '--' . $tk->taxkey, + rate => $tk->rate + }; + }; - while (my $ref = $sth->fetchrow_hashref("NAME_lc")) { - push @{ $form->{TAXKEY} }, $ref; - } - - $sth->finish; if ($form->{id}) { - # get new accounts - $query = qq|SELECT id, accno,description - FROM chart - WHERE link = ? - ORDER BY accno|; - $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query"); - $sth = $dbh->prepare($query); - $sth->execute($form->{link}) || $form->dberror($query . " ($form->{link})"); - $form->{NEWACCOUNT} = []; - while (my $ref = $sth->fetchrow_hashref("NAME_lc")) { - push @{ $form->{NEWACCOUNT} }, $ref; + my $chart_obj = SL::DB::Manager::Chart->find_by(id => $form->{id}) || die "Can't open chart"; + + my @chart_fields = qw(accno description charttype category link pos_bilanz + pos_eur pos_er new_chart_id valid_from pos_bwa datevautomatik); + foreach my $cf ( @chart_fields ) { + $form->{"$cf"} = $chart_obj->$cf; } - $sth->finish; + my $active_taxkey = $chart_obj->get_active_taxkey; + $form->{$_} = $active_taxkey->$_ foreach qw(taxkey_id pos_ustva tax_id startdate); + $form->{tax} = $active_taxkey->tax_id . '--' . $active_taxkey->taxkey_id; - # get the taxkeys of account - - $query = qq{ - SELECT - tk.id, - tk.chart_id, - c.accno, - tk.tax_id, - t.taxdescription, - t.rate, - tk.taxkey_id, - tk.pos_ustva, - tk.startdate - FROM taxkeys tk - LEFT JOIN tax t ON (t.id = tk.tax_id) - LEFT JOIN chart c ON (c.id = t.chart_id) - - WHERE tk.chart_id = ? - ORDER BY startdate DESC - }; - $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query"); - $sth = $dbh->prepare($query); + # check if there are any transactions for this chart + $form->{orphaned} = $chart_obj->has_transaction ? 0 : 1; - $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})"); + # check if new account is active + # The old sql query was broken since at least 2006 and always returned 0 + $form->{new_chart_valid} = $chart_obj->new_chart_valid; + # get the taxkeys of the account $form->{ACCOUNT_TAXKEYS} = []; - - while (my $ref = $sth->fetchrow_hashref("NAME_lc")) { - push @{ $form->{ACCOUNT_TAXKEYS} }, $ref; + foreach my $taxkey ( sort { $b->startdate <=> $a->startdate } @{ $chart_obj->taxkeys } ) { + push @{ $form->{ACCOUNT_TAXKEYS} }, { id => $taxkey->id, + chart_id => $taxkey->chart_id, + tax_id => $taxkey->tax_id, + taxkey_id => $taxkey->taxkey_id, + pos_ustva => $taxkey->pos_ustva, + startdate => $taxkey->startdate->to_kivitendo, + taxdescription => $taxkey->tax->taxdescription, + rate => $taxkey->tax->rate, + accno => defined $taxkey->tax->chart_id ? $taxkey->tax->chart->accno : undef, + }; } - $sth->finish; - - } - # check if we have any transactions - $query = qq|SELECT a.trans_id FROM acc_trans a - WHERE a.chart_id = ?|; - $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query"); - $sth = $dbh->prepare($query); - $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})"); - - ($form->{orphaned}) = $sth->fetchrow_array; - $form->{orphaned} = !$form->{orphaned}; - $sth->finish; - - # check if new account is active - $form->{new_chart_valid} = 0; - if ($form->{new_chart_id}) { - $query = qq|SELECT current_date-valid_from FROM chart - WHERE id = ?|; - $main::lxdebug->message(LXDebug->QUERY(), "\$query=\n $query"); - my ($count) = selectrow_query($form, $dbh, $query, $form->{id}); - if ($count >=0) { - $form->{new_chart_valid} = 1; - } - $sth->finish; - } + # get new accounts (Folgekonto). Find all charts with the same link + $form->{NEWACCOUNT} = $chart_obj->db->dbh->selectall_arrayref('select id, accno,description from chart where link = ? and id != ? order by accno', {Slice => {}}, $chart_obj->link, $form->{id}); - $dbh->disconnect; + } else { # set to orphaned for new charts, so chart_type can be changed (needed by $AccountIsPosted) + $form->{orphaned} = 1; + }; $main::lxdebug->leave_sub(); } sub save_account { + my ($self, $myconfig, $form) = @_; $main::lxdebug->enter_sub(); + my $rc = SL::DB->client->with_transaction(\&_save_account, $self, $myconfig, $form); + + $::lxdebug->leave_sub; + return $rc; +} + +sub _save_account { # TODO: it should be forbidden to change an account to a heading if there # have been bookings to this account in the past my ($self, $myconfig, $form) = @_; - # connect to database, turn off AutoCommit - my $dbh = $form->dbconnect_noauto($myconfig); + my $dbh = SL::DB->client->dbh; for (qw(AR_include_in_dropdown AP_include_in_dropdown summary_account)) { $form->{$form->{$_}} = $form->{$_} if $form->{$_}; @@ -224,23 +160,15 @@ sub save_account { } } - $form->{link} = ""; - foreach my $item ($form->{AR}, $form->{AR_amount}, - $form->{AR_tax}, $form->{AR_paid}, - $form->{AP}, $form->{AP_amount}, - $form->{AP_tax}, $form->{AP_paid}, - $form->{IC}, $form->{IC_sale}, - $form->{IC_cogs}, $form->{IC_taxpart}, - $form->{IC_income}, $form->{IC_expense}, - $form->{IC_taxservice} - ) { - $form->{link} .= "${item}:" if ($item); - } - chop $form->{link}; + my @link_order = qw(AR AR_amount AR_tax AR_paid AP AP_amount AP_tax AP_paid IC IC_sale IC_cogs IC_taxpart IC_income IC_expense IC_taxservice); + $form->{link} = join ':', grep $_, map $form->{$_}, @link_order; # strip blanks from accno map { $form->{$_} =~ s/ //g; } qw(accno); + # collapse multiple (horizontal) whitespace in chart description (Ticket 148) + map { $form->{$_} =~ s/\h+/ /g } qw(description); + my ($query, $sth); if ($form->{id} eq "NULL") { @@ -301,6 +229,7 @@ sub save_account { pos_bwa = ?, pos_bilanz = ?, pos_eur = ?, + pos_er = ?, new_chart_id = ?, valid_from = ?, datevautomatik = ? @@ -315,6 +244,7 @@ sub save_account { conv_i($form->{pos_bwa}), conv_i($form->{pos_bilanz}), conv_i($form->{pos_eur}), + conv_i($form->{pos_er}), conv_i($form->{new_chart_id}), conv_date($form->{valid_from}), ($form->{datevautomatik} eq 'T') ? 'true':'false', @@ -443,42 +373,32 @@ SQL do_query($form, $dbh, $query, $form->{id}); - # commit - my $rc = $dbh->commit; - $dbh->disconnect; - - $main::lxdebug->leave_sub(); - - return $rc; + return 1; } sub delete_account { + my ($self, $myconfig, $form) = @_; $main::lxdebug->enter_sub(); + my $rc = SL::DB->client->with_transaction(\&_delete_account, $self, $myconfig, $form); + + $::lxdebug->leave_sub; + return $rc; +} + +sub _delete_account { my ($self, $myconfig, $form) = @_; - # connect to database, turn off AutoCommit - my $dbh = $form->dbconnect_noauto($myconfig); + my $dbh = SL::DB->client->dbh; my $query = qq|SELECT count(*) FROM acc_trans a WHERE a.chart_id = ?|; my ($count) = selectrow_query($form, $dbh, $query, $form->{id}); if ($count) { - $dbh->disconnect; - $main::lxdebug->leave_sub(); return; } - # set inventory_accno_id, income_accno_id, expense_accno_id to defaults - foreach my $type (qw(inventory income expense)) { - $query = - qq|UPDATE parts | . - qq|SET ${type}_accno_id = (SELECT ${type}_accno_id FROM defaults) | . - qq|WHERE ${type}_accno_id = ?|; - do_query($form, $dbh, $query, $form->{id}); - } - $query = qq|DELETE FROM tax WHERE chart_id = ?|; do_query($form, $dbh, $query, $form->{id}); @@ -495,170 +415,7 @@ sub delete_account { WHERE id = ?|; do_query($form, $dbh, $query, $form->{id}); - # commit and redirect - my $rc = $dbh->commit; - $dbh->disconnect; - - $main::lxdebug->leave_sub(); - - return $rc; -} - -sub lead { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - - # connect to database - my $dbh = $form->dbconnect($myconfig); - - my $query = qq|SELECT id, lead - FROM leads - ORDER BY 2|; - - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - while (my $ref = $sth->fetchrow_hashref("NAME_lc")) { - push @{ $form->{ALL} }, $ref; - } - - $sth->finish; - $dbh->disconnect; - - $main::lxdebug->leave_sub(); -} - -sub get_lead { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - - # connect to database - my $dbh = $form->dbconnect($myconfig); - - my $query = - qq|SELECT l.id, l.lead | . - qq|FROM leads l | . - qq|WHERE l.id = ?|; - my $sth = $dbh->prepare($query); - $sth->execute($form->{id}) || $form->dberror($query . " ($form->{id})"); - - my $ref = $sth->fetchrow_hashref("NAME_lc"); - - map { $form->{$_} = $ref->{$_} } keys %$ref; - - $sth->finish; - - $dbh->disconnect; - - $main::lxdebug->leave_sub(); -} - -sub save_lead { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - my ($query); - - # connect to database - my $dbh = $form->dbconnect($myconfig); - - my @values = ($form->{description}); - # id is the old record - if ($form->{id}) { - $query = qq|UPDATE leads SET - lead = ? - WHERE id = ?|; - push(@values, $form->{id}); - } else { - $query = qq|INSERT INTO leads - (lead) - VALUES (?)|; - } - do_query($form, $dbh, $query, @values); - - $dbh->disconnect; - - $main::lxdebug->leave_sub(); -} - -sub delete_lead { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - my ($query); - - # connect to database - my $dbh = $form->dbconnect($myconfig); - - $query = qq|DELETE FROM leads - WHERE id = ?|; - do_query($form, $dbh, $query, $form->{id}); - - $dbh->disconnect; - - $main::lxdebug->leave_sub(); -} - -sub language { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form, $return_list) = @_; - - # connect to database - my $dbh = $form->dbconnect($myconfig); - - my $query = - "SELECT id, description, template_code, article_code, " . - " output_numberformat, output_dateformat, output_longdates " . - "FROM language ORDER BY description"; - - my $sth = $dbh->prepare($query); - $sth->execute || $form->dberror($query); - - my $ary = []; - - while (my $ref = $sth->fetchrow_hashref("NAME_lc")) { - push(@{ $ary }, $ref); - } - - $sth->finish; - $dbh->disconnect; - - $main::lxdebug->leave_sub(); - - if ($return_list) { - return @{$ary}; - } else { - $form->{ALL} = $ary; - } -} - -sub get_language { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - - # connect to database - my $dbh = $form->dbconnect($myconfig); - - my $query = - "SELECT description, template_code, article_code, " . - " output_numberformat, output_dateformat, output_longdates " . - "FROM language WHERE id = ?"; - my $sth = $dbh->prepare($query); - $sth->execute($form->{"id"}) || $form->dberror($query . " ($form->{id})"); - - my $ref = $sth->fetchrow_hashref("NAME_lc"); - - map { $form->{$_} = $ref->{$_} } keys %$ref; - - $sth->finish; - - $dbh->disconnect; - - $main::lxdebug->leave_sub(); + return 1; } sub get_language_details { @@ -666,80 +423,19 @@ sub get_language_details { my ($self, $myconfig, $form, $id) = @_; - # connect to database - my $dbh = $form->dbconnect($myconfig); + my $dbh = SL::DB->client->dbh; my $query = "SELECT template_code, " . " output_numberformat, output_dateformat, output_longdates " . "FROM language WHERE id = ?"; my @res = selectrow_query($form, $dbh, $query, $id); - $dbh->disconnect; $main::lxdebug->leave_sub(); return @res; } -sub save_language { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - - # connect to database - my $dbh = $form->dbconnect($myconfig); - my (@values, $query); - - map({ push(@values, $form->{$_}); } - qw(description template_code article_code - output_numberformat output_dateformat output_longdates)); - - # id is the old record - if ($form->{id}) { - $query = - "UPDATE language SET " . - " description = ?, template_code = ?, article_code = ?, " . - " output_numberformat = ?, output_dateformat = ?, " . - " output_longdates = ? " . - "WHERE id = ?"; - push(@values, $form->{id}); - } else { - $query = - "INSERT INTO language (" . - " description, template_code, article_code, " . - " output_numberformat, output_dateformat, output_longdates" . - ") VALUES (?, ?, ?, ?, ?, ?)"; - } - do_query($form, $dbh, $query, @values); - - $dbh->disconnect; - - $main::lxdebug->leave_sub(); -} - -sub delete_language { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - my $query; - - # connect to database - my $dbh = $form->dbconnect_noauto($myconfig); - - foreach my $table (qw(generic_translations units_language)) { - $query = qq|DELETE FROM $table WHERE language_id = ?|; - do_query($form, $dbh, $query, $form->{"id"}); - } - - $query = "DELETE FROM language WHERE id = ?"; - do_query($form, $dbh, $query, $form->{"id"}); - - $dbh->commit(); - $dbh->disconnect; - - $main::lxdebug->leave_sub(); -} - sub prepare_template_filename { $main::lxdebug->enter_sub(); @@ -747,30 +443,24 @@ sub prepare_template_filename { my ($filename, $display_filename); - if ($form->{type} eq "stylesheet") { - $filename = "css/$myconfig->{stylesheet}"; - $display_filename = $myconfig->{stylesheet}; - - } else { - $filename = $form->{formname}; + $filename = $form->{formname}; - if ($form->{language}) { - my ($id, $template_code) = split(/--/, $form->{language}); - $filename .= "_${template_code}"; - } + if ($form->{language}) { + my ($id, $template_code) = split(/--/, $form->{language}); + $filename .= "_${template_code}"; + } - if ($form->{printer}) { - my ($id, $template_code) = split(/--/, $form->{printer}); - $filename .= "_${template_code}"; - } + if ($form->{printer}) { + my ($id, $template_code) = split(/--/, $form->{printer}); + $filename .= "_${template_code}"; + } - $filename .= "." . ($form->{format} eq "html" ? "html" : "tex"); - if ($form->{"formname"} =~ m|\.\.| || $form->{"formname"} =~ m|^/|) { - $filename =~ s|.*/||; - } - $display_filename = $filename; - $filename = SL::DB::Default->get->templates . "/$filename"; + $filename .= "." . ($form->{format} eq "html" ? "html" : "tex"); + if ($form->{"formname"} =~ m|\.\.| || $form->{"formname"} =~ m|^/|) { + $filename =~ s|.*/||; } + $display_filename = $filename; + $filename = SL::DB::Default->get->templates . "/$filename"; $main::lxdebug->leave_sub(); @@ -825,12 +515,53 @@ sub save_template { return $error; } +sub displayable_name_specs_by_module { + +{ + 'SL::DB::Customer' => { + specs => SL::DB::Customer->displayable_name_specs, + prefs => SL::DB::Customer->displayable_name_prefs, + }, + 'SL::DB::Vendor' => { + specs => SL::DB::Vendor->displayable_name_specs, + prefs => SL::DB::Vendor->displayable_name_prefs, + }, + 'SL::DB::Part' => { + specs => SL::DB::Part->displayable_name_specs, + prefs => SL::DB::Part->displayable_name_prefs, + }, + }; +} + +sub positions_scrollbar_height { + SL::Helper::UserPreferences::PositionsScrollbar->new()->get_height(); +} + +sub purchase_search_makemodel { + SL::Helper::UserPreferences::PartPickerSearch->new()->get_purchase_search_makemodel(); +} + +sub sales_search_customer_partnumber { + SL::Helper::UserPreferences::PartPickerSearch->new()->get_sales_search_customer_partnumber(); +} + +sub positions_show_update_button { + SL::Helper::UserPreferences::UpdatePositions->new()->get_show_update_button(); +} + +sub time_recording_use_duration { + SL::Helper::UserPreferences::TimeRecording->new()->get_use_duration(); +} + +sub longdescription_dialog_size_percentage { + SL::Helper::UserPreferences::DisplayPreferences->new()->get_longdescription_dialog_size_percentage(); +} + sub save_preferences { $main::lxdebug->enter_sub(); my ($self, $form) = @_; - my $employee = SL::DB::Manager::Employee->find_by(login => $::myconfig{login}); + my $employee = SL::DB::Manager::Employee->current; $employee->update_attributes(name => $form->{name}); my $user = SL::DB::Manager::AuthUser->find_by(login => $::myconfig{login}); @@ -840,6 +571,35 @@ sub save_preferences { map { ($_ => $form->{$_}) } SL::DB::AuthUser::CONFIG_VARS(), }); + # Displayable name preferences + my $displayable_name_specs_by_module = displayable_name_specs_by_module(); + foreach my $specs (@{ $form->{displayable_name_specs} }) { + if (!$specs->{value} || $specs->{value} eq $displayable_name_specs_by_module->{$specs->{module}}->{prefs}->get_default()) { + $displayable_name_specs_by_module->{$specs->{module}}->{prefs}->delete($specs->{value}); + } else { + $displayable_name_specs_by_module->{$specs->{module}}->{prefs}->store_value($specs->{value}); + } + } + + if (exists $form->{positions_scrollbar_height}) { + SL::Helper::UserPreferences::PositionsScrollbar->new()->store_height($form->{positions_scrollbar_height}) + } + if (exists $form->{purchase_search_makemodel}) { + SL::Helper::UserPreferences::PartPickerSearch->new()->store_purchase_search_makemodel($form->{purchase_search_makemodel}) + } + if (exists $form->{sales_search_customer_partnumber}) { + SL::Helper::UserPreferences::PartPickerSearch->new()->store_sales_search_customer_partnumber($form->{sales_search_customer_partnumber}) + } + if (exists $form->{positions_show_update_button}) { + SL::Helper::UserPreferences::UpdatePositions->new()->store_show_update_button($form->{positions_show_update_button}) + } + if (exists $form->{time_recording_use_duration}) { + SL::Helper::UserPreferences::TimeRecording->new()->store_use_duration($form->{time_recording_use_duration}) + } + if (exists $form->{longdescription_dialog_size_percentage}) { + SL::Helper::UserPreferences::DisplayPreferences->new()->store_longdescription_dialog_size_percentage($form->{longdescription_dialog_size_percentage}) + } + $main::lxdebug->leave_sub(); return 1; @@ -854,7 +614,7 @@ sub get_defaults { my $myconfig = \%main::myconfig; my $form = $main::form; - my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig); + my $dbh = $params{dbh} || SL::DB->client->dbh; my $defaults = selectfirst_hashref_query($form, $dbh, qq|SELECT * FROM defaults|) || {}; @@ -870,7 +630,7 @@ sub closedto { my ($self, $myconfig, $form) = @_; - my $dbh = $form->dbconnect($myconfig); + my $dbh = SL::DB->client->dbh; my $query = qq|SELECT closedto, max_future_booking_interval, revtrans FROM defaults|; my $sth = $dbh->prepare($query); @@ -880,8 +640,6 @@ sub closedto { $sth->finish; - $dbh->disconnect; - $main::lxdebug->leave_sub(); } @@ -890,23 +648,24 @@ sub closebooks { my ($self, $myconfig, $form) = @_; - my $dbh = $form->dbconnect($myconfig); + SL::DB->client->with_transaction(sub { + my $dbh = SL::DB->client->dbh; - my ($query, @values); + my ($query, @values); - # is currently NEVER trueish (no more hidden revtrans in $form) - # if ($form->{revtrans}) { - # $query = qq|UPDATE defaults SET closedto = NULL, revtrans = '1'|; - # -> therefore you can only set this to false (which is already the default) - # and this flag is currently only checked in gl.pl. TOOD Can probably be removed + # is currently NEVER trueish (no more hidden revtrans in $form) + # if ($form->{revtrans}) { + # $query = qq|UPDATE defaults SET closedto = NULL, revtrans = '1'|; + # -> therefore you can only set this to false (which is already the default) + # and this flag is currently only checked in gl.pl. TOOD Can probably be removed - $query = qq|UPDATE defaults SET closedto = ?, max_future_booking_interval = ?, revtrans = '0'|; - @values = (conv_date($form->{closedto}), conv_i($form->{max_future_booking_interval})); + $query = qq|UPDATE defaults SET closedto = ?, max_future_booking_interval = ?, revtrans = '0'|; + @values = (conv_date($form->{closedto}), conv_i($form->{max_future_booking_interval})); - # set close in defaults - do_query($form, $dbh, $query, @values); - - $dbh->disconnect; + # set close in defaults + do_query($form, $dbh, $query, @values); + 1; + }) or do { die SL::DB->client->error }; $main::lxdebug->leave_sub(); } @@ -932,7 +691,7 @@ sub retrieve_units { my ($self, $myconfig, $form, $prefix) = @_; $prefix ||= ''; - my $dbh = $form->get_standard_dbh; + my $dbh = SL::DB->client->dbh; my $query = "SELECT *, base_unit AS original_base_unit FROM units"; @@ -1021,7 +780,7 @@ sub units_in_use { my ($self, $myconfig, $form, $units) = @_; - my $dbh = $form->dbconnect($myconfig); + my $dbh = SL::DB->client->dbh; map({ $_->{"in_use"} = 0; } values(%{$units})); @@ -1058,8 +817,6 @@ sub units_in_use { } } - $dbh->disconnect(); - $main::lxdebug->leave_sub(); } @@ -1190,37 +947,45 @@ sub add_unit { my ($self, $myconfig, $form, $name, $base_unit, $factor, $languages) = @_; - my $dbh = $form->dbconnect_noauto($myconfig); + SL::DB->client->with_transaction(sub { + my $dbh = SL::DB->client->dbh; - my $query = qq|SELECT COALESCE(MAX(sortkey), 0) + 1 FROM units|; - my ($sortkey) = selectrow_query($form, $dbh, $query); + 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); + $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) . ")"); + 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(); } - $sth->finish(); - } - - $dbh->commit(); - $dbh->disconnect(); + 1; + }) or do { die SL::DB->client->error }; $main::lxdebug->leave_sub(); } sub save_units { + my ($self, $myconfig, $form, $units, $delete_units) = @_; $main::lxdebug->enter_sub(); + my $rc = SL::DB->client->with_transaction(\&_save_units, $self, $myconfig, $form, $units, $delete_units); + + $::lxdebug->leave_sub; + return $rc; +} + +sub _save_units { my ($self, $myconfig, $form, $units, $delete_units) = @_; - my $dbh = $form->dbconnect_noauto($myconfig); + my $dbh = SL::DB->client->dbh; my ($base_unit, $unit, $sth, $query); @@ -1267,10 +1032,8 @@ sub save_units { $sth->finish(); $sth_lang->finish(); - $dbh->commit(); - $dbh->disconnect(); - $main::lxdebug->leave_sub(); + return 1; } sub taxes { @@ -1278,21 +1041,23 @@ sub taxes { my ($self, $myconfig, $form) = @_; - # connect to database - my $dbh = $form->dbconnect($myconfig); + my $dbh = SL::DB->client->dbh; my $query = qq|SELECT t.id, t.taxkey, t.taxdescription, round(t.rate * 100, 2) AS rate, - (SELECT accno FROM chart WHERE id = chart_id) AS taxnumber, - (SELECT description FROM chart WHERE id = chart_id) AS account_description, - (SELECT accno FROM chart WHERE id = skonto_sales_chart_id) AS skonto_chart_accno, - (SELECT description FROM chart WHERE id = skonto_sales_chart_id) AS skonto_chart_description, - (SELECT accno FROM chart WHERE id = skonto_purchase_chart_id) AS skonto_chart_purchase_accno, - (SELECT description FROM chart WHERE id = skonto_purchase_chart_id) AS skonto_chart_purchase_description + tc.accno AS taxnumber, + tc.description AS account_description, + ssc.accno AS skonto_chart_accno, + ssc.description AS skonto_chart_description, + spc.accno AS skonto_chart_purchase_accno, + spc.description AS skonto_chart_purchase_description FROM tax t + LEFT JOIN chart tc ON (tc.id = t.chart_id) + LEFT JOIN chart ssc ON (ssc.id = t.skonto_sales_chart_id) + LEFT JOIN chart spc ON (spc.id = t.skonto_purchase_chart_id) ORDER BY taxkey, rate|; my $sth = $dbh->prepare($query); @@ -1304,7 +1069,6 @@ sub taxes { } $sth->finish; - $dbh->disconnect; $main::lxdebug->leave_sub(); } @@ -1314,7 +1078,7 @@ sub get_tax_accounts { my ($self, $myconfig, $form) = @_; - my $dbh = $form->dbconnect($myconfig); + my $dbh = SL::DB->client->dbh; # get Accounts from chart my $query = qq{ SELECT @@ -1346,8 +1110,6 @@ sub get_tax_accounts { $sth->finish; - $dbh->disconnect; - $main::lxdebug->leave_sub(); } @@ -1356,8 +1118,7 @@ sub get_tax { my ($self, $myconfig, $form) = @_; - # connect to database - my $dbh = $form->dbconnect($myconfig); + my $dbh = SL::DB->client->dbh; my $query = qq|SELECT taxkey, @@ -1408,19 +1169,24 @@ sub get_tax { $sth->finish; } - $dbh->disconnect; - $main::lxdebug->leave_sub(); } sub save_tax { + my ($self, $myconfig, $form) = @_; $main::lxdebug->enter_sub(); + my $rc = SL::DB->client->with_transaction(\&_save_tax, $self, $myconfig, $form); + + $::lxdebug->leave_sub; + return $rc; +} + +sub _save_tax { my ($self, $myconfig, $form) = @_; my $query; - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); + my $dbh = SL::DB->client->dbh; $form->{rate} = $form->{rate} / 100; @@ -1432,14 +1198,13 @@ sub save_tax { $chart_categories .= 'E' if $form->{expense}; $chart_categories .= 'C' if $form->{costs}; - my @values = ($form->{taxkey}, $form->{taxdescription}, $form->{rate}, conv_i($form->{chart_id}), conv_i($form->{chart_id}), conv_i($form->{skonto_sales_chart_id}), conv_i($form->{skonto_purchase_chart_id}), $chart_categories); + my @values = ($form->{taxkey}, $form->{taxdescription}, $form->{rate}, conv_i($form->{chart_id}), conv_i($form->{skonto_sales_chart_id}), conv_i($form->{skonto_purchase_chart_id}), $chart_categories); if ($form->{id} ne "") { $query = qq|UPDATE tax SET taxkey = ?, taxdescription = ?, rate = ?, chart_id = ?, - taxnumber = (SELECT accno FROM chart WHERE id = ? ), skonto_sales_chart_id = ?, skonto_purchase_chart_id = ?, chart_categories = ? @@ -1453,13 +1218,12 @@ sub save_tax { taxdescription, rate, chart_id, - taxnumber, skonto_sales_chart_id, skonto_purchase_chart_id, chart_categories, id ) - VALUES (?, ?, ?, ?, (SELECT accno FROM chart WHERE id = ?), ?, ?, ?, ?)|; + VALUES (?, ?, ?, ?, ?, ?, ?, ?)|; } push(@values, $form->{id}); do_query($form, $dbh, $query, @values); @@ -1471,10 +1235,6 @@ sub save_tax { 'language_id' => $language_id, 'translation' => $form->{translations}->{$language_id}); } - - $dbh->commit(); - - $main::lxdebug->leave_sub(); } sub delete_tax { @@ -1483,86 +1243,11 @@ sub delete_tax { my ($self, $myconfig, $form) = @_; my $query; - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); - - $query = qq|DELETE FROM tax - WHERE id = ?|; - do_query($form, $dbh, $query, $form->{id}); - - $dbh->commit(); - - $main::lxdebug->leave_sub(); -} - -sub save_price_factor { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); - - my $query; - my @values = ($form->{description}, conv_i($form->{factor})); - - if ($form->{id}) { - $query = qq|UPDATE price_factors SET description = ?, factor = ? WHERE id = ?|; - push @values, conv_i($form->{id}); - - } else { - $query = qq|INSERT INTO price_factors (description, factor, sortkey) VALUES (?, ?, (SELECT COALESCE(MAX(sortkey), 0) + 1 FROM price_factors))|; - } - - do_query($form, $dbh, $query, @values); - - $dbh->commit(); - - $main::lxdebug->leave_sub(); -} - -sub get_all_price_factors { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); - - $form->{PRICE_FACTORS} = selectall_hashref_query($form, $dbh, qq|SELECT * FROM price_factors ORDER BY sortkey|); - - $main::lxdebug->leave_sub(); -} - -sub get_price_factor { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); - - my $query = qq|SELECT description, factor, - ((SELECT COUNT(*) FROM parts WHERE price_factor_id = ?) + - (SELECT COUNT(*) FROM invoice WHERE price_factor_id = ?) + - (SELECT COUNT(*) FROM orderitems WHERE price_factor_id = ?)) = 0 AS orphaned - FROM price_factors WHERE id = ?|; - - ($form->{description}, $form->{factor}, $form->{orphaned}) = selectrow_query($form, $dbh, $query, (conv_i($form->{id})) x 4); - - $main::lxdebug->leave_sub(); -} - -sub delete_price_factor { - $main::lxdebug->enter_sub(); - - my ($self, $myconfig, $form) = @_; - - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); - - do_query($form, $dbh, qq|DELETE FROM price_factors WHERE id = ?|, conv_i($form->{id})); - $dbh->commit(); + SL::DB->client->with_transaction(sub { + $query = qq|DELETE FROM tax WHERE id = ?|; + do_query($form, SL::DB->client->dbh, $query, $form->{id}); + 1; + }) or do { die SL::DB->client->error }; $main::lxdebug->leave_sub(); } @@ -1572,35 +1257,37 @@ sub save_warehouse { my ($self, $myconfig, $form) = @_; - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); + croak('Need at least one new bin') unless $form->{number_of_new_bins} > 0; - my ($query, @values, $sth); + SL::DB->client->with_transaction(sub { + my $dbh = SL::DB->client->dbh; - if (!$form->{id}) { - $query = qq|SELECT nextval('id')|; - ($form->{id}) = selectrow_query($form, $dbh, $query); + my ($query, @values, $sth); - $query = qq|INSERT INTO warehouse (id, sortkey) VALUES (?, (SELECT COALESCE(MAX(sortkey), 0) + 1 FROM warehouse))|; - do_query($form, $dbh, $query, $form->{id}); - } + if (!$form->{id}) { + $query = qq|SELECT nextval('id')|; + ($form->{id}) = selectrow_query($form, $dbh, $query); - do_query($form, $dbh, qq|UPDATE warehouse SET description = ?, invalid = ? WHERE id = ?|, - $form->{description}, $form->{invalid} ? 't' : 'f', conv_i($form->{id})); + $query = qq|INSERT INTO warehouse (id, sortkey) VALUES (?, (SELECT COALESCE(MAX(sortkey), 0) + 1 FROM warehouse))|; + do_query($form, $dbh, $query, $form->{id}); + } - if (0 < $form->{number_of_new_bins}) { - my ($num_existing_bins) = selectfirst_array_query($form, $dbh, qq|SELECT COUNT(*) FROM bin WHERE warehouse_id = ?|, $form->{id}); - $query = qq|INSERT INTO bin (warehouse_id, description) VALUES (?, ?)|; - $sth = prepare_query($form, $dbh, $query); + do_query($form, $dbh, qq|UPDATE warehouse SET description = ?, invalid = ? WHERE id = ?|, + $form->{description}, $form->{invalid} ? 't' : 'f', conv_i($form->{id})); - foreach my $i (1..$form->{number_of_new_bins}) { - do_statement($form, $sth, $query, conv_i($form->{id}), "$form->{prefix}" . ($i + $num_existing_bins)); - } + if (0 < $form->{number_of_new_bins}) { + my ($num_existing_bins) = selectfirst_array_query($form, $dbh, qq|SELECT COUNT(*) FROM bin WHERE warehouse_id = ?|, $form->{id}); + $query = qq|INSERT INTO bin (warehouse_id, description) VALUES (?, ?)|; + $sth = prepare_query($form, $dbh, $query); - $sth->finish(); - } + foreach my $i (1..$form->{number_of_new_bins}) { + do_statement($form, $sth, $query, conv_i($form->{id}), "$form->{prefix}" . ($i + $num_existing_bins)); + } - $dbh->commit(); + $sth->finish(); + } + 1; + }) or do { die SL::DB->client->error }; $main::lxdebug->leave_sub(); } @@ -1610,34 +1297,30 @@ sub save_bins { my ($self, $myconfig, $form) = @_; - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); + SL::DB->client->with_transaction(sub { + my $dbh = SL::DB->client->dbh; - my ($query, @values, $commit_necessary, $sth); - - @values = map { $form->{"id_${_}"} } grep { $form->{"delete_${_}"} } (1..$form->{rowcount}); - - if (@values) { - $query = qq|DELETE FROM bin WHERE id IN (| . join(', ', ('?') x scalar(@values)) . qq|)|; - do_query($form, $dbh, $query, @values); - - $commit_necessary = 1; - } + my ($query, @values, $sth); - $query = qq|UPDATE bin SET description = ? WHERE id = ?|; - $sth = prepare_query($form, $dbh, $query); + @values = map { $form->{"id_${_}"} } grep { $form->{"delete_${_}"} } (1..$form->{rowcount}); - foreach my $row (1..$form->{rowcount}) { - next if ($form->{"delete_${row}"}); + if (@values) { + $query = qq|DELETE FROM bin WHERE id IN (| . join(', ', ('?') x scalar(@values)) . qq|)|; + do_query($form, $dbh, $query, @values); + } - do_statement($form, $sth, $query, $form->{"description_${row}"}, conv_i($form->{"id_${row}"})); + $query = qq|UPDATE bin SET description = ? WHERE id = ?|; + $sth = prepare_query($form, $dbh, $query); - $commit_necessary = 1; - } + foreach my $row (1..$form->{rowcount}) { + next if ($form->{"delete_${row}"}); - $sth->finish(); + do_statement($form, $sth, $query, $form->{"description_${row}"}, conv_i($form->{"id_${row}"})); + } - $dbh->commit() if ($commit_necessary); + $sth->finish(); + 1; + }) or do { die SL::DB->client->error }; $main::lxdebug->leave_sub(); } @@ -1647,26 +1330,26 @@ sub delete_warehouse { my ($self, $myconfig, $form) = @_; - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); + my $rc = SL::DB->client->with_transaction(sub { + my $dbh = SL::DB->client->dbh; - my $id = conv_i($form->{id}); - my $query = qq|SELECT i.bin_id FROM inventory i WHERE i.bin_id IN (SELECT b.id FROM bin b WHERE b.warehouse_id = ?) LIMIT 1|; - my ($count) = selectrow_query($form, $dbh, $query, $id); + my $id = conv_i($form->{id}); + my $query = qq|SELECT i.bin_id FROM inventory i WHERE i.bin_id IN (SELECT b.id FROM bin b WHERE b.warehouse_id = ?) LIMIT 1|; + my ($count) = selectrow_query($form, $dbh, $query, $id); - if ($count) { - $main::lxdebug->leave_sub(); - return 0; - } + if ($count) { + return 0; + } - do_query($form, $dbh, qq|DELETE FROM bin WHERE warehouse_id = ?|, conv_i($form->{id})); - do_query($form, $dbh, qq|DELETE FROM warehouse WHERE id = ?|, conv_i($form->{id})); + do_query($form, $dbh, qq|DELETE FROM bin WHERE warehouse_id = ?|, conv_i($form->{id})); + do_query($form, $dbh, qq|DELETE FROM warehouse WHERE id = ?|, conv_i($form->{id})); - $dbh->commit(); + return 1; + }); $main::lxdebug->leave_sub(); - return 1; + return $rc; } sub get_all_warehouses { @@ -1674,8 +1357,7 @@ sub get_all_warehouses { my ($self, $myconfig, $form) = @_; - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); + my $dbh = SL::DB->client->dbh; my $query = qq|SELECT w.id, w.description, w.invalid, (SELECT COUNT(b.description) FROM bin b WHERE b.warehouse_id = w.id) AS number_of_bins @@ -1692,8 +1374,7 @@ sub get_warehouse { my ($self, $myconfig, $form) = @_; - # connect to database - my $dbh = $form->get_standard_dbh($myconfig); + my $dbh = SL::DB->client->dbh; my $id = conv_i($form->{id}); my $query = qq|SELECT w.description, w.invalid @@ -1705,12 +1386,14 @@ sub get_warehouse { map { $form->{$_} = $ref->{$_} } keys %{ $ref }; $query = <{BINS} = selectall_hashref_query($form, $dbh, $query, conv_i($form->{id})); @@ -1718,4 +1401,22 @@ SQL $main::lxdebug->leave_sub(); } +sub get_eur_categories { + my ($self, $myconfig, $form) = @_; + + my $dbh = SL::DB->client->dbh; + my %eur_categories = selectall_as_map($form, $dbh, "select * from eur_categories order by id", 'id', 'description'); + + return \%eur_categories; +} + +sub get_bwa_categories { + my ($self, $myconfig, $form) = @_; + + my $dbh = SL::DB->client->dbh; + my %bwa_categories = selectall_as_map($form, $dbh, "select * from bwa_categories order by id", 'id', 'description'); + + return \%bwa_categories; +} + 1; diff --git a/SL/AP.pm b/SL/AP.pm index f551b34ae..d399b7c1b 100644 --- a/SL/AP.pm +++ b/SL/AP.pm @@ -25,7 +25,8 @@ # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1335, USA. #====================================================================== # # Accounts Payables database backend routines @@ -38,18 +39,32 @@ use SL::DATEV qw(:CONSTANTS); use SL::DBUtils; use SL::IO; use SL::MoreCommon; +use SL::DB::ApGl; use SL::DB::Default; +use SL::DB::Draft; +use SL::DB::Order; +use SL::DB::PurchaseInvoice; +use SL::Util qw(trim); +use SL::DB; use Data::Dumper; - +use List::Util qw(sum0); use strict; sub post_transaction { + my ($self, $myconfig, $form, $provided_dbh, %params) = @_; $main::lxdebug->enter_sub(); - my ($self, $myconfig, $form, $provided_dbh, $payments_only) = @_; - my $rc = 0; # return code auf false setzen - # connect to database - my $dbh = $provided_dbh ? $provided_dbh : $form->dbconnect_noauto($myconfig); + my $rc = SL::DB->client->with_transaction(\&_post_transaction, $self, $myconfig, $form, $provided_dbh, %params); + + $::lxdebug->leave_sub; + return $rc; +} + +sub _post_transaction { + my ($self, $myconfig, $form, $provided_dbh, %params) = @_; + + my $payments_only = $params{payments_only}; + my $dbh = $provided_dbh || SL::DB->client->dbh; my ($null, $taxrate, $amount); my $exchangerate = 0; @@ -57,8 +72,6 @@ sub post_transaction { $form->{defaultcurrency} = $form->get_default_currency($myconfig); $form->{taxincluded} = 0 unless $form->{taxincluded}; - ($null, $form->{department_id}) = split(/--/, $form->{department}); - if ($form->{currency} eq $form->{defaultcurrency}) { $form->{exchangerate} = 1; } else { @@ -66,13 +79,8 @@ sub post_transaction { $form->{exchangerate} = $exchangerate || $form->parse_amount($myconfig, $form->{exchangerate}); } - for my $i (1 .. $form->{rowcount}) { - $form->{AP_amounts}{"amount_$i"} = - (split(/--/, $form->{"AP_amount_$i"}))[0]; - } - - ($form->{AP_amounts}{payables}) = split(/--/, $form->{APselected}); - ($form->{AP_payables}) = split(/--/, $form->{APselected}); + # get the charts selected + $form->{AP_amounts}{"amount_$_"} = $form->{"AP_amount_chart_id_$_"} for (1 .. $form->{rowcount}); # calculate the totals while calculating and reformatting the $amount_$i and $tax_$i ($form->{netamount},$form->{total_tax},$form->{invtotal}) = $form->calculate_arap('buy',$form->{taxincluded}, $form->{exchangerate}); @@ -132,22 +140,50 @@ sub post_transaction { $query = qq|UPDATE ap SET invnumber = ?, transdate = ?, ordnumber = ?, vendor_id = ?, taxincluded = ?, - amount = ?, duedate = ?, paid = ?, netamount = ?, + amount = ?, duedate = ?, deliverydate = ?, tax_point = ?, paid = ?, netamount = ?, currency_id = (SELECT id FROM currencies WHERE name = ?), notes = ?, department_id = ?, storno = ?, storno_id = ?, - globalproject_id = ?, direct_debit = ? + globalproject_id = ?, direct_debit = ?, payment_id = ?, transaction_description = ? WHERE id = ?|; @values = ($form->{invnumber}, conv_date($form->{transdate}), $form->{ordnumber}, conv_i($form->{vendor_id}), $form->{taxincluded} ? 't' : 'f', $form->{invtotal}, - conv_date($form->{duedate}), $form->{invpaid}, - $form->{netamount}, + conv_date($form->{duedate}), conv_date($form->{deliverydate}), conv_date($form->{tax_point}), + $form->{invpaid}, $form->{netamount}, $form->{currency}, $form->{notes}, conv_i($form->{department_id}), $form->{storno}, $form->{storno_id}, conv_i($form->{globalproject_id}), $form->{direct_debit} ? 't' : 'f', + conv_i($form->{payment_id}), $form->{transaction_description}, $form->{id}); do_query($form, $dbh, $query, @values); + $form->new_lastmtime('ap'); + + # Link this record to the record it was created from. + my $convert_from_oe_id = delete $form->{convert_from_oe_id}; + if (!$form->{postasnew} && $convert_from_oe_id) { + RecordLinks->create_links('dbh' => $dbh, + 'mode' => 'ids', + 'from_table' => 'oe', + 'from_ids' => $convert_from_oe_id, + 'to_table' => 'ap', + 'to_id' => $form->{id}, + ); + + # Close the record it was created from if the amount of + # all APs create from this record equals the records amount. + my @links = RecordLinks->get_links('dbh' => $dbh, + 'from_table' => 'oe', + 'from_id' => $convert_from_oe_id, + 'to_table' => 'ap', + ); + + my $amount_sum = sum0 map { SL::DB::PurchaseInvoice->new(id => $_->{to_id})->load->amount } @links; + my $order = SL::DB::Order->new(id => $convert_from_oe_id)->load; + + $order->update_attributes(closed => 1) if ($amount_sum - $order->amount) == 0; + } + # add individual transactions for my $i (1 .. $form->{rowcount}) { if ($form->{"amount_$i"} != 0) { @@ -158,13 +194,11 @@ sub post_transaction { $query = qq|INSERT INTO acc_trans | . qq| (trans_id, chart_id, amount, transdate, project_id, taxkey, tax_id, chart_link)| . - qq|VALUES (?, (SELECT c.id FROM chart c WHERE c.accno = ?), | . - qq| ?, ?, ?, ?, ?,| . - qq| (SELECT c.link FROM chart c WHERE c.accno = ?))|; - @values = ($form->{id}, $form->{AP_amounts}{"amount_$i"}, + qq|VALUES (?, ?, ?, ?, ?, ?, ?, (SELECT c.link FROM chart c WHERE c.id = ?))|; + @values = ($form->{id}, $form->{"AP_amount_chart_id_$i"}, $form->{"amount_$i"}, conv_date($form->{transdate}), $project_id, $form->{"taxkey_$i"}, conv_i($form->{"tax_id_$i"}), - $form->{AP_amounts}{"amount_$i"}); + $form->{"AP_amount_chart_id_$i"}); do_query($form, $dbh, $query, @values); if ($form->{"tax_$i"} != 0) { @@ -188,19 +222,17 @@ sub post_transaction { # add payables $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, tax_id, chart_link) | . - qq|VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, | . - qq| (SELECT taxkey_id FROM chart WHERE accno = ?),| . + qq|VALUES (?, ?, ?, ?, | . + qq| (SELECT taxkey_id FROM chart WHERE id = ?),| . qq| (SELECT tax_id| . qq| FROM taxkeys| . - qq| WHERE chart_id= (SELECT id | . - qq| FROM chart| . - qq| WHERE accno = ?)| . + qq| WHERE chart_id = ?| . qq| AND startdate <= ?| . qq| ORDER BY startdate DESC LIMIT 1),| . - qq| (SELECT c.link FROM chart c WHERE c.accno = ?))|; - @values = ($form->{id}, $form->{AP_amounts}{payables}, $form->{payables}, - conv_date($form->{transdate}), $form->{AP_amounts}{payables}, $form->{AP_amounts}{payables}, conv_date($form->{transdate}), - $form->{AP_amounts}{payables}); + qq| (SELECT c.link FROM chart c WHERE c.id = ?))|; + @values = ($form->{id}, $form->{AP_chart_id}, $form->{payables}, + conv_date($form->{transdate}), $form->{AP_chart_id}, $form->{AP_chart_id}, conv_date($form->{transdate}), + $form->{AP_chart_id}); do_query($form, $dbh, $query, @values); } @@ -209,6 +241,8 @@ sub post_transaction { $form->{payables} = $form->{invpaid}; } + my %already_cleared = %{ $params{already_cleared} // {} }; + # add paid transactions for my $i (1 .. $form->{paidaccounts}) { @@ -242,23 +276,29 @@ sub post_transaction { $amount = $form->round_amount($form->{"paid_$i"} * $form->{exchangerate} * -1, 2); + + my $new_cleared = !$form->{"acc_trans_id_$i"} ? 'f' + : !$already_cleared{$form->{"acc_trans_id_$i"}} ? 'f' + : $already_cleared{$form->{"acc_trans_id_$i"}}->{amount} != $amount * -1 ? 'f' + : $already_cleared{$form->{"acc_trans_id_$i"}}->{accno} != $form->{"AP_paid_account_$i"} ? 'f' + : $already_cleared{$form->{"acc_trans_id_$i"}}->{cleared} ? 't' + : 'f'; + if ($form->{payables}) { $query = - qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, project_id, taxkey, tax_id, chart_link) | . - qq|VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, ?, | . - qq| (SELECT taxkey_id FROM chart WHERE accno = ?),| . + qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, project_id, cleared, taxkey, tax_id, chart_link) | . + qq|VALUES (?, ?, ?, ?, ?, ?, | . + qq| (SELECT taxkey_id FROM chart WHERE id = ?),| . qq| (SELECT tax_id| . qq| FROM taxkeys| . - qq| WHERE chart_id= (SELECT id | . - qq| FROM chart| . - qq| WHERE accno = ?)| . + qq| WHERE chart_id = ?| . qq| AND startdate <= ?| . qq| ORDER BY startdate DESC LIMIT 1),| . - qq| (SELECT c.link FROM chart c WHERE c.accno = ?))|; - @values = ($form->{id}, $form->{AP_payables}, $amount, - conv_date($form->{"datepaid_$i"}), $project_id, - $form->{AP_payables}, $form->{AP_payables}, conv_date($form->{"datepaid_$i"}), - $form->{AP_payables}); + qq| (SELECT c.link FROM chart c WHERE c.id = ?))|; + @values = ($form->{id}, $form->{AP_chart_id}, $amount, + conv_date($form->{"datepaid_$i"}), $project_id, $new_cleared, + $form->{AP_chart_id}, $form->{AP_chart_id}, conv_date($form->{"datepaid_$i"}), + $form->{AP_chart_id}); do_query($form, $dbh, $query, @values); } $form->{payables} = $amount; @@ -266,8 +306,8 @@ sub post_transaction { # add payment my $gldate = (conv_date($form->{"gldate_$i"}))? conv_date($form->{"gldate_$i"}) : conv_date($form->current_date($myconfig)); $query = - qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, gldate, source, memo, project_id, taxkey, tax_id, chart_link) | . - qq|VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, ?, ?, ?, ?, | . + qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, gldate, source, memo, project_id, cleared, taxkey, tax_id, chart_link) | . + qq|VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, ?, ?, ?, ?, ?, | . qq| (SELECT taxkey_id FROM chart WHERE accno = ?), | . qq| (SELECT tax_id| . qq| FROM taxkeys| . @@ -279,7 +319,7 @@ sub post_transaction { qq| (SELECT c.link FROM chart c WHERE c.accno = ?))|; @values = ($form->{id}, $form->{"AP_paid_account_$i"}, $form->{"paid_$i"}, conv_date($form->{"datepaid_$i"}), $gldate, $form->{"source_$i"}, - $form->{"memo_$i"}, $project_id, $form->{"AP_paid_account_$i"}, + $form->{"memo_$i"}, $project_id, $new_cleared, $form->{"AP_paid_account_$i"}, $form->{"AP_paid_account_$i"}, conv_date($form->{"datepaid_$i"}), $form->{"AP_paid_account_$i"}); do_query($form, $dbh, $query, @values); @@ -316,6 +356,15 @@ sub post_transaction { $form->{"exchangerate_$i"}), 2); if ($amount != 0) { + # fetch fxgain and fxloss chart info from defaults if charts aren't already filled in form + if ( !$form->{fxgain_accno} && $::instance_conf->get_fxgain_accno_id ) { + $form->{fxgain_accno} = SL::DB::Manager::Chart->find_by(id => $::instance_conf->get_fxgain_accno_id)->accno; + }; + if ( !$form->{fxloss_accno} && $::instance_conf->get_fxloss_accno_id ) { + $form->{fxloss_accno} = SL::DB::Manager::Chart->find_by(id => $::instance_conf->get_fxloss_accno_id)->accno; + }; + die "fxloss_accno missing" if $amount < 0 and not $form->{fxloss_accno}; + die "fxgain_accno missing" if $amount > 0 and not $form->{fxgain_accno}; $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, fx_transaction, cleared, project_id, taxkey, tax_id, chart_link) | . qq|VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, 't', 'f', ?, | . @@ -349,40 +398,94 @@ sub post_transaction { if ($payments_only) { $query = qq|UPDATE ap SET paid = ?, datepaid = ? WHERE id = ?|; do_query($form, $dbh, $query, $form->{invpaid}, $form->{invpaid} ? conv_date($form->{datepaid}) : undef, conv_i($form->{id})); + $form->new_lastmtime('ap'); } IO->set_datepaid(table => 'ap', id => $form->{id}, dbh => $dbh); + if ($form->{draft_id}) { + SL::DB::Manager::Draft->delete_all(where => [ id => delete($form->{draft_id}) ]); + } + + # hook for taxkey 94 + $self->_reverse_charge($myconfig, $form); # safety check datev export if ($::instance_conf->get_datev_check_on_ap_transaction) { - my $transdate = $::form->{transdate} ? DateTime->from_lxoffice($::form->{transdate}) : undef; - $transdate ||= DateTime->today; - my $datev = SL::DATEV->new( - exporttype => DATEV_ET_BUCHUNGEN, - format => DATEV_FORMAT_KNE, dbh => $dbh, trans_id => $form->{id}, ); - - $datev->export; + $datev->generate_datev_data; if ($datev->errors) { - $dbh->rollback; die join "\n", $::locale->text('DATEV check returned errors:'), $datev->errors; } } - if (!$provided_dbh) { - $dbh->commit(); - $dbh->disconnect(); - } - - $rc = 1; # Den return-code auf true setzen, aber nur falls beim commit alles i.O. ist + return 1; +} - $main::lxdebug->leave_sub(); +sub _reverse_charge { + my ($self, $myconfig, $form) = @_; - return $rc; + # delete previous bookings, if they exists (repost) + my $ap_gl = SL::DB::Manager::ApGl->get_first(where => [ ap_id => $form->{id} ]); + my $gl_id = ref $ap_gl eq 'SL::DB::ApGl' ? $ap_gl->gl_id : undef; + + SL::DB::Manager::GLTransaction->delete_all(where => [ id => $gl_id ]) if $gl_id; + SL::DB::Manager::ApGl-> delete_all(where => [ ap_id => $form->{id} ]) if $gl_id; + SL::DB::Manager::RecordLink-> delete_all(where => [ from_table => 'ap', to_table => 'gl', from_id => $form->{id} ]); + + my ($i, $current_transaction); + + for $i (1 .. $form->{rowcount}) { + + my $tax = SL::DB::Manager::Tax->get_first( where => [id => $form->{"tax_id_$i"}, '!reverse_charge_chart_id' => undef ]); + next unless ref $tax eq 'SL::DB::Tax'; + + # gl booking + my ($credit, $debit); + $credit = SL::DB::Manager::Chart->find_by(id => $tax->chart_id); + $debit = SL::DB::Manager::Chart->find_by(id => $tax->reverse_charge_chart_id); + + croak("No such Chart ID" . $tax->chart_id) unless ref $credit eq 'SL::DB::Chart'; + croak("No such Chart ID" . $tax->reverse_chart_id) unless ref $debit eq 'SL::DB::Chart'; + + my ($tmpnetamount, $tmptaxamount) = $form->calculate_tax($form->{"amount_$i"}, $tax->rate, $form->{taxincluded}, 2); + $current_transaction = SL::DB::GLTransaction->new( + employee_id => $form->{employee_id}, + transdate => $form->{transdate}, + description => $form->{notes} || $form->{invnumber}, + reference => $form->{invnumber}, + department_id => $form->{department_id} ? $form->{department_id} : undef, + imported => 0, # not imported + taxincluded => 0, + )->add_chart_booking( + chart => $tmptaxamount > 0 ? $debit : $credit, + debit => abs($tmptaxamount), + source => "Reverse Charge for " . $form->{invnumber}, + tax_id => 0, + )->add_chart_booking( + chart => $tmptaxamount > 0 ? $credit : $debit, + credit => abs($tmptaxamount), + source => "Reverse Charge for " . $form->{invnumber}, + tax_id => 0, + )->post; + # add a stable link from ap to gl + my %props_gl = ( + ap_id => $form->{id}, + gl_id => $current_transaction->id, + ); + SL::DB::ApGl->new(%props_gl)->save; + # Record a record link from ap to gl + my %props_rl = ( + from_table => 'ap', + from_id => $form->{id}, + to_table => 'gl', + to_id => $current_transaction->id, + ); + SL::DB::RecordLink->new(%props_rl)->save; + } } sub delete_transaction { @@ -390,19 +493,26 @@ sub delete_transaction { my ($self, $myconfig, $form) = @_; - # connect to database - my $dbh = $form->dbconnect_noauto($myconfig); + SL::DB->client->with_transaction(sub { - # acc_trans entries are deleted by database triggers. - my $query = qq|DELETE FROM ap WHERE id = ?|; - do_query($form, $dbh, $query, $form->{id}); + # if tax 94 reverse charge, clear all GL bookings and links + my $ap_gl = SL::DB::Manager::ApGl->get_first(where => [ ap_id => $form->{id} ]); + my $gl_id = ref $ap_gl eq 'SL::DB::ApGl' ? $ap_gl->gl_id : undef; - my $rc = $dbh->commit; - $dbh->disconnect; + SL::DB::Manager::GLTransaction->delete_all(where => [ id => $gl_id ]) if $gl_id; + SL::DB::Manager::ApGl-> delete_all(where => [ ap_id => $form->{id} ]) if $gl_id; + SL::DB::Manager::RecordLink-> delete_all(where => [ from_table => 'ap', to_table => 'gl', from_id => $form->{id} ]); + # done gl delete for tax 94 case + + # begin ap delete + my $query = qq|DELETE FROM ap WHERE id = ?|; + do_query($form, SL::DB->client->dbh, $query, $form->{id}); + 1; + }) or do { die SL::DB->client->error }; $main::lxdebug->leave_sub(); - return $rc; + return 1; } sub ap_transactions { @@ -417,68 +527,112 @@ sub ap_transactions { qq|SELECT a.id, a.invnumber, a.transdate, a.duedate, a.amount, a.paid, | . qq| a.ordnumber, v.name, a.invoice, a.netamount, a.datepaid, a.notes, | . qq| a.globalproject_id, a.storno, a.storno_id, a.direct_debit, | . + qq| a.transaction_description, a.itime::DATE AS insertdate, | . qq| pr.projectnumber AS globalprojectnumber, | . qq| e.name AS employee, | . qq| v.vendornumber, v.country, v.ustid, | . qq| tz.description AS taxzone, | . qq| pt.description AS payment_terms, | . + qq| department.description AS department, | . qq{ ( SELECT ch.accno || ' -- ' || ch.description FROM acc_trans at LEFT JOIN chart ch ON ch.id = at.chart_id WHERE ch.link ~ 'AP[[:>:]]' AND at.trans_id = a.id LIMIT 1 - ) AS charts } . + ) AS charts, } . + qq{ ( SELECT ch.accno || ' -- ' || ch.description + FROM acc_trans at + LEFT JOIN chart ch ON ch.id = at.chart_id + WHERE ch.link ~ 'AP_amount' + AND at.trans_id = a.id + LIMIT 1 + ) AS debit_chart } . qq|FROM ap a | . qq|JOIN vendor v ON (a.vendor_id = v.id) | . qq|LEFT JOIN contacts cp ON (a.cp_id = cp.cp_id) | . qq|LEFT JOIN employee e ON (a.employee_id = e.id) | . qq|LEFT JOIN project pr ON (a.globalproject_id = pr.id) | . qq|LEFT JOIN tax_zones tz ON (tz.id = a.taxzone_id)| . - qq|LEFT JOIN payment_terms pt ON (pt.id = a.payment_id)|; + qq|LEFT JOIN payment_terms pt ON (pt.id = a.payment_id)| . + qq|LEFT JOIN department ON (department.id = a.department_id)|; my $where = ''; - unless ( $::auth->assert('show_ap_transactions', 1) ) { - $where .= " AND NOT invoice = 'f' "; # remove ap transactions from Sales -> Reports -> Invoices - }; - my @values; - if ($form->{vendor_id}) { - $where .= " AND a.vendor_id = ?"; - push(@values, $form->{vendor_id}); - } elsif ($form->{vendor}) { + # Permissions: + # - Always return invoices & AP transactions for projects the employee has "view invoices" permissions for, no matter what the other rules say. + # - Exclude AP transactions if no permissions for them exist. + # - Limit to own invoices unless may edit all invoices or view invoices is allowed. + # - If may edit all or view invoices is allowed, allow filtering by employee. + my (@permission_where, @permission_values); + + if ($::auth->assert('vendor_invoice_edit', 1) || $::auth->assert('purchase_invoice_view', 1)) { + if (!$::auth->assert('show_ap_transactions', 1)) { + push @permission_where, "NOT invoice = 'f'"; # remove ap transactions from Purchase -> Reports -> Invoices + } + + if (!$::auth->assert('purchase_all_edit', 1) && !$::auth->assert('purchase_invoice_view', 1)) { + # only show own invoices + push @permission_where, "a.employee_id = ?"; + push @permission_values, SL::DB::Manager::Employee->current->id; + + } else { + if ($form->{employee_id}) { + push @permission_where, "a.employee_id = ?"; + push @permission_values, conv_i($form->{employee_id}); + } + } + } + + if (@permission_where || (!$::auth->assert('vendor_invoice_edit', 1) && !$::auth->assert('purchase_invoice_view', 1))) { + my $permission_where_str = @permission_where ? "OR (" . join(" AND ", map { "($_)" } @permission_where) . ")" : ""; + $where .= qq| + AND ( (a.globalproject_id IN ( + SELECT epi.project_id + FROM employee_project_invoices epi + WHERE epi.employee_id = ?)) + $permission_where_str) + |; + push @values, SL::DB::Manager::Employee->current->id, @permission_values; + } + + if ($form->{vendor}) { $where .= " AND v.name ILIKE ?"; - push(@values, $form->like($form->{vendor})); + push(@values, like($form->{vendor})); } if ($form->{"cp_name"}) { $where .= " AND (cp.cp_name ILIKE ? OR cp.cp_givenname ILIKE ?)"; - push(@values, ('%' . $form->{"cp_name"} . '%')x2); + push(@values, (like($form->{"cp_name"}))x2); } - if ($form->{department}) { - # ähnlich wie commit 0bbfb33b6aa8e38bb6c81d1684ab7d08e5b5c5af abteilung - # wird so nicht mehr als zeichenkette zusammengebaut - # hätte zu ee9f9f9aa4c3b9d5d20ab10a45c12bcaa6aa78d0 auffallen können ;-) jan - #my ($null, $department_id) = split /--/, $form->{department}; + if ($form->{department_id}) { $where .= " AND a.department_id = ?"; - push(@values, $form->{department}); + push(@values, $form->{department_id}); } if ($form->{invnumber}) { $where .= " AND a.invnumber ILIKE ?"; - push(@values, $form->like($form->{invnumber})); + push(@values, like($form->{invnumber})); } if ($form->{ordnumber}) { $where .= " AND a.ordnumber ILIKE ?"; - push(@values, $form->like($form->{ordnumber})); + push(@values, like($form->{ordnumber})); + } + if ($form->{taxzone_id}) { + $where .= " AND a.taxzone_id = ?"; + push(@values, $form->{taxzone_id}); + } + if ($form->{transaction_description}) { + $where .= " AND a.transaction_description ILIKE ?"; + push(@values, like($form->{transaction_description})); } if ($form->{notes}) { - $where .= " AND lower(a.notes) LIKE ?"; - push(@values, $form->like($form->{notes})); + $where .= " AND a.notes ILIKE ?"; + push(@values, like($form->{notes})); } if ($form->{project_id}) { $where .= - qq|AND ((a.globalproject_id = ?) OR EXISTS | . + qq| AND ((a.globalproject_id = ?) OR EXISTS | . qq| (SELECT * FROM invoice i | . qq| WHERE i.project_id = ? AND i.trans_id = a.id) | . qq| OR EXISTS | . @@ -490,11 +644,19 @@ sub ap_transactions { if ($form->{transdatefrom}) { $where .= " AND a.transdate >= ?"; - push(@values, $form->{transdatefrom}); + push(@values, trim($form->{transdatefrom})); } if ($form->{transdateto}) { $where .= " AND a.transdate <= ?"; - push(@values, $form->{transdateto}); + push(@values, trim($form->{transdateto})); + } + if ($form->{duedatefrom}) { + $where .= " AND a.duedate >= ?"; + push(@values, trim($form->{duedatefrom})); + } + if ($form->{duedateto}) { + $where .= " AND a.duedate <= ?"; + push(@values, trim($form->{duedateto})); } if ($form->{open} || $form->{closed}) { unless ($form->{open} && $form->{closed}) { @@ -503,8 +665,35 @@ sub ap_transactions { } } + if ($form->{parts_partnumber}) { + $where .= <{parts_partnumber}); + } + + if ($form->{parts_description}) { + $where .= <{parts_description}); + } + if ($where) { - substr($where, 0, 4, " WHERE "); + $where =~ s{\s*AND\s*}{ WHERE }; $query .= $where; } @@ -513,7 +702,7 @@ sub ap_transactions { my $sortdir = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC'; my $sortorder = join(', ', map { "$_ $sortdir" } @a); - if (grep({ $_ eq $form->{sort} } qw(transdate id invnumber ordnumber name netamount tax amount paid datepaid due duedate notes employee transaction_description direct_debit))) { + if (grep({ $_ eq $form->{sort} } qw(transdate id invnumber ordnumber name netamount tax amount paid datepaid due duedate notes employee transaction_description direct_debit department taxzone))) { $sortorder = $form->{sort} . " $sortdir"; } @@ -532,7 +721,7 @@ sub get_transdate { my ($self, $myconfig, $form) = @_; # connect to database - my $dbh = $form->dbconnect($myconfig); + my $dbh = SL::DB->client->dbh; my $query = "SELECT COALESCE(" . @@ -541,8 +730,6 @@ sub get_transdate { " current_date)"; ($form->{transdate}) = $dbh->selectrow_array($query); - $dbh->disconnect; - $main::lxdebug->leave_sub(); } @@ -586,17 +773,33 @@ sub _delete_payments { } sub post_payment { + my ($self, $myconfig, $form, $locale) = @_; $main::lxdebug->enter_sub(); + my $rc = SL::DB->client->with_transaction(\&_post_payment, $self, $myconfig, $form, $locale); + + $::lxdebug->leave_sub; + return $rc; +} + +sub _post_payment { my ($self, $myconfig, $form, $locale) = @_; - # connect to database, turn off autocommit - my $dbh = $form->dbconnect_noauto($myconfig); + my $dbh = SL::DB->client->dbh; my (%payments, $old_form, $row, $item, $query, %keep_vars); $old_form = save_form(); + $query = <{id}); + # Delete all entries in acc_trans from prior payments. if (SL::DB::Default->get->payments_changeable != 0) { $self->_delete_payments($form, $dbh); @@ -625,7 +828,7 @@ sub post_payment { # Get the AP accno. $query = - qq|SELECT c.accno + qq|SELECT c.id FROM acc_trans at LEFT JOIN chart c ON (at.chart_id = c.id) WHERE (trans_id = ?) @@ -633,19 +836,14 @@ sub post_payment { ORDER BY at.acc_trans_id LIMIT 1|; - ($form->{APselected}) = selectfirst_array_query($form, $dbh, $query, conv_i($form->{id})); + ($form->{AP_chart_id}) = selectfirst_array_query($form, $dbh, $query, conv_i($form->{id})); # Post the new payments. - $self->post_transaction($myconfig, $form, $dbh, 1); + $self->post_transaction($myconfig, $form, $dbh, payments_only => 1, already_cleared => \%already_cleared); restore_form($old_form); - my $rc = $dbh->commit(); - $dbh->disconnect(); - - $main::lxdebug->leave_sub(); - - return $rc; + return 1; } sub setup_form { @@ -715,7 +913,7 @@ sub setup_form { } $index = $form->{acc_trans}{$key}->[$i - 1]->{index}; - $form->{"tax_$index"} = $form->{acc_trans}{$key}->[$i - 1]->{amount} * -1; + $form->{"tax_$index"} = $form->round_amount($form->{acc_trans}{$key}->[$i - 1]->{amount} * -1 / $exchangerate, 2); $totaltax += $form->{"tax_$index"}; } else { @@ -731,26 +929,7 @@ sub setup_form { $form->{"projectnumber_$k"} = "$form->{acc_trans}{$key}->[$i-1]->{projectnumber}"; $form->{"oldprojectnumber_$k"} = $form->{"projectnumber_$k"}; $form->{"project_id_$k"} = "$form->{acc_trans}{$key}->[$i-1]->{project_id}"; - } - - $form->{"${key}_$k"} = "$form->{acc_trans}{$key}->[$i-1]->{accno}--$form->{acc_trans}{$key}->[$i-1]->{description}"; - - my $q_description = quotemeta($form->{acc_trans}{$key}->[$i-1]->{description}); - $form->{"select${key}"} =~ - m/