tax_id in acc_trans
[kivitendo-erp.git] / SL / IR.pm
index 909a3b0..5ff85e5 100644 (file)
--- a/SL/IR.pm
+++ b/SL/IR.pm
@@ -38,11 +38,13 @@ use SL::AM;
 use SL::ARAP;
 use SL::Common;
 use SL::CVar;
+use SL::DATEV qw(:CONSTANTS);
 use SL::DBUtils;
 use SL::DO;
 use SL::GenericTranslations;
 use SL::IO;
 use SL::MoreCommon;
+use SL::DB::Default;
 use List::Util qw(min);
 
 use strict;
@@ -83,7 +85,7 @@ sub post_invoice {
   if ($form->{currency} eq $defaultcurrency) {
     $form->{exchangerate} = 1;
   } else {
-    $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{transdate}, 'sell');
+    $exchangerate = $form->check_exchangerate($myconfig, $form->{currency}, $form->{invdate}, 'sell');
   }
 
   $form->{exchangerate} = $exchangerate || $form->parse_amount($myconfig, $form->{exchangerate});
@@ -207,9 +209,9 @@ sub post_invoice {
 
       next if $payments_only;
 
-      # update parts table
+      # update parts table by setting lastcost to current price, don't allow negative values by using abs
       $query = qq|UPDATE parts SET lastcost = ? WHERE id = ?|;
-      @values = ($form->{"sellprice_$i"}, conv_i($form->{"id_$i"}));
+      @values = (abs($form->{"sellprice_$i"} / $basefactor), conv_i($form->{"id_$i"}));
       do_query($form, $dbh, $query, @values);
 
       # check if we sold the item already and
@@ -267,13 +269,15 @@ sub post_invoice {
 
             # allocated >= 0
             # add entry for inventory, this one is for the sold item
-            $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey) VALUES (?, ?, ?, ?, (SELECT taxkey_id FROM chart WHERE id = ?))|;
-            @values = ($ref->{trans_id},  $ref->{inventory_accno_id}, $linetotal, $ref->{transdate}, $ref->{inventory_accno_id});
+            $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, tax_id) VALUES (?, ?, ?, ?, (SELECT taxkey_id FROM chart WHERE id = ?),
+                                (SELECT tax_id FROM taxkeys WHERE taxkey_id= (SELECT taxkey_id  FROM chart WHERE accno = ?) AND startdate <= ? ORDER BY startdate DESC LIMIT 1))|;
+            @values = ($ref->{trans_id},  $ref->{inventory_accno_id}, $linetotal, $ref->{transdate}, $ref->{inventory_accno_id}, $ref->{inventory_accno_id}, $ref->{transdate});
             do_query($form, $dbh, $query, @values);
 
 # add expense
-            $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey) VALUES (?, ?, ?, ?, (SELECT taxkey from tax WHERE chart_id = ?))|;
-            @values = ($ref->{trans_id},  $ref->{expense_accno_id}, ($linetotal * -1), $ref->{transdate}, $ref->{expense_accno_id});
+            $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, tax_id) VALUES (?, ?, ?, ?, (SELECT taxkey from tax WHERE chart_id = ?),
+                                (SELECT tax_id FROM taxkeys WHERE taxkey_id= (SELECT taxkey_id  FROM chart WHERE accno = ?) AND startdate <= ? ORDER BY startdate DESC LIMIT 1))|;
+            @values = ($ref->{trans_id},  $ref->{expense_accno_id}, ($linetotal * -1), $ref->{transdate}, $ref->{expense_accno_id}, $ref->{expense_accno_id}, $ref->{transdate});
             do_query($form, $dbh, $query, @values);
           }
         };
@@ -337,7 +341,7 @@ sub post_invoice {
 
       # update lastcost
       $query = qq|UPDATE parts SET lastcost = ? WHERE id = ?|;
-      do_query($form, $dbh, $query, $form->{"sellprice_$i"}, conv_i($form->{"id_$i"}));
+      do_query($form, $dbh, $query, $form->{"sellprice_$i"} / $basefactor, conv_i($form->{"id_$i"}));
     }
 
     next if $payments_only;
@@ -476,11 +480,12 @@ sub post_invoice {
 
       next if $payments_only || !$form->{amount}{$trans_id}{$accno};
 
-      $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
+      $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id, tax_id)
                   VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
-                  (SELECT taxkey_id  FROM chart WHERE accno = ?), ?)|;
+                  (SELECT taxkey_id  FROM chart WHERE accno = ?), ?,
+                  (SELECT tax_id FROM taxkeys WHERE taxkey_id= (SELECT taxkey_id  FROM chart WHERE accno = ?) AND startdate <= ? ORDER BY startdate DESC LIMIT 1))|;
       @values = ($trans_id, $accno, $form->{amount}{$trans_id}{$accno},
-                 conv_date($form->{invdate}), $accno, $project_id);
+                 conv_date($form->{invdate}), $accno, $project_id, $accno, conv_date($form->{invdate}));
       do_query($form, $dbh, $query, @values);
     }
   }
