Project

General

Profile

Export aller Kontenblätter

Vor allem für einen Jahresabschluss ist es normalerweise nötig, unter "Berichte → Konten" die Auszüge von allen bebuchten Konten zu exportieren.

Da es diese Funktion bisher in kivitendo nicht gibt, haben wir einen provisorischen "Hack" erstellt, mit dem alle Kontenblätter für ein bestimmtes Jahr als csv-Dateien exportiert werden können.

Die Änderungen betreffen ausschliesslich die Datei bin/mozilla/ca.pl.

Wir haben dazu die zwei neuen Subroutinen 'csvkonten' und 'csv_transactions' erstellt, wobei letzte vorläufig mal einfach eine Kopie der sub list_transactions mit kleineren Anpassungen darstellt.

Die Angaben zur URL der kivitendo-Instanz, zum Zeitraum und zum Speicherort der erstellen Dateien müssen momentan noch manuell in die Datei ca.pl eingetragen werden.
Dazu folgende 3 Kommentarzeilen in der abgeänderten ca.pl suchen:
'# Im Link muss 'URL_zur_aktiven_kivitendo_Instanz' durch die entsprechende richtige URL ersetzt werden!'
'# Hier manuell das Jahr eingeben'
'# Der folgende Pfad muss je nach Installationspfad der aktiven kivitendo-Instanz individuell angepasst werden!'

Sind die Änderungen gemacht, so erscheint im Titelbalken ein Link 'CSV-Export alle Konten'. Wenn dieser angeklickt wird, so wird für jedes Konto eine csv-Datei in den eingetragenen Pfad geschrieben.

Wer sich die Änderungen nicht selbst zutraut, kann sich an wenden und uns den Auftrag für eine entsprechende Anpassung erteilen (ca. 2 Stunden Arbeit à 100 Franken).

Wir planen dazu eine Erweiterung für kivitendo mit eigenem Untermenüpunkt zu erstellen, in der der Zeitraum, sowie weitere Einstellungen über das Webinterface von kivitendo konfigurierbar sind. Wer Interesse daran hat und bereit ist, sich an den Kosten zu beteiligen, bitte ein Mail an senden!

Hier der diff zur kivitendo Version 3.5.2 (wer eine andere Version hat, muss unter Umständen entsprechende Anpassungen machen):

diff --git a/bin/mozilla/ca.pl b/bin/mozilla/ca.pl
index 774da85..99e8e53 100644
--- a/bin/mozilla/ca.pl
+++ b/bin/mozilla/ca.pl
@@ -43,6 +43,8 @@ require "bin/mozilla/reportgenerator.pl";

 use strict;

+sub csv_transactions();
+
 1;

 # end of main
