Consolidation and extended test runs
[kivitendo-erp.git] / SL / AccTransCorrections.pm
index 44f3afd..ea7ca53 100644 (file)
@@ -1,5 +1,6 @@
 package AccTransCorrections;
 
+use utf8;
 use strict;
 
 use List::Util qw(first);
@@ -129,8 +130,8 @@ sub _prepare_data {
     delete $entry->{chartlink};
   }
 
-  # Verknüpfungen zwischen Steuerschlüsseln und zum Zeitpunkt der Transaktion
-  # gültigen Steuersätze
+  # Verknüpfungen zwischen Steuerschlüsseln und zum Zeitpunkt der Transaktion
+  # gültigen Steuersätze
   my %all_taxes = $self->{taxkeys}->get_full_tax_info('transdate' => $transaction->[0]->{transdate});
 
   my ($trans_type, $previous_non_tax_entry);
@@ -184,8 +185,8 @@ sub _prepare_data {
     }
   }
 
-  # Alle Einträge entfernen, die die Gegenkonten zu Zahlungsein- und
-  # -ausgängen darstellen.
+  # Alle Einträge entfernen, die die Gegenkonten zu Zahlungsein- und
+  # -ausgängen darstellen.
   foreach my $payment (@{ $data->{payments} }) {
     my $idx = 0 < $payment->{amount} ? 'debit' : 'credit';
 
@@ -253,8 +254,8 @@ sub _group_sub_transactions {
 }
 
 # Problemfall: Verkaufsrechnungen, bei denen Buchungen auf Warenbestandskonten
-# mit Steuerschlüssel != 0 durchgeführt wurden. Richtig wäre, dass alle
-# Steuerschlüssel für solche Warenbestandsbuchungen 0 sind.
+# mit Steuerschlüssel != 0 durchgeführt wurden. Richtig wäre, dass alle
+# Steuerschlüssel für solche Warenbestandsbuchungen 0 sind.
 sub _check_trans_invoices_inventory_with_taxkeys {
   $main::lxdebug->enter_sub();
 
@@ -288,8 +289,51 @@ sub _check_trans_invoices_inventory_with_taxkeys {
   return 0;
 }
 
-# Problemfall: Kreditorenbuchungen, bei denen mit Umsatzsteuerschlüsseln
-# gebucht wurde und Debitorenbuchungen, bei denen mit Vorsteuerschlüsseln
+# Problemfall: Verkaufsrechnungen, bei denen Steuern verbucht wurden, obwohl
+# kein Steuerschlüssel eingetragen ist.
+sub _check_missing_taxkeys_in_invoices {
+  $::lxdebug->enter_sub;
+
+  my $self        = shift;
+  my %params      = @_;
+  my $transaction = $params{transaction};
+  my $found_broken = 0;
+
+  $::lxdebug->leave_sub and return 0
+    if    !$transaction->[0]->{invoice};
+
+  my @sub_transactions = $self->_group_sub_transactions($transaction);
+
+  for my $sub_transaction (@sub_transactions) {
+    $::lxdebug->leave_sub and return 0
+      if    _is_split_transaction($sub_transaction)
+         || _is_simple_transaction($sub_transaction);
+
+    my $split_side_entries = _get_splitted_side($sub_transaction);
+    my $num_tax_rows;
+    my $num_taxed_rows;
+    for my $entry (@{ $split_side_entries }) {
+      my $is_tax = grep { m/(?:AP_tax|AR_tax)/ } keys %{ $entry->{chartlinks} };
+
+      $num_tax_rows++   if  $is_tax;
+      $num_taxed_rows++ if !$is_tax && $entry->{tax_key} != 0;
+    }
+
+    # now if this has tax rows but NO taxed rows, something is wrong.
+    if ($num_tax_rows > 0 && $num_taxed_rows == 0) {
+      $params{problem}->{type} = 'missing_taxkeys_in_invoices';
+      push @{ $self->{missing_taxkeys_in_invoices} ||= [] }, $params{problem};
+      $found_broken = 1;
+    }
+  }
+
+  $::lxdebug->leave_sub;
+
+  return $found_broken;
+}
+
+# Problemfall: Kreditorenbuchungen, bei denen mit Umsatzsteuerschlüsseln
+# gebucht wurde und Debitorenbuchungen, bei denen mit Vorsteuerschlüsseln
 # gebucht wurde.
 sub _check_trans_ap_ar_wrong_taxkeys {
   $main::lxdebug->enter_sub();
@@ -317,8 +361,8 @@ sub _check_trans_ap_ar_wrong_taxkeys {
 }
 
 # Problemfall: Splitbuchungen, die mehrere Haben- und Sollkonten ansprechen.
-# Aber nur für Debitoren- und Kreditorenbuchungen, weil das bei Einkaufs- und
-# Verkaufsrechnungen hingegen völlig normal ist.
+# Aber nur für Debitoren- und Kreditorenbuchungen, weil das bei Einkaufs- und
+# Verkaufsrechnungen hingegen völlig normal ist.
 sub _check_trans_split_multiple_credit_and_debit {
   $main::lxdebug->enter_sub();
 
@@ -342,7 +386,7 @@ sub _check_trans_split_multiple_credit_and_debit {
 }
 
 # Problemfall: Buchungen, bei denen Steuersummen nicht mit den Summen
-# übereinstimmen, die nach ausgewähltem Steuerschlüssel hätten auftreten müssen.
+# übereinstimmen, die nach ausgewähltem Steuerschlüssel hätten auftreten müssen.
 sub _check_trans_wrong_taxkeys {
   $main::lxdebug->enter_sub();
 
@@ -467,16 +511,16 @@ sub _check_trans_wrong_taxkeys {
   return $retval;
 }
 
-# Inaktiver Code für das Erraten möglicher Verteilungen von
-# Steuerschlüsseln. Deaktiviert, weil er exponentiell Zeit
-# benötigt.
+# Inaktiver Code für das Erraten möglicher Verteilungen von
+# Steuerschlüsseln. Deaktiviert, weil er exponentiell Zeit
+# benötigt.
 
 #       if (abs($expected_tax - $data{$side}->{tax_sum}) >= 0.02) {
 #         my @potential_taxkeys = $trans_type eq 'AP' ? (0, 8, 9) : (0, 1, 2, 3);
 
 #         $main::lxdebug->dump(0, "pota", \@potential_taxkeys);
 
-#         # Über alle Kombinationen aus Buchungssätzen und potenziellen Steuerschlüsseln
+#         # Über alle Kombinationen aus Buchungssätzen und potenziellen Steuerschlüsseln
 #         # iterieren und jeweils die Summe ermitteln.
 #         my $num_entries    = scalar @{ $data{$side}->{entries} };
 #         my @taxkey_indices = (0) x $num_entries;
@@ -490,7 +534,7 @@ sub _check_trans_wrong_taxkeys {
 #         while ($num_entries == scalar @taxkey_indices) {
 #           my @tax_cache = ();
 
-#           # Berechnen der Steuersumme für die aktuell angenommenen Steuerschlüssel.
+#           # Berechnen der Steuersumme für die aktuell angenommenen Steuerschlüssel.
 #           my $tax_sum = 0;
 #           foreach my $i (0 .. $num_entries - 1) {
 #             my $taxkey      = $potential_taxkeys[$taxkey_indices[$i]];
@@ -500,9 +544,9 @@ sub _check_trans_wrong_taxkeys {
 #             $tax_sum       += $tax_cache[$i];
 #           }
 
-#           # Entspricht die Steuersumme mit den aktuell angenommenen Steuerschlüsseln
+#           # Entspricht die Steuersumme mit den aktuell angenommenen Steuerschlüsseln
 #           # der verbuchten Steuersumme? Wenn ja, dann ist das eine potenzielle
-#           # Lösung.
+#           # Lösung.
 #           if (abs($tax_sum - $data{$side}->{tax_sum}) < 0.02) {
 #             push @solutions, {
 #               'taxkeys' => [ @potential_taxkeys[@taxkey_indices] ],
@@ -510,8 +554,8 @@ sub _check_trans_wrong_taxkeys {
 #             }
 #           }
 
-#           # Weiterzählen der Steuerschlüsselindices zum Interieren über
-#           # alle möglichen Kombinationen.
+#           # Weiterzählen der Steuerschlüsselindices zum Interieren über
+#           # alle möglichen Kombinationen.
 #           my $i = 0;
 #           while (1) {
 #             $taxkey_indices[$i]++;
@@ -605,6 +649,8 @@ sub analyze {
 
   my @problems = @{ $self->{problems} };
 
+  map { $self->{$_} ||= [] } qw(ap_ar_taxkey_problems invoice_inventory_taxkey_problems missing_taxkeys_in_invoices);
+
   if (0 != scalar @{ $self->{ap_ar_taxkey_problems} }) {
     my $problem = {
       'type'        => 'ap_ar_wrong_taxkeys',
@@ -623,8 +669,18 @@ sub analyze {
     unshift @problems, $problem;
   }
 
+  if (0 != scalar @{ $self->{missing_taxkeys_in_invoices} }) {
+    my $problem = {
+      'type'        => 'missing_taxkeys_in_invoices',
+      'ap_problems' => [ grep { $_->{data}->{module} eq 'ap' } @{ $self->{missing_taxkeys_in_invoices} } ],
+      'ar_problems' => [ grep { $_->{data}->{module} eq 'ar' } @{ $self->{missing_taxkeys_in_invoices} } ],
+    };
+    unshift @problems, $problem;
+  }
+
   $main::lxdebug->leave_sub();
 
+#  $::lxdebug->dump(0, 'problems:', \@problems);
 
   return @problems;
 }