Jahresabschluß - GLTransaction->post und Tests
[kivitendo-erp.git] / SL / Controller / YearEndTransactions.pm
index 00dea4b..43b4fee 100644 (file)
@@ -49,7 +49,6 @@ sub action_year_end_bookings {
 
   $self->_parse_form;
 
-
   eval {
     _year_end_bookings( start_date => $self->cb_startdate,
                         cb_date    => $self->cb_date,
@@ -66,9 +65,9 @@ sub action_year_end_bookings {
                                                );
 
   my $html = $self->render('yearend/_charts', { layout  => 0 , process => 1, output => 0 },
-                 charts          => $report_data,
-                 profit_loss_sum => $profit_loss_sum,
-               );
+                           charts          => $report_data,
+                           profit_loss_sum => $profit_loss_sum,
+                          );
   return $self->js->flash('info', t8('Year-end bookings were successfully completed!'))
                ->html('#charts', $html)
                ->render;
@@ -105,8 +104,8 @@ sub action_update_charts {
                                                );
 
   $self->render('yearend/_charts', { layout  => 0 , process => 1 },
-                 charts          => $report_data,
-                 profit_loss_sum => $profit_loss_sum,
+                charts          => $report_data,
+                profit_loss_sum => $profit_loss_sum,
                );
 }
 
@@ -121,7 +120,6 @@ sub _parse_form {
   $self->cb_startdate($::locale->parse_date_to_object($self->get_balance_starting_date($self->cb_date)));
 
   die "cb_date must come after start_date" unless $self->cb_date > $self->cb_startdate;
-
 }
 
 sub _year_end_bookings {
@@ -140,6 +138,10 @@ sub _year_end_bookings {
                                                 cb_date    => $cb_date,
                                                );
 
+  # load all charts from report as objects and store them in a hash
+  my @report_chart_ids = map { $_->{chart_id} } @{ $report_data };
+  my %charts_by_id = map { ( $_->id => $_ ) } @{ SL::DB::Manager::Chart->get_all(where => [ id => \@report_chart_ids ]) };
+
   my @asset_accounts       = grep { $_->{account_type} eq 'asset_account' }       @{ $report_data };
   my @profit_loss_accounts = grep { $_->{account_type} eq 'profit_loss_account' } @{ $report_data };
 
@@ -174,6 +176,8 @@ sub _year_end_bookings {
       description    => 'Automatische SB-Buchungen Bestandskonten Soll für ' . $cb_date->year,
       ob_transaction => 0,
       cb_transaction => 1,
+      taxincluded    => 0,
+      transactions   => [],
     );
     my $asset_ob_debit_entry = SL::DB::GLTransaction->new(
       employee_id    => $employee_id,
@@ -182,6 +186,8 @@ sub _year_end_bookings {
       description    => 'Automatische EB-Buchungen Bestandskonten Haben für ' . $ob_date->year,
       ob_transaction => 1,
       cb_transaction => 0,
+      taxincluded    => 0,
+      transactions   => [],
     );
     my $asset_cb_credit_entry = SL::DB::GLTransaction->new(
       employee_id    => $employee_id,
@@ -190,6 +196,8 @@ sub _year_end_bookings {
       description    => 'Automatische SB-Buchungen Bestandskonten Haben für ' . $cb_date->year,
       ob_transaction => 0,
       cb_transaction => 1,
+      taxincluded    => 0,
+      transactions   => [],
     );
     my $asset_ob_credit_entry = SL::DB::GLTransaction->new(
       employee_id    => $employee_id,
@@ -198,100 +206,77 @@ sub _year_end_bookings {
       description    => 'Automatische EB-Buchungen Bestandskonten Soll für ' . $ob_date->year,
       ob_transaction => 1,
       cb_transaction => 0,
+      taxincluded    => 0,
+      transactions   => [],
     );
-    $asset_cb_debit_entry->transactions([]);
-    $asset_ob_debit_entry->transactions([]);
-    $asset_cb_credit_entry->transactions([]);
-    $asset_ob_credit_entry->transactions([]);
 
     foreach my $asset_account ( @asset_accounts ) {
       next if $asset_account->{amount_with_cb} == 0;
-
-      # create cb and ob acc_trans entry here, but decide which gl entry to add it to later
-      my $asset_cb_acc = SL::DB::AccTransaction->new(
-        transdate      => $cb_date,
-        ob_transaction => 0,
-        cb_transaction => 1,
-        chart_id       => $asset_account->{chart_id},
-        chart_link     => $asset_account->{chart_link},
-        tax_id         => 0,
-        taxkey         => 0,
-        amount         => - $asset_account->{amount_with_cb},
-      );
-      my $asset_ob_acc = SL::DB::AccTransaction->new(
-        transdate      => $ob_date,
-        ob_transaction => 1,
-        cb_transaction => 0,
-        chart_id       => $asset_account->{chart_id},
-        chart_link     => $asset_account->{chart_link},
-        tax_id         => 0,
-        taxkey         => 0,
-        amount         => $asset_account->{amount_with_cb},
-      );
+      my $ass_acc = $charts_by_id{ $asset_account->{chart_id} };
 
       if ( $asset_account->{amount_with_cb} < 0 ) {
-        $debit_balance += $asset_account->{amount_with_cb};
         # $main::lxdebug->message(0, sprintf("adding accno %s with balance %s to debit", $asset_account->{accno}, $asset_account->{amount_with_cb}));
+        $debit_balance += $asset_account->{amount_with_cb};
+
+        $asset_cb_debit_entry->add_chart_booking(
+          chart  => $ass_acc,
+          credit => - $asset_account->{amount_with_cb},
+          tax_id => 0
+        );
+        $asset_ob_debit_entry->add_chart_booking(
+          chart  => $ass_acc,
+          debit  => - $asset_account->{amount_with_cb},
+          tax_id => 0
+        );
 
-        $asset_cb_debit_entry->add_transactions($asset_cb_acc);
-        $asset_ob_debit_entry->add_transactions($asset_ob_acc);
       } else {
         # $main::lxdebug->message(0, sprintf("adding accno %s with balance %s to credit", $asset_account->{accno}, $asset_account->{amount_with_cb}));
         $credit_balance += $asset_account->{amount_with_cb};
-        $asset_cb_credit_entry->add_transactions($asset_cb_acc);
-        $asset_ob_credit_entry->add_transactions($asset_ob_acc);
+
+        $asset_cb_credit_entry->add_chart_booking(
+          chart  => $ass_acc,
+          debit  => $asset_account->{amount_with_cb},
+          tax_id => 0
+        );
+        $asset_ob_credit_entry->add_chart_booking(
+          chart  => $ass_acc,
+          credit  => $asset_account->{amount_with_cb},
+          tax_id => 0
+        );
       };
     };
 
-    my $debit_cb_acc = SL::DB::AccTransaction->new(
-      transdate      => $cb_date,
-      ob_transaction => 0,
-      cb_transaction => 1,
-      chart_id       => $carry_over_chart->id,
-      chart_link     => $carry_over_chart->link, # maybe leave chart_link empty?
-      tax_id         => 0,
-      taxkey         => 0,
-      amount         => $debit_balance,
-    );
-    my $debit_ob_acc = SL::DB::AccTransaction->new(
-      transdate      => $ob_date,
-      ob_transaction => 1,
-      cb_transaction => 0,
-      chart_id       => $carry_over_chart->id,
-      chart_link     => $carry_over_chart->link,
-      tax_id         => 0,
-      taxkey         => 0,
-      amount         => - $debit_balance,
-    );
-    my $credit_cb_acc = SL::DB::AccTransaction->new(
-      transdate      => $cb_date,
-      ob_transaction => 0,
-      cb_transaction => 1,
-      chart_id       => $carry_over_chart->id,
-      chart_link     => $carry_over_chart->link, # maybe leave chart_link empty?
-      tax_id         => 0,
-      taxkey         => 0,
-      amount         => $credit_balance,
-    );
-    my $credit_ob_acc = SL::DB::AccTransaction->new(
-      transdate      => $ob_date,
-      ob_transaction => 1,
-      cb_transaction => 0,
-      chart_id       => $carry_over_chart->id,
-      chart_link     => $carry_over_chart->link,
-      tax_id         => 0,
-      taxkey         => 0,
-      amount         => - $credit_balance,
-    );
-    $asset_cb_debit_entry->add_transactions($debit_cb_acc);
-    $asset_ob_debit_entry->add_transactions($debit_ob_acc);
-    $asset_cb_credit_entry->add_transactions($credit_cb_acc);
-    $asset_ob_credit_entry->add_transactions($credit_ob_acc);
+    if ( $debit_balance ) {
+      $asset_cb_debit_entry->add_chart_booking(
+        chart  => $carry_over_chart,
+        debit  => -1 * $debit_balance,
+        tax_id => 0,
+      );
+
+      $asset_ob_debit_entry->add_chart_booking(
+        chart  => $carry_over_chart,
+        credit => -1 * $debit_balance,
+        tax_id => 0,
+      );
+    };
+
+    if ( $credit_balance ) {
+      $asset_cb_credit_entry->add_chart_booking(
+        chart  => $carry_over_chart,
+        credit => $credit_balance,
+        tax_id => 0,
+      );
+      $asset_ob_credit_entry->add_chart_booking(
+        chart  => $carry_over_chart,
+        debit  => $credit_balance,
+        tax_id => 0,
+      );
+    };
 
-    $asset_cb_debit_entry->save if scalar @{ $asset_cb_debit_entry->transactions } > 1;
-    $asset_ob_debit_entry->save if scalar @{ $asset_ob_debit_entry->transactions } > 1;
-    $asset_cb_credit_entry->save if scalar @{ $asset_cb_credit_entry->transactions } > 1;
-    $asset_ob_credit_entry->save if scalar @{ $asset_ob_credit_entry->transactions } > 1;
+    $asset_cb_debit_entry->post  if scalar @{ $asset_cb_debit_entry->transactions  } > 1;
+    $asset_ob_debit_entry->post  if scalar @{ $asset_ob_debit_entry->transactions  } > 1;
+    $asset_cb_credit_entry->post if scalar @{ $asset_cb_credit_entry->transactions } > 1;
+    $asset_ob_credit_entry->post if scalar @{ $asset_ob_credit_entry->transactions } > 1;
 
     #######  profit-loss accounts #######
     # these only have a closing balance, the balance is transferred to the profit-loss account
@@ -301,6 +286,7 @@ sub _year_end_bookings {
     my $profit_loss_sum = sum map { $_->{amount_with_cb} }
                               grep { $_->{account_type} eq 'profit_loss_account' }
                               @{$report_data};
+    $profit_loss_sum ||= 0;
     my $pl_chart;
     if ( $profit_loss_sum > 0 ) {
       $pl_chart = $profit_chart;
@@ -318,6 +304,8 @@ sub _year_end_bookings {
       description    => 'Automatische SB-Buchungen Erfolgskonten Soll für ' . $cb_date->year,
       ob_transaction => 0,
       cb_transaction => 1,
+      taxincluded    => 0,
+      transactions   => [],
     );
     my $pl_cb_credit_entry = SL::DB::GLTransaction->new(
       employee_id    => $employee_id,
@@ -326,148 +314,123 @@ sub _year_end_bookings {
       description    => 'Automatische SB-Buchungen Erfolgskonten Haben für ' . $cb_date->year,
       ob_transaction => 0,
       cb_transaction => 1,
+      taxincluded    => 0,
+      transactions   => [],
     );
-    $pl_cb_debit_entry->transactions([]);
-    $pl_cb_credit_entry->transactions([]);
 
     foreach my $profit_loss_account ( @profit_loss_accounts ) {
       # $main::lxdebug->message(0, sprintf("found chart %s with balance %s", $profit_loss_account->{accno}, $profit_loss_account->{amount_with_cb}));
+      my $chart = $charts_by_id{ $profit_loss_account->{chart_id} };
 
       next if $profit_loss_account->{amount_with_cb} == 0;
 
-      my $debit_cb_acc = SL::DB::AccTransaction->new(
-        transdate      => $cb_date,
-        ob_transaction => 0,
-        cb_transaction => 1,
-        chart_id       => $profit_loss_account->{chart_id},
-        chart_link     => $profit_loss_account->{chart_link},
-        tax_id         => 0,
-        taxkey         => 0,
-        amount         => - $profit_loss_account->{amount_with_cb},
-      );
-      my $credit_cb_acc = SL::DB::AccTransaction->new(
-        transdate      => $cb_date,
-        ob_transaction => 0,
-        cb_transaction => 1,
-        chart_id       => $profit_loss_account->{chart_id},
-        chart_link     => $profit_loss_account->{chart_link},
-        tax_id         => 0,
-        taxkey         => 0,
-        amount         => $profit_loss_account->{amount_with_cb},
-      );
-      if ( { $profit_loss_account->{amount_with_cb} < 0 } ) {
-        $pl_debit_balance += $profit_loss_account->{amount_with_cb};
-         $pl_cb_debit_entry->add_transactions($debit_cb_acc);
+      if ( $profit_loss_account->{amount_with_cb} < 0 ) {
+        $pl_debit_balance -= $profit_loss_account->{amount_with_cb};
+        $pl_cb_debit_entry->add_chart_booking(
+          chart  => $chart,
+          tax_id => 0,
+          credit => - $profit_loss_account->{amount_with_cb},
+        );
       } else {
         $pl_credit_balance += $profit_loss_account->{amount_with_cb};
-         $pl_cb_credit_entry->add_transactions($credit_cb_acc);
+        $pl_cb_credit_entry->add_chart_booking(
+          chart  => $chart,
+          tax_id => 0,
+          debit  => $profit_loss_account->{amount_with_cb},
+        );
       };
     };
 
-    $debit_cb_acc = SL::DB::AccTransaction->new(
-      transdate      => $cb_date,
-      ob_transaction => 0,
-      cb_transaction => 1,
-      chart_id       => $pl_chart->id,
-      chart_link     => $pl_chart->link,
-      tax_id         => 0,
-      taxkey         => 0,
-      amount         => $pl_debit_balance,
-    );
-    $credit_cb_acc = SL::DB::AccTransaction->new(
-      transdate      => $cb_date,
-      ob_transaction => 0,
-      cb_transaction => 1,
-      chart_id       => $pl_chart->id,
-      chart_link     => $pl_chart->link,
-      tax_id         => 0,
-      taxkey         => 0,
-      amount         => - $pl_credit_balance,
-    );
-    $pl_cb_debit_entry->add_transactions($debit_cb_acc);
-    $pl_cb_credit_entry->add_transactions($credit_cb_acc);
+    # $main::lxdebug->message(0, "pl_debit_balance  = $pl_debit_balance");
+    # $main::lxdebug->message(0, "pl_credit_balance = $pl_credit_balance");
+
+    $pl_cb_debit_entry->add_chart_booking(
+      chart  => $pl_chart,
+      tax_id => 0,
+      debit  => $pl_debit_balance,
+    ) if $pl_debit_balance;
+
+    $pl_cb_credit_entry->add_chart_booking(
+      chart  => $pl_chart,
+      tax_id => 0,
+      credit => $pl_credit_balance,
+    ) if $pl_credit_balance;
 
-    $pl_cb_debit_entry->save  if scalar @{ $pl_cb_debit_entry->transactions }  > 1;
-    $pl_cb_credit_entry->save if scalar @{ $pl_cb_credit_entry->transactions } > 1;
+    # printf("debit : %s -> %s\n", $_->chart->displayable_name, $_->amount) foreach @{ $pl_cb_debit_entry->transactions };
+    # printf("credit: %s -> %s\n", $_->chart->displayable_name, $_->amount) foreach @{ $pl_cb_credit_entry->transactions };
+
+    $pl_cb_debit_entry->post  if scalar @{ $pl_cb_debit_entry->transactions }  > 1;
+    $pl_cb_credit_entry->post if scalar @{ $pl_cb_credit_entry->transactions } > 1;
 
     ######### profit-loss transfer #########
     # and finally transfer the new balance of the profit-loss account via the carry-over account
     # we want to use profit_loss_sum with cb!
 
-    my $carry_over_cb_entry = SL::DB::GLTransaction->new(
-      employee_id    => $employee_id,
-      transdate      => $cb_date,
-      reference      => 'SB ' . $cb_date->year,
-      description    => sprintf('Automatische SB-Buchung für %s %s',
-                                $profit_loss_sum >= 0 ? 'Gewinnvortrag' : 'Verlustvortrag',
-                                $cb_date->year,
-                               ),
-      ob_transaction => 0,
-      cb_transaction => 1,
-    );
-    my $carry_over_ob_entry = SL::DB::GLTransaction->new(
-      employee_id    => $employee_id,
-      transdate      => $ob_date,
-      reference      => 'EB ' . $ob_date->year,
-      description    => sprintf('Automatische EB-Buchung für %s %s',
-                                $profit_loss_sum >= 0 ? 'Gewinnvortrag' : 'Verlustvortrag',
-                                $ob_date->year,
-                               ),
-      ob_transaction => 1,
-      cb_transaction => 0,
-    );
-    $carry_over_cb_entry->transactions([]);
-    $carry_over_ob_entry->transactions([]);
+    if ( $profit_loss_sum != 0 ) {
 
-    my $carry_over_cb_acc_co = SL::DB::AccTransaction->new(
-      transdate      => $cb_date,
-      ob_transaction => 0,
-      cb_transaction => 1,
-      chart_id       => $carry_over_chart->id,
-      chart_link     => $carry_over_chart->link,
-      tax_id         => 0,
-      taxkey         => 0,
-      amount         => $profit_loss_sum,
-    );
-    my $carry_over_cb_acc_pl = SL::DB::AccTransaction->new(
-      transdate      => $cb_date,
-      ob_transaction => 0,
-      cb_transaction => 1,
-      chart_id       => $pl_chart->id,
-      chart_link     => $pl_chart->link,
-      tax_id         => 0,
-      taxkey         => 0,
-      amount         => - $profit_loss_sum,
-    );
+      my $carry_over_cb_entry = SL::DB::GLTransaction->new(
+        employee_id    => $employee_id,
+        transdate      => $cb_date,
+        reference      => 'SB ' . $cb_date->year,
+        description    => sprintf('Automatische SB-Buchung für %s %s',
+                                  $profit_loss_sum >= 0 ? 'Gewinnvortrag' : 'Verlustvortrag',
+                                  $cb_date->year,
+                                 ),
+        ob_transaction => 0,
+        cb_transaction => 1,
+        taxincluded    => 0,
+        transactions   => [],
+      );
+      my $carry_over_ob_entry = SL::DB::GLTransaction->new(
+        employee_id    => $employee_id,
+        transdate      => $ob_date,
+        reference      => 'EB ' . $ob_date->year,
+        description    => sprintf('Automatische EB-Buchung für %s %s',
+                                  $profit_loss_sum >= 0 ? 'Gewinnvortrag' : 'Verlustvortrag',
+                                  $ob_date->year,
+                                 ),
+        ob_transaction => 1,
+        cb_transaction => 0,
+        taxincluded    => 0,
+        transactions   => [],
+      );
 
-    $carry_over_cb_entry->add_transactions($carry_over_cb_acc_co);
-    $carry_over_cb_entry->add_transactions($carry_over_cb_acc_pl);
-    $carry_over_cb_entry->save if $profit_loss_sum != 0;
+      my ($amount1, $amount2);
+      if ( $profit_loss_sum < 0 ) {
+        $amount1 = 'debit';
+        $amount2 = 'credit';
+      } else {
+        $amount1 = 'credit';
+        $amount2 = 'debit';
+      };
 
-    my $carry_over_ob_acc_co = SL::DB::AccTransaction->new(
-      transdate      => $ob_date,
-      ob_transaction => 1,
-      cb_transaction => 0,
-      chart_id       => $pl_chart->id,
-      chart_link     => $pl_chart->link,
-      tax_id         => 0,
-      taxkey         => 0,
-      amount         => $profit_loss_sum,
-    );
-    my $carry_over_ob_acc_pl = SL::DB::AccTransaction->new(
-      transdate      => $ob_date,
-      ob_transaction => 1,
-      cb_transaction => 0,
-      chart_id       => $carry_over_chart->id,
-      chart_link     => $carry_over_chart->link,
-      tax_id         => 0,
-      taxkey         => 0,
-      amount         => - $profit_loss_sum,
-    );
+      $carry_over_cb_entry->add_chart_booking(
+        chart    => $carry_over_chart,
+        tax_id   => 0,
+        $amount1 => abs($profit_loss_sum),
+      );
+      $carry_over_cb_entry->add_chart_booking(
+        chart    => $pl_chart,
+        tax_id   => 0,
+        $amount2 => abs($profit_loss_sum),
+      );
+      $carry_over_ob_entry->add_chart_booking(
+        chart    => $carry_over_chart,
+        tax_id   => 0,
+        $amount2 => abs($profit_loss_sum),
+      );
+      $carry_over_ob_entry->add_chart_booking(
+        chart    => $pl_chart,
+        tax_id   => 0,
+        $amount1 => abs($profit_loss_sum),
+      );
+
+      # printf("debit : %s -> %s\n", $_->chart->displayable_name, $_->amount) foreach @{ $carry_over_ob_entry->transactions };
+      # printf("credit: %s -> %s\n", $_->chart->displayable_name, $_->amount) foreach @{ $carry_over_ob_entry->transactions };
 
-    $carry_over_ob_entry->add_transactions($carry_over_ob_acc_co);
-    $carry_over_ob_entry->add_transactions($carry_over_ob_acc_pl);
-    $carry_over_ob_entry->save if $profit_loss_sum != 0;
+      $carry_over_cb_entry->post if scalar @{ $carry_over_cb_entry->transactions } > 1;
+      $carry_over_ob_entry->post if scalar @{ $carry_over_ob_entry->transactions } > 1;
+    };
 
     my $consistency_query = <<SQL;
 select sum(amount)
@@ -475,10 +438,10 @@ select sum(amount)
  where     (ob_transaction is true or cb_transaction is true)
        and (transdate = ? or transdate = ?)
 SQL
-     my ($sum) = my ($empty) = selectrow_query($::form, $db->dbh, $consistency_query,
-                                               $cb_date,
-                                               $ob_date
-                                              );
+    my ($sum) = selectrow_query($::form, $db->dbh, $consistency_query,
+                                $cb_date,
+                                $ob_date
+                               );
      die "acc_trans transactions don't add up to zero" unless $sum == 0;
 
     1;
@@ -500,7 +463,6 @@ sub _report {
 select c.id as chart_id,
        c.accno,
        c.description,
-       c.link as chart_link,
        c.category,
        sum(a.amount) filter (where cb_transaction is false and ob_transaction is false) as amount,
        sum(a.amount) filter (where ob_transaction is true                             ) as ob_amount,