@@ -499,6 +504,12 @@ sub post_invoice {
 
   # record payments and offsetting AP
   for my $i (1 .. $form->{paidaccounts}) {
+    if ($form->{"acc_trans_id_$i"}
+        && $payments_only
+        && (SL::DB::Default->get->payments_changeable == 0)) {
+      next;
+    }
+
     next if $form->{"paid_$i"} == 0;
 
     my ($accno)            = split /--/, $form->{"AP_paid_$i"};
@@ -509,20 +520,25 @@ sub post_invoice {
 
     # record AP
     if ($form->{amount}{ $form->{id} }{ $form->{AP} } != 0) {
-      $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id)
+      $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, taxkey, project_id, tax_id)
                   VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?,
-                          (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
+                          (SELECT taxkey_id FROM chart WHERE accno = ?), ?,
+                          (SELECT tax_id FROM taxkeys WHERE taxkey_id= (SELECT taxkey_id  FROM chart WHERE accno = ?) AND startdate <= ? ORDER BY startdate DESC LIMIT 1))|;
       @values = (conv_i($form->{id}), $form->{AP}, $amount,
-                 $form->{"datepaid_$i"}, $form->{AP}, $project_id);
+                 $form->{"datepaid_$i"}, $form->{AP}, $project_id, $form->{AP}, conv_date($form->{"datepaid_$i"}));
       do_query($form, $dbh, $query, @values);
     }
 
     # record payment
-    $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, source, memo, taxkey, project_id)
-                VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, ?, ?,
-                (SELECT taxkey_id FROM chart WHERE accno = ?), ?)|;
+    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, taxkey, project_id, tax_id)
+                VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, ?, ?, ?,
+                (SELECT taxkey_id FROM chart WHERE accno = ?), ?,
+                (SELECT tax_id FROM taxkeys WHERE taxkey_id= (SELECT taxkey_id  FROM chart WHERE accno = ?) AND startdate <= ? ORDER BY startdate DESC LIMIT 1))|;
     @values = (conv_i($form->{id}), $accno, $form->{"paid_$i"}, $form->{"datepaid_$i"},
-               $form->{"source_$i"}, $form->{"memo_$i"}, $accno, $project_id);
+               $gldate, $form->{"source_$i"}, $form->{"memo_$i"}, $accno, $project_id, $accno, conv_date($form->{"datepaid_$i"}));
     do_query($form, $dbh, $query, @values);
 
     $exchangerate = 0;
@@ -560,9 +576,10 @@ sub post_invoice {
       $form->{fx}{$accno}{$transdate} = $form->round_amount($form->{fx}{$accno}{$transdate}, 2);
       next if ($form->{fx}{$accno}{$transdate} == 0);
 
-      $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, cleared, fx_transaction, taxkey, project_id)
-                  VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, '0', '1', 0, ?)|;
-      @values = (conv_i($form->{id}), $accno, $form->{fx}{$accno}{$transdate}, conv_date($transdate), $project_id);
+      $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate, cleared, fx_transaction, taxkey, project_id, tax_id)
+                  VALUES (?, (SELECT id FROM chart WHERE accno = ?), ?, ?, '0', '1', 0, ?,
+                  (SELECT tax_id FROM taxkeys WHERE taxkey_id= (SELECT taxkey_id  FROM chart WHERE accno = ?) AND startdate <= ? ORDER BY startdate DESC LIMIT 1))|;
+      @values = (conv_i($form->{id}), $accno, $form->{fx}{$accno}{$transdate}, conv_date($transdate), $project_id, $accno, $form->{fx}{$accno}{$transdate});
       do_query($form, $dbh, $query, @values);
     }
   }
@@ -674,6 +691,27 @@ sub post_invoice {
                                'arap_id' => $form->{id},
                                'table'   => 'ap',);
 
+  # safety check datev export
+  if ($::instance_conf->get_datev_check_on_purchase_invoice) {
+    my $transdate = $::form->{invdate} ? DateTime->from_lxoffice($::form->{invdate}) : undef;
+    $transdate  ||= DateTime->today;
+
+    my $datev = SL::DATEV->new(
+      exporttype => DATEV_ET_BUCHUNGEN,
+      format     => DATEV_FORMAT_KNE,
+      dbh        => $dbh,
+      from       => $transdate,
+      to         => $transdate,
+    );
+
+    $datev->export;
+
+    if ($datev->errors) {
+      $dbh->rollback;
+      die join "\n", $::locale->text('DATEV check returned errors:'), $datev->errors;
+    }
+  }
+
   my $rc = 1;
   if (!$provided_dbh) {
     $rc = $dbh->commit();
@@ -844,6 +882,9 @@ sub retrieve_invoice {
   $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{id}));
   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