@@ -103,6 +105,88 @@ sub chart_of_accounts {

   my $report = SL::ReportGenerator->new(\%myconfig, $form);

+# Provisorischen Link zum Erzeugen des csv-Exports für alle Konten gleichzeitig in den Titel eingefügt
+# Im Link muss 'URL_zur_aktiven_kivitendo_Instanz' durch die entsprechende richtige URL ersetzt werden!
+  $report->set_options('output_format'         => 'HTML',
+                       'title'                 => $form->{title}."&nbsp;&nbsp;&nbsp;<a href='URL_zur_aktiven_kivitendo_Instanz'/ca.pl?action=csvkonten'>CSV-Export alle Konten</a>",
+                       'attachment_basename'   => $locale->text('chart_of_accounts') . strftime('_%Y%m%d', localtime time),
+                       'std_column_visibility' => 1,
+    );
+  $report->set_options_from_form();
+  $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
+
+  $report->set_columns(%column_defs);
+  $report->set_column_order(@columns);
+
+  $report->set_export_options('chart_of_accounts');
+
+  $report->set_sort_indicator($form->{sort}, 1);
+
+  my %totals = ('debit' => 0, 'credit' => 0);
+
+  foreach my $ca (@{ $form->{CA} }) {
+    next unless defined $ca->{amount};
+    my $row = { };
+
+    foreach (qw(debit credit)) {
+      $totals{$_} += $ca->{$_} * 1;
+      $ca->{$_}    = $form->format_amount(\%myconfig, $ca->{$_}, 2) if ($ca->{$_});
+    }
+
+    map { $row->{$_} = { 'data' => $ca->{$_} } } @columns;
+
+    map { $row->{$_}->{align} = 'right'       } qw(debit credit);
+    map { $row->{$_}->{class} = 'listheading' } @columns if ($ca->{charttype} eq "H");
+
+    $row->{accno}->{link} = build_std_url('action=list', 'accno=' . E($ca->{accno}), 'description=' . E($ca->{description}));
+
+    $report->add_data($row);
+  }
+
+  my $row = { map { $_ => { 'class' => 'listtotal', 'align' => 'right' } } @columns };
+  map { $row->{$_}->{data} = $form->format_amount(\%myconfig, $totals{$_}, 2) } qw(debit credit);
+
+  $report->add_separator();
+  $report->add_data($row);
+
+  $report->generate_with_headers();
+
+  $main::lxdebug->leave_sub();
+}
+
+# Neue Subroutine zum Durchlaufen aller Konten, damit von jedem Konto automatisch
+# eine csv-Datei erzeugt werden kann.
+# Diese Subroutine soll in Zukunft von einem neuen Untermenue-Punkt aufgerufen werden,
+# -> muss noch im Menü eingerichtet werden link > ca.pl?action=csvkonten
+
+sub csvkonten {
+  $main::lxdebug->enter_sub();
+
+  my $form     = $main::form;
+  my %myconfig = %main::myconfig;
+  my $locale   = $main::locale;
+
+  $main::auth->assert('report');
+
+  $form->{title} = $locale->text('Chart of Accounts');
+
+  if ( $::instance_conf->get_accounting_method eq 'cash' ) {
+    # $form->{method} can probably be made redundant now that we have get_accounting_method
+    $form->{method} = "cash";
+  }
+
+  CA->all_accounts(\%myconfig, \%$form);
+
+  my @columns     = qw(accno description debit credit);
+  my %column_defs = (
+    'accno'       => { 'text' => $locale->text('Account'), },
+    'description' => { 'text' => $locale->text('Description'), },
+    'debit'       => { 'text' => $locale->text('Debit'), },
+    'credit'      => { 'text' => $locale->text('Credit'), },
+  );
+
+  my $report = SL::ReportGenerator->new(\%myconfig, $form);
+
   $report->set_options('output_format'         => 'HTML',
                        'title'                 => $form->{title},
                        'attachment_basename'   => $locale->text('chart_of_accounts') . strftime('_%Y%m%d', localtime time),
@@ -137,6 +221,10 @@ sub chart_of_accounts {
     $row->{accno}->{link} = build_std_url('action=list', 'accno=' . E($ca->{accno}), 'description=' . E($ca->{description}));

     $report->add_data($row);
+
+    $form->{accno} = $ca->{accno};
+    $form->{description} = $ca->{description};
+    csv_transactions();
   }

   my $row = { map { $_ => { 'class' => 'listtotal', 'align' => 'right' } } @columns };
@@ -573,6 +661,359 @@ sub list_transactions {
   $main::lxdebug->leave_sub();
 }

+# Neue Subroutine fuer den automatischen csv-Export aller Konten
+# Sollte noch von allem Unnoetigen, das aus 'list_transactions' stammt
+# befreit werden.
+
+sub csv_transactions {
+  $main::lxdebug->enter_sub();
+
+  my $form     = $main::form;
+  my %myconfig = %main::myconfig;
+  my $locale   = $main::locale;
+  my $defaults = SL::DB::Default->get;
+
+  $main::auth->assert('report');
+
+# Erstellen der Text-Variable $stringAccount zum schrittweisen
+# Aufbau der csv-Datei. Erst am Ende der Subroutine wird der
+# Inhalt der Variable in eine csv-Datei geschrieben.
+# Wichtig: alle Zeilenumbrueche sind noetig und gewollt!
+# Todo: Das Jahr ist momentan fix auf 2018 gesetzt,
+# muss noch via Eingabe dynamisch gesetzt werden koennen!
+
+  my $stringAccount = $locale->text('Account') . " " . $form->{accno} . " - " . $form->{description} . " 
+;;
+";
+
+  $form->{title} = $locale->text('Account') . " " . $form->{accno} . " - " . $form->{description} . " - csv exportiert";
+
+ # if ($form->{reporttype} eq "custom") {
+
+    #forgotten the year --> thisyear
+    if ($form->{year} !~ m/^\d\d\d\d$/) {
+      $locale->date(\%myconfig, $form->current_date(\%myconfig), 0) =~
+        /(\d\d\d\d)/;
+ #     $form->{year} = $1;
+
+
+ # Hier manuell das Jahr eingeben
+
+      $form->{year} = 2018;
+
+    }
+
+    #yearly report
+
+      $form->{fromdate} = "1.1.$form->{year}";
+      $form->{todate}   = "31.12.$form->{year}";
+      $stringAccount = $stringAccount . "1.1." . $form->{year} ." - 31.12." . $form->{year} . " 
+";
+
+  CA->all_transactions(\%myconfig, \%$form);
+
+  $form->{saldo_old} += $form->{beginning_balance};
+  $form->{saldo_new} += $form->{beginning_balance};
+  my $saldo_old = format_debit_credit($form->{saldo_old});
+  my $eb_string = format_debit_credit($form->{beginning_balance});
+   $form->{balance} = $form->{saldo_old};
+
+  my @options;
+  if ($form->{department}) {
+    my ($department) = split /--/, $form->{department};
+     push @options, $locale->text('Department') . " : $department";
+  }
+  if ($form->{projectnumber}) {
+     push @options, $locale->text('Project Number') . " : $form->{projectnumber}<br>";
+  }
+
+  my $period;
+  if ($form->{fromdate} || $form->{todate}) {
+    my ($fromdate, $todate);
+
+    if ($form->{fromdate}) {
+      $fromdate = $locale->date(\%myconfig, $form->{fromdate}, 1);
+    }
+    if ($form->{todate}) {
+      $todate = $locale->date(\%myconfig, $form->{todate}, 1);
+    }
+
+    $period = "$fromdate - $todate";
+
+  } else {
+    $period = $locale->date(\%myconfig, $form->current_date(\%myconfig), 1);
+  }
+
+   push @options, $period;
+
+  # $form->{print_date} = $locale->text('Create Date') . " " . $locale->date(\%myconfig, $form->current_date(\%myconfig), 0);
+   push (@options, $form->{print_date});
+
+  $stringAccount = $stringAccount . $locale->text('Create Date') . " " . $locale->date(\%myconfig, $form->current_date(\%myconfig), 0) . " 
+";
+
+  # $form->{company} = $locale->text('Company') . " " . $defaults->company;
+   push (@options, $form->{company});
+
+  $stringAccount = $stringAccount . $locale->text('Company') . " " . $defaults->company . " 
+;;
+";
+
+  my @columns     = qw(transdate reference description gegenkonto debit credit ustkonto ustrate balance);
+  my %column_defs = (
+    'transdate'   => { 'text' => $locale->text('Date'), },
+    'reference'   => { 'text' => $locale->text('Reference'), },
+    'description' => { 'text' => $locale->text('Description'), },
+    'debit'       => { 'text' => $locale->text('Debit'), },
+    'credit'      => { 'text' => $locale->text('Credit'), },
+    'gegenkonto'  => { 'text' => $locale->text('Gegenkonto'), },
+    'ustkonto'    => { 'text' => $locale->text('USt-Konto'), },
+    'balance'     => { 'text' => $locale->text('Balance'), },
+    'ustrate'     => { 'text' => $locale->text('Satz %'), },
+ );
+
+  my @hidden_variables = qw(accno fromdate todate description accounttype l_heading subtotal department projectnumber project_id sort method);
+
+  #~ my $link = build_std_url('action=list_transactions', grep { $form->{$_} } @hidden_variables);
+
+  #~ $form->{callback} = $link . '&sort=' . E($form->{sort});
+
+  my %column_alignment = map { $_ => 'right' } qw(debit credit balance);
+
+  my @custom_headers = ();
+ # Zeile 1:
+  # push @custom_headers, [
+    # { 'text' => 'Letzte Buchung', },
+    # { 'text' => 'EB-Wert', },
+   # { 'text' => 'Saldo alt', 'colspan' => 2, },
+    # { 'text' => 'Jahresverkehrszahlen alt', 'colspan' => 2, },
+   # { 'text' => '', 'colspan' => 2, },
+  # ];
+ $stringAccount = $stringAccount . "Letzte Buchung;EB-Wert;Saldo alt;;Jahresverkehrszahlen alt
+";
+
+  push @custom_headers, [
+    { 'text' => $form->{last_transaction}, },
+    { 'text' => $eb_string, },
+    { 'text' => $saldo_old, 'colspan' => 2, },
+    { 'text' => $form->format_amount(\%myconfig, abs($form->{old_balance_debit}), 2) . " S", },
+    { 'text' => $form->format_amount(\%myconfig, $form->{old_balance_credit}, 2) . " H", },
+    { 'text' => '', 'colspan' => 2, },
+  ];
+ $stringAccount = $stringAccount . $form->{last_transaction} . ";" . $eb_string . ";" . $saldo_old . ";;" . $form->format_amount(\%myconfig, abs($form->{old_balance_debit}), 2) . " S;" . $form->format_amount(\%myconfig, $form->{old_balance_credit}, 2) . " H
+;;
+";
+
+ # Zeile 2:
+  # push @custom_headers, [
+    # { 'text' => $locale->text('Date'), 'link' => $link . "&sort=transdate", },
+    # { 'text' => $locale->text('Reference'), 'link' => $link . "&sort=reference",  },
+    # { 'text' => $locale->text('Description'), 'link' => $link . "&sort=description",  },
+    # { 'text' => $locale->text('Gegenkonto'), },
+    # { 'text' => $locale->text('Debit'), },
+    # { 'text' => $locale->text('Credit'), },
+    # { 'text' => $locale->text('USt-Konto'), },
+    # { 'text' => $locale->text('Satz %'), },
+    # { 'text' => $locale->text('Balance'), },
+  # ];
+ $stringAccount = $stringAccount . $locale->text('Date') . ";" . $locale->text('Reference') . ";" . $locale->text('Description') . ";" . $locale->text('Gegenkonto') . ";" . $locale->text('Debit') . ";" . $locale->text('Credit') . ";" . $locale->text('USt-Konto') . ";" . $locale->text('Satz %') . ";" . $locale->text('Balance') . " 
+";
+
+   my $report = SL::ReportGenerator->new(\%myconfig, $form);
+  # $report->set_custom_headers(@custom_headers);
+
+  $report->set_options('top_info_text'         => join("\n", @options),
+                       'output_format'         => 'HTML',
+                       'title'                 => $form->{title},
+                       # 'attachment_basename'   => $locale->text('list_of_transactions') . strftime('_%Y%m%d', localtime time),
+                       'std_column_visibility' => 0,
+    );
+  # $report->set_options_from_form();
+  $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
+
+  # $report->set_columns(%column_defs);
+  # $report->set_column_order(@columns);
+
+  # $report->set_export_options('list_transactions', @hidden_variables);
+
+  # $report->set_sort_indicator($form->{sort}, 1);
+
+  $column_defs{balance}->{visible} = 1;
+
+  my $ml = ($form->{category} =~ /(A|E)/) ? -1 : 1;
+
+  my $idx       = 0;
+  my %totals    = ( 'debit' => 0, 'credit' => 0 );
+  my %subtotals = ( 'debit' => 0, 'credit' => 0 );
+  my ($previous_index, $row_set);
+
+  foreach my $ca (@{ $form->{CA} }) {
+
+    foreach (qw(debit credit)) {
+      $subtotals{$_} += $ca->{$_};
+      $totals{$_}    += $ca->{$_};
+      if ($_ =~ /debit.*/) {
+        $ml = -1;
+      } else {
+        $ml = 1;
+      }
+      $form->{balance}= $form->{balance} + $ca->{$_} * $ml;
+      $ca->{$_}       = $form->format_amount(\%myconfig, $ca->{$_}, 2) if ($ca->{$_} != 0);
+    }
+
+    my $do_subtotal = 0;
+    if (($form->{subtotal})
+        && (($idx == scalar @{ $form->{CA} } - 1)
+            || ($ca->{$form->{sort}} ne $form->{CA}->[$idx + 1]->{$form->{sort}}))) {
+      $do_subtotal = 1;
+    }
+
+    my $row = { };
+
+    $ca->{ustrate} = $form->format_amount(\%myconfig, $ca->{ustrate} * 100, 2) if ($ca->{ustrate} != 0);
+
+# Beschreibung immer auf einer Zeile ausgeben:
+    my $description = $ca->{description} . " " . $ca->{memo};
+
+#    if ($ca->{memo} ne "") {
+#      $ca->{description} .= " \n " . $ca->{memo};
+#    }
+
+    foreach my $gegenkonto (@{ $ca->{GEGENKONTO} }) {
+      if ($ca->{gegenkonto} eq "") {
+        $ca->{gegenkonto} = $gegenkonto->{accno};
+      } else {
+        $ca->{gegenkonto} .= ", " . $gegenkonto->{accno};
+      }
+    }
+
+    foreach (@columns) {
+      $row->{$_} = {
+        'data'  => $ca->{$_},
+        'align' => $column_alignment{$_},
+      };
+    }
+
+    $row->{balance}->{data}        = $form->format_amount(\%myconfig, $form->{balance}, 2, 'DRCR');
+
+    if ($ca->{index} ne $previous_index) {
+#       $report->add_data($row_set) if ($row_set);
+
+#       $row_set         = [ ];
+      $previous_index  = $ca->{index};
+
+      $row->{reference}->{link} = build_std_url("script=$ca->{module}.pl", 'action=edit', 'id=' . E($ca->{id}), 'callback');
+
+    } elsif ($ca->{index} eq $previous_index) {
+      map { $row->{$_}->{data} = '' } qw(reference description);
+      $row->{transdate}->{data} = '' if ($form->{sort} eq 'transdate');
+    }
+
+    my $row_set = [];
+
+    #~ push @{ $row_set }, $row;
+
+    #~ push @{ $row_set }, create_subtotal_row(\%subtotals, \@columns, \%column_alignment, 'listsubtotal') if ($do_subtotal);
+
+    $stringAccount = $stringAccount . $ca->{transdate} . ";" . $ca->{reference} . ";" . $description . ";" . $ca->{gegenkonto} . ";" . $ca->{debit} . ";" . $ca->{credit} . ";" . $ca->{ustkonto} . ";" . $ca->{ustrate} . ";" . $row->{balance}->{data} ." 
+";
+
+    $idx++;
+    # $report->add_data($row_set);
+
+  }
+
+  # $report->add_data($row_set) if ($row_set);
+
+  # $report->add_separator();
+
+  my $row = create_subtotal_row(\%totals, \@columns, \%column_alignment, 'listtotal');
+
+  $row->{balance}->{data}        = $form->format_amount(\%myconfig, $form->{balance}, 2, 'DRCR');
+
+  $report->add_data($row);
+
+  $stringAccount = $stringAccount . "Total;;;;" . $form->format_amount(\%myconfig, abs($form->{current_balance_debit}) , 2) . ";" . $form->format_amount(\%myconfig, $form->{current_balance_credit}, 2) . ";;;" . format_debit_credit($form->{saldo_new}) . " 
+";
+
+  # $report->add_separator();
+  #~ $row = {
+     #~ 'transdate' => {
+       #~ 'data'    => "",
+       #~ 'class' => 'listtotal',
+     #~ },
+     #~ 'reference' => {
+       #~ 'data'    => $locale->text('EB-Wert'),
+       #~ 'class' => 'listtotal',
+     #~ },
+     #~ 'description'      => {
+       #~ 'data'    => $locale->text('Saldo neu'),
+       #~ 'colspan' => 2,
+       #~ 'class' => 'listtotal',
+     #~ },
+     #~ 'debit'      => {
+       #~ 'data'    => $locale->text('Jahresverkehrszahlen neu'),
+       #~ 'colspan' => 2,
+       #~ 'align' => 'left',
+       #~ 'class' => 'listtotal',
+    #~ },
+     #~ 'ustkonto'      => {
+       #~ 'data'    => '',
+       #~ 'colspan' => 2,
+       #~ 'align' => 'left',
+       #~ 'class' => 'listtotal',
+    #~ },
+  #~ };
+
+  $stringAccount = $stringAccount . ";" . $locale->text('EB-Wert') . ";" . $locale->text('Saldo neu') . ";;" . $locale->text('Jahresverkehrszahlen neu') . " 
+";
+  # $report->add_data($row);
+  my $saldo_new = format_debit_credit($form->{saldo_new});
+  #~ $row = {
+     #~ 'transdate' => {
+       #~ 'data'    => "",
+       #~ 'class' => 'listtotal',
+     #~ },
+     #~ 'reference' => {
+       #~ 'data'    => $eb_string,
+       #~ 'class' => 'listtotal',
+     #~ },
+     #~ 'description'      => {
+       #~ 'data'    => $saldo_new,
+       #~ 'colspan' => 2,
+       #~ 'class' => 'listtotal',
+     #~ },
+     #~ 'debit'      => {
+       #~ 'data'    => $form->format_amount(\%myconfig, abs($form->{current_balance_debit}) , 2) . " S",
+       #~ 'class' => 'listtotal',
+     #~ },
+      #~ 'credit'      => {
+       #~ 'data'    => $form->format_amount(\%myconfig, $form->{current_balance_credit}, 2) . " H",
+       #~ 'class' => 'listtotal',
+     #~ },
+      #~ 'ustkonto'      => {
+       #~ 'data'    => "",
+       #~ 'colspan' => 2,
+       #~ 'class' => 'listtotal',
+     #~ },
+  #~ };
+
+  $stringAccount = $stringAccount . ";" . $eb_string . ";" . $saldo_new . ";;" . $form->format_amount(\%myconfig, abs($form->{current_balance_debit}) , 2) . " S;" . $form->format_amount(\%myconfig, $form->{current_balance_credit}, 2) . " H
+;;";
+
+  # $stringAccount in Datei schreiben
+  # Der folgende Pfad muss je nach Installationspfad der aktiven kivitendo-Instanz individuell angepasst werden!
+  open ACFILE, ">/var/www/kivitendo-erp/webdav/" . $locale->text('Account') . "_" . $form->{accno} .".csv";
+  print ACFILE $stringAccount;
+  close ACFILE;
+
+  $report->add_data($row);
+
+  $report->generate_with_headers();
+
+  $main::lxdebug->leave_sub();
+}
+
 sub create_subtotal_row {
   $main::lxdebug->enter_sub();