+  # remove any trailing whitespace
+  $form->{currency} =~ s/\s*$//;
+
   $form->{exchangerate}  = $form->get_exchangerate($dbh, $form->{currency}, $form->{invdate}, "sell");
 
   # get shipto
@@ -985,7 +1026,7 @@ sub get_vendor {
          v.id AS vendor_id, v.name AS vendor, v.discount as vendor_discount,
          v.creditlimit, v.terms, v.notes AS intnotes,
          v.email, v.cc, v.bcc, v.language_id, v.payment_id,
-         v.street, v.zipcode, v.city, v.country, v.taxzone_id,
+         v.street, v.zipcode, v.city, v.country, v.taxzone_id, v.curr,
          $duedate + COALESCE(pt.terms_netto, 0) AS duedate,
          b.description AS business
        FROM vendor v
@@ -995,6 +1036,12 @@ sub get_vendor {
   my $ref = selectfirst_hashref_query($form, $dbh, $query, @values);
   map { $params->{$_} = $ref->{$_} } keys %$ref;
 
+  # remove any trailing whitespace
+  $form->{curr} =~ s/\s*$//;
+
+  # use vendor currency if not empty
+  $form->{currency} = $form->{curr} if $form->{curr};
+
   $params->{creditremaining} = $params->{creditlimit};
 
   $query = qq|SELECT SUM(amount - paid) FROM ap WHERE vendor_id = ?|;
@@ -1277,7 +1324,8 @@ sub vendor_details {
   # get rest for the vendor
   # fax and phone and email as vendor*
   my $query =
-    qq|SELECT ct.*, cp.*, ct.notes as vendornotes, phone as vendorphone, fax as vendorfax, email as vendoremail
+    qq|SELECT ct.*, cp.*, ct.notes as vendornotes, phone as vendorphone, fax as vendorfax, email as vendoremail,
+         ct.curr AS currency
        FROM vendor ct
        LEFT JOIN contacts cp ON (ct.id = cp.cp_cv_id)
        WHERE (ct.id = ?) $contact
@@ -1296,6 +1344,8 @@ sub vendor_details {
   }
 
   map { $form->{$_} = $ref->{$_} } keys %$ref;
+  # remove any trailing whitespace
+  $form->{currency} =~ s/\s*$// if ($form->{currency});
 
   my $custom_variables = CVar->get_custom_variables('dbh'      => $dbh,
                                                     'module'   => 'CT',
@@ -1394,10 +1444,12 @@ sub post_payment {
   $old_form = save_form();
 
   # Delete all entries in acc_trans from prior payments.
-  $self->_delete_payments($form, $dbh);
+  if (SL::DB::Default->get->payments_changeable != 0) {
+    $self->_delete_payments($form, $dbh);
+  }
 
   # Save the new payments the user made before cleaning up $form.
-  map { $payments{$_} = $form->{$_} } grep m/^datepaid_\d+$|^memo_\d+$|^source_\d+$|^exchangerate_\d+$|^paid_\d+$|^AP_paid_\d+$|^paidaccounts$/, keys %{ $form };
+  map { $payments{$_} = $form->{$_} } grep m/^datepaid_\d+$|^gldate_\d+$|^acc_trans_id_\d+$|^memo_\d+$|^source_\d+$|^exchangerate_\d+$|^paid_\d+$|^AP_paid_\d+$|^paidaccounts$/, keys %{ $form };
 
   # Clean up $form so that old content won't tamper the results.
   %keep_vars = map { $_, 1 } qw(login password id);
@@ -1450,38 +1502,26 @@ sub post_payment {
 }
 
 sub get_duedate {
-  $main::lxdebug->enter_sub();
+  $::lxdebug->enter_sub;
 
-  my $self     = shift;
-  my %params   = @_;
+  my ($self, %params) = @_;
 
   if (!$params{vendor_id} || !$params{invdate}) {
-    $main::lxdebug->leave_sub();
+    $::lxdebug->leave_sub;
     return $params{default};
   }
 
-  my $myconfig = \%main::myconfig;
-  my $form     = $main::form;
-
-  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
-
+  my $dbh      = $::form->get_standard_dbh;
   my $query    = qq|SELECT ?::date + pt.terms_netto
                     FROM vendor v
                     LEFT JOIN payment_terms pt ON (pt.id = v.payment_id)
                     WHERE v.id = ?|;
 
-  my ($sth, $duedate);
-
-  if (($sth = $dbh->prepare($query)) && $sth->execute($params{invdate}, conv_i($params{vendor_id}))) {
-    ($duedate) = $sth->fetchrow_array();
-    $sth->finish();
-  } else {
-    $dbh->rollback();
-  }
+  my ($duedate) = selectfirst_array_query($::form, $dbh, $query, $params{invdate}, $params{vendor_id});
 
   $duedate ||= $params{default};
 
-  $main::lxdebug->leave_sub();
+  $::lxdebug->leave_sub;
 
   return $duedate;
 }