Merge branch 'test' of ../kivitendo-erp_20220811
[kivitendo-erp.git] / bin / mozilla / rp.pl
index 01ae84f..630a2b5 100644 (file)
@@ -28,7 +28,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.
 #======================================================================
 #
 # module for preparing Income Statement and Balance Sheet
 
 use POSIX qw(strftime);
 
-use SL::PE;
+use SL::DB::Default;
+use SL::DB::Project;
+use SL::DB::Customer;
 use SL::RP;
 use SL::Iconv;
+use SL::Locale::String qw(t8);
+use SL::Presenter::Tag;
 use SL::ReportGenerator;
 use Data::Dumper;
+use List::MoreUtils qw(any);
 
-require "bin/mozilla/arap.pl";
 require "bin/mozilla/common.pl";
 require "bin/mozilla/reportgenerator.pl";
 
@@ -92,22 +97,22 @@ use strict;
 # $locale->text('Receipts')
 # $locale->text('Payments')
 # $locale->text('Project Transactions')
-# $locale->text('Non-taxable Sales')
-# $locale->text('Non-taxable Purchases')
 # $locale->text('Business evaluation')
+# $locale->text('Final Invoice, please use mark as paid manually')
 
 # $form->parse_html_template('rp/html_report_susa')
 
 my $rp_access_map = {
-  'projects'         => 'report',
-  'ar_aging'         => 'general_ledger',
-  'ap_aging'         => 'general_ledger',
-  'receipts'         => 'cash',
-  'payments'         => 'cash',
-  'trial_balance'    => 'report',
-  'income_statement' => 'report',
-  'bwa'              => 'report',
-  'balance_sheet'    => 'report',
+  'projects'           => 'report',
+  'ar_aging'           => 'general_ledger',
+  'ap_aging'           => 'general_ledger',
+  'receipts'           => 'cash',
+  'payments'           => 'cash',
+  'trial_balance'      => 'report',
+  'income_statement'   => 'report',
+  'erfolgsrechnung'    => 'report',
+  'bwa'                => 'report',
+  'balance_sheet'      => 'report',
 };
 
 sub check_rp_access {
@@ -127,13 +132,12 @@ sub report {
   my %title = (
     balance_sheet        => $::locale->text('Balance Sheet'),
     income_statement     => $::locale->text('Income Statement'),
+    erfolgsrechnung      => $::locale->text('Erfolgsrechnung'),
     trial_balance        => $::locale->text('Trial Balance'),
     ar_aging             => $::locale->text('Search AR Aging'),
     ap_aging             => $::locale->text('Search AP Aging'),
     tax_collected        => $::locale->text('Tax collected'),
     tax_paid             => $::locale->text('Tax paid'),
-    nontaxable_sales     => $::locale->text('Non-taxable Sales'),
-    nontaxable_purchases => $::locale->text('Non-taxable Purchases'),
     receipts             => $::locale->text('Receipts'),
     payments             => $::locale->text('Payments'),
     projects             => $::locale->text('Project Transactions'),
@@ -141,6 +145,10 @@ sub report {
   );
 
   $::form->{title} = $title{$::form->{report}};
+  $::request->{layout}->add_javascripts('kivi.CustomerVendor.js');
+  $::request->{layout}->add_javascripts('autocomplete_project.js');
+  $::form->{fromdate} = DateTime->today->truncate(to => 'year')->to_kivitendo;
+  $::form->{todate} = DateTime->today->truncate(to => 'year')->add(years => 1)->add(days => -1)->to_kivitendo;
 
   # get departments
   $::form->all_departments(\%::myconfig);
@@ -151,26 +159,15 @@ sub report {
 
   $::form->get_lists("projects" => { "key" => "ALL_PROJECTS", "all" => 1 });
 
-  my $onload = qq|focus()|;
-
-  my $is_projects         = $::form->{report} eq "projects";
-  my $is_income_statement = $::form->{report} eq "income_statement";
-  my $is_bwa              = $::form->{report} eq "bwa";
-  my $is_balance_sheet    = $::form->{report} eq "balance_sheet";
-  my $is_trial_balance    = $::form->{report} eq "trial_balance";
-  my $is_taxreport        = $::form->{report} =~ /^tax_/;
-  my $is_nontaxable       = $::form->{report} =~ /^nontaxable_/;
-  my $is_aging            = $::form->{report} =~ /^a[rp]_aging$/;
-  my $is_payments         = $::form->{report} =~ /(receipts|payments)$/;
-
-#  if (is_taxreport) {
-#    $::form->{db} = ($::form->{report} =~ /_collected/) ? "ar" : "ap";
-#    RP->get_taxaccounts(\%::myconfig, $::form);
-#  }
-#
-#  if ($is_nontaxable) {
-#    $::form->{db} = ($::form->{report} =~ /_sales/) ? "ar" : "ap";
-#  }
+  my $is_projects            = $::form->{report} eq "projects";
+  my $is_income_statement    = $::form->{report} eq "income_statement";
+  my $is_erfolgsrechnung     = $::form->{report} eq "erfolgsrechnung";
+  my $is_bwa                 = $::form->{report} eq "bwa";
+  my $is_balance_sheet       = $::form->{report} eq "balance_sheet";
+  my $is_trial_balance       = $::form->{report} eq "trial_balance";
+  my $is_aging               = $::form->{report} =~ /^a[rp]_aging$/;
+  my $is_payments            = $::form->{report} =~ /(receipts|payments)$/;
+  my $format                 = 'html';
 
   my ($label, $nextsub, $vc);
   if ($is_aging) {
@@ -180,12 +177,9 @@ sub report {
 
     $nextsub = "generate_$::form->{report}";
 
-    # setup vc selection
-    $::form->all_vc(\%::myconfig, $::form->{vc}, $is_sales ? "AR" : "AP");
-    $vc .= "<option>$_->{name}--$_->{id}\n" for @{ $::form->{"all_$::form->{vc}"} };
-    $vc = ($vc)
-        ? qq|<select name=$::form->{vc}><option>\n$vc</select>|
-        : qq|<input name=$::form->{vc} size=35>|;
+    $vc = qq|<input name=$::form->{vc} size=35 class="initial_focus">|;
+
+    $format = 'pdf';
   }
 
   my ($selection, $paymentaccounts);
@@ -201,24 +195,26 @@ sub report {
     }
   }
 
+  setup_rp_report_action_bar();
+
   $::form->header;
   print $::form->parse_html_template('rp/report', {
-    paymentaccounts     => $paymentaccounts,
-    selection           => $selection,
-    is_aging            => $is_aging,
-    vc                  => $vc,
-    label               => $label,
-    year                => DateTime->today->year,
-    onload              => $onload,
-    nextsub             => $nextsub,
-    accrual             => $::instance_conf->get_accounting_method ne 'cash',
-    cash                => $::instance_conf->get_accounting_method eq 'cash',
-    is_payments         => $is_payments,
-    is_trial_balance    => $is_trial_balance,
-    is_balance_sheet    => $is_balance_sheet,
-    is_bwa              => $is_bwa,
-    is_income_statement => $is_income_statement,
-    is_projects         => $is_projects,
+    paymentaccounts        => $paymentaccounts,
+    selection              => $selection,
+    is_aging               => $is_aging,
+    vc                     => $vc,
+    label                  => $label,
+    year                   => DateTime->today->year,
+    today                  => DateTime->today,
+    nextsub                => $nextsub,
+    is_payments            => $is_payments,
+    is_trial_balance       => $is_trial_balance,
+    is_balance_sheet       => $is_balance_sheet,
+    is_bwa                 => $is_bwa,
+    is_income_statement    => $is_income_statement,
+    is_erfolgsrechnung     => $is_erfolgsrechnung,
+    is_projects            => $is_projects,
+    format                 => $format,
   });
 
   $::lxdebug->leave_sub;
@@ -226,35 +222,6 @@ sub report {
 
 sub continue { call_sub($main::form->{"nextsub"}); }
 
-sub get_project {
-  $main::lxdebug->enter_sub();
-
-  $main::auth->assert('report');
-
-  my $form     = $main::form;
-  my %myconfig = %main::myconfig;
-  my $locale   = $main::locale;
-
-  my $nextsub = shift;
-
-  $form->{project_id} = $form->{project_id_1};
-  if ($form->{projectnumber} && !$form->{project_id}) {
-    $form->{rowcount} = 1;
-
-    # call this instead of update
-    $form->{update}          = $nextsub;
-    $form->{projectnumber_1} = $form->{projectnumber};
-
-    delete $form->{sort};
-    check_project('generate_projects');
-
-    # if there is one only, assign id
-    $form->{project_id} = $form->{project_id_1};
-  }
-
-  $main::lxdebug->leave_sub();
-}
-
 sub generate_income_statement {
   $main::lxdebug->enter_sub();
 
@@ -414,19 +381,49 @@ sub generate_income_statement {
       . qq| $longcomparetodate|;
   }
 
-  # setup variables for the form
-  my @a = qw(company address businessnumber);
-  map { $form->{$_} = $myconfig{$_} } @a;
+  if ( $::instance_conf->get_profit_determination eq 'balance' ) {
+    $form->{title} = $locale->text('Income Statement');
+  } elsif ( $::instance_conf->get_profit_determination eq 'income' ) {
+    $form->{title} = $locale->text('Net Income Statement');
+  } else {
+    $form->{title} = "";
+  };
 
-  $form->{templates} = $myconfig{templates};
+  if ( $form->{method} eq 'cash' ) {
+    $form->{accounting_method} = $locale->text('Cash accounting');
+  } elsif ( $form->{method} eq 'accrual' ) {
+    $form->{accounting_method} = $locale->text('Accrual accounting');
+  } else {
+    $form->{accounting_method} = "";
+  };
 
-  $form->{IN} = "income_statement.html";
+  $form->{report_date} = $locale->text('Report date') . ": " . $form->current_date;
 
-  $form->parse_template;
+  $form->header;
+  print $form->parse_html_template('rp/income_statement');
 
   $main::lxdebug->leave_sub();
 }
 
+sub generate_erfolgsrechnung {
+  $::lxdebug->enter_sub;
+  $::auth->assert('report');
+
+  $::form->{decimalplaces} = $::form->{decimalplaces} * 1 || 2;
+  $::form->{padding}       = "&emsp;";
+  $::form->{bold}          = "<b>";
+  $::form->{endbold}       = "</b>";
+  $::form->{br}            = "<br>";
+
+  my $data = RP->erfolgsrechnung(\%::myconfig, $::form);
+
+  $::form->header();
+  print $::form->parse_html_template('rp/erfolgsrechnung', $data);
+
+  $::lxdebug->leave_sub;
+}
+
+
 sub generate_balance_sheet {
   $::lxdebug->enter_sub;
   $::auth->assert('report');
@@ -439,8 +436,9 @@ sub generate_balance_sheet {
 
   my $data = RP->balance_sheet(\%::myconfig, $::form);
 
-  $::form->{asofdate} ||= $::form->current_date;
-  $::form->{period}     = $::locale->date(\%::myconfig, $::form->current_date, 1);
+  $::form->{asofdate}    ||= $::form->current_date;
+  $::form->{report_title}  = $::locale->text('Balance Sheet');
+  $::form->{report_date} ||= $::form->current_date;
 
   ($::form->{department}) = split /--/, $::form->{department};
 
@@ -451,13 +449,10 @@ sub generate_balance_sheet {
   $::form->{this_period} = $::locale->date(\%::myconfig, $::form->{asofdate}, 0);
   $::form->{last_period} = $::locale->date(\%::myconfig, $::form->{compareasofdate}, 0);
 
+#  balance sheet isn't read from print templates anymore,
+#  instead use template in rp
 #  $::form->{IN} = "balance_sheet.html";
 
-  # setup company variables for the form
-  map { $::form->{$_} = $::myconfig{$_} } qw(company address businessnumber nativecurr);
-
-  $::form->{templates} = $::myconfig{templates};
-
   $::form->header;
   print $::form->parse_html_template('rp/balance_sheet', $data);
 
@@ -473,8 +468,20 @@ sub generate_projects {
   my %myconfig = %main::myconfig;
   my $locale   = $main::locale;
 
-  &get_project("generate_projects");
-  $form->{projectnumber} = $form->{projectnumber_1};
+  my $project            = $form->{project_id} ? SL::DB::Project->new(id => $form->{project_id})->load : undef;
+  $form->{projectnumber} = $project ? $project->projectnumber : '';
+
+  # make sure todate and fromdate always have a value, even if the date fields
+  # were left empty or the inputs weren't valid dates/couldn't be parsed
+
+  $project = SL::DB::Project->new() unless $project;  # dummy object for dbh
+  unless ($::locale->parse_date_to_object($::form->{fromdate})) {
+    ($form->{fromdate}) = $project->db->dbh->selectrow_array('select min(transdate) from acc_trans');
+  };
+
+  unless ($::locale->parse_date_to_object($::form->{todate})) {
+    ($form->{todate})   = $project->db->dbh->selectrow_array('select max(transdate) from acc_trans');
+  };
 
   $form->{nextsub} = "generate_projects";
   $form->{title}   = $locale->text('Project Transactions');
@@ -499,6 +506,7 @@ sub generate_trial_balance {
   my $form     = $main::form;
   my %myconfig = %main::myconfig;
   my $locale   = $main::locale;
+  my $defaults = SL::DB::Default->get;
 
   if ($form->{reporttype} eq "custom") {
 
@@ -623,7 +631,7 @@ sub generate_trial_balance {
   my $attachment_basename = $locale->text('trial_balance');
   my $report              = SL::ReportGenerator->new(\%myconfig, $form);
 
-  my @hidden_variables    = qw(fromdate todate year cash);
+  my @hidden_variables    = qw(fromdate todate year method department_id all_accounts);
 
   my $href                = build_std_url('action=generate_trial_balance', grep { $form->{$_} } @hidden_variables);
 
@@ -655,17 +663,44 @@ sub generate_trial_balance {
   my @options;
 
 
-  $form->{template_fromto} = $locale->date(\%myconfig, $form->{fromdate}, 0) . "&nbsp; - &nbsp;" . $locale->date(\%myconfig, $form->{todate}, 0);
+  $form->{template_fromto} = $locale->date(\%myconfig, $form->{fromdate}, 0) . " - " . $locale->date(\%myconfig, $form->{todate}, 0);
 
   $form->{print_date} = $locale->text('Create Date') . " " . $locale->date(\%myconfig, $form->current_date(\%myconfig), 0);
   push (@options, $form->{print_date});
 
-  $form->{company} = $locale->text('Company') . " " . $myconfig{company};
+  $form->{company} = $locale->text('Company') . " " . $defaults->company;
   push (@options, $form->{company});
 
+  if ($::form->{customer_id}) {
+    my $customer = SL::DB::Manager::Customer->find_by(id => $::form->{customer_id});
+    push @options, $::locale->text('Customer') . ' ' . $customer->displayable_name;
+  }
+
 
   $form->{template_to} = $locale->date(\%myconfig, $form->{todate}, 0);
 
+  my @custom_headers = ([
+    { text => $::locale->text('Account'),          rowspan => 2, },
+    { text => $::locale->text('Description'),      rowspan => 2, },
+    { text => $::locale->text('Last Transaction'), rowspan => 2, },
+    { text => $::locale->text('Starting Balance'), colspan => 2, },
+    { text => $::locale->text('Sum for')   . " $form->{template_fromto}", colspan => 2, },
+    { text => $::locale->text('Sum per')   . " $form->{template_to}",     colspan => 2, },
+    { text => $::locale->text('Saldo per') . " $form->{template_to}",     colspan => 2, },
+  ], [
+    { text => '', },
+    { text => '', },
+    { text => '', },
+    { text => $::locale->text('Assets'), },
+    { text => $::locale->text('Equity'), },
+    { text => $::locale->text('Debit'),  },
+    { text => $::locale->text('Credit'), },
+    { text => $::locale->text('Debit'),  },
+    { text => $::locale->text('Credit'), },
+    { text => $::locale->text('Debit'),  },
+    { text => $::locale->text('Credit'), },
+  ]);
+
   $report->set_options('output_format'        => 'HTML',
                        'top_info_text'        => join("\n", @options),
                        'title'                => $form->{title},
@@ -673,6 +708,7 @@ sub generate_trial_balance {
                        'html_template'        => 'rp/html_report_susa',
                        'pdf_template'         => 'rp/html_report_susa',
     );
+  $report->set_custom_headers(@custom_headers);
   $report->set_options_from_form();
   $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
 
@@ -895,7 +931,7 @@ sub list_accounts {
 sub generate_ar_aging {
   $main::lxdebug->enter_sub();
 
-  $main::auth->assert('general_ledger');
+  $main::auth->assert('general_ledger | ar_transactions');
 
   my $form     = $main::form;
   my %myconfig = %main::myconfig;
@@ -918,7 +954,7 @@ sub generate_ar_aging {
 sub generate_ap_aging {
   $main::lxdebug->enter_sub();
 
-  $main::auth->assert('general_ledger');
+  $main::auth->assert('general_ledger | ap_transactions');
 
   my $form     = $main::form;
   my %myconfig = %main::myconfig;
@@ -971,26 +1007,27 @@ sub aging {
 
   my $report = SL::ReportGenerator->new(\%myconfig, $form);
 
-  my @columns = qw(statement ct invnumber transdate duedate amount open);
-
+  my @columns = qw(statement ct invnumber transdate duedate amount open datepaid current_open type);
   my %column_defs = (
-    'statement' => { 'text' => '', 'visible' => $form->{ct} eq 'customer' ? 'HTML' : 0, },
+    'statement' => { raw_header_data => SL::Presenter::Tag::checkbox_tag("checkall", checkall => '[name^=statement_]'), 'visible' => $form->{ct} eq 'customer' ? 'HTML' : 0, align => "center" },
     'ct'        => { 'text' => $form->{ct} eq 'customer' ? $locale->text('Customer') : $locale->text('Vendor'), },
     'invnumber' => { 'text' => $locale->text('Invoice'), },
     'transdate' => { 'text' => $locale->text('Date'), },
     'duedate'   => { 'text' => $locale->text('Due'), },
     'amount'    => { 'text' => $locale->text('Amount'), },
     'open'      => { 'text' => $locale->text('Open'), },
+    'datepaid'  => { 'text' => $locale->text('Date of Last Payment'), visible => ($form->{reporttype} eq 'custom') },
+    'current_open' => { 'text' => $locale->text('Open Amount at Last Payment Date'), visible => ($form->{reporttype} eq 'custom') },
+    'type'      => { 'text' => $locale->text('Note'), },
   );
 
   my %column_alignment = ('statement' => 'center',
-                          map { $_ => 'right' } qw(open amount));
+                          map { $_ => 'right' } qw(open amount current_open datepaid));
 
   $report->set_options('std_column_visibility' => 1);
   $report->set_columns(%column_defs);
   $report->set_column_order(@columns);
-
-  my @hidden_variables = qw(todate customer vendor arap title ct);
+  my @hidden_variables = qw(todate customer vendor arap title ct fordate reporttype department fromdate);
   $report->set_export_options('generate_' . ($form->{arap} eq 'ar' ? 'ar' : 'ap') . '_aging', @hidden_variables);
 
   my @options;
@@ -1014,10 +1051,20 @@ sub aging {
     $form->{title} = sprintf($locale->text('Ap aging on %s'), $form->{todate});
   }
 
-  if ($form->{fromdate}) {
-    push @options, $locale->text('for Period') . " " . $locale->text('From') . " " .$locale->date(\%myconfig, $form->{fromdate}, 1) . " " . $locale->text('Bis') . " " . $locale->date(\%myconfig, $form->{todate}, 1);
+  $form->{callback} .= "&reporttype=" . E($form->{reporttype});
+  if ($form->{reporttype} eq 'free') {
+    if ($form->{fromdate}) {
+      push @options, $locale->text('for Period') . " " . $locale->text('From') . " " .
+      $locale->date(\%myconfig, $form->{fromdate}, 1) . " "                          .
+      $locale->text('Bis') . " " . $locale->date(\%myconfig, $form->{todate}, 1);
+    } else {
+      push @options, $locale->text('for Period') . " " . $locale->text('Bis') . " " .
+      $locale->date(\%myconfig, $form->{todate}, 1);
+    }
+  } elsif ($form->{reporttype} eq 'custom') {
+    push @options, $locale->text('Reference day') . " " . $locale->date(\%myconfig, $form->{fordate}, 1);
   } else {
-    push @options, $locale->text('for Period') . " " . $locale->text('Bis') . " " . $locale->date(\%myconfig, $form->{todate}, 1);
+    die "Unknown reporttype for aging";
   }
 
   $attachment_basename = $form->{ct} eq 'customer' ? $locale->text('ar_aging_list') : $locale->text('ap_aging_list');
@@ -1032,7 +1079,7 @@ sub aging {
 
   my $previous_ctid = 0;
   my $row_idx       = 0;
-  my @periods       = qw(open amount);
+  my @periods       = qw(open amount current_open);
   my %subtotals     = map { $_ => 0 } @periods;
   my %totals        = map { $_ => 0 } @periods;
 
@@ -1058,6 +1105,12 @@ sub aging {
     }
 
     $row->{invnumber}->{link} =  build_std_url("script=$ref->{module}.pl", 'action=edit', 'callback', 'id=' . E($ref->{id}));
+    if ($row->{type}->{data} eq 'final_invoice') {
+      $row->{type}->{data} = $locale->text('Final Invoice, please use mark as paid manually');
+      $row->{type}->{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'callback', 'id=' . E($ref->{id}));
+    } else {
+      $row->{type}->{data} = '';
+    }
 
     if ($previous_ctid != $ref->{ctid}) {
       $row->{statement}->{raw_data} =
@@ -1085,63 +1138,12 @@ sub aging {
                          'raw_bottom_info_text' => $raw_bottom_info_text);
   }
 
+  setup_rp_aging_action_bar(arap => $form->{arap});
   $report->generate_with_headers();
 
   $main::lxdebug->leave_sub();
 }
 
-sub select_all {
-  $main::lxdebug->enter_sub();
-
-  my $form     = $main::form;
-  my %myconfig = %main::myconfig;
-  my $locale   = $main::locale;
-
-  RP->aging(\%myconfig, \%$form);
-
-  map { $_->{checked} = "checked" } @{ $form->{AG} };
-
-  &aging;
-
-  $main::lxdebug->leave_sub();
-}
-
-sub e_mail {
-  $::lxdebug->enter_sub;
-  $::auth->assert('general_ledger');
-
-  # get name and email addresses
-  my $selected = 0;
-  for my $i (1 .. $::form->{rowcount}) {
-    next unless $::form->{"statement_$i"};
-    $::form->{"$::form->{ct}_id"} = $::form->{"$::form->{ct}_id_$i"};
-    RP->get_customer(\%::myconfig, $::form);
-    $selected = 1;
-    last;
-  }
-
-  $::form->error($::locale->text('Nothing selected!')) unless $selected;
-
-  $::form->{media} = "email";
-
-  # save all other variables
-  my @hidden_values;
-  for my $key (keys %$::form) {
-    next if any { $key eq $_ } qw(login password action email cc bcc subject message type sendmode format header);
-    next unless '' eq ref $::form->{$key};
-    push @hidden_values, $key;
-  }
-
-  $::form->header;
-  print $::form->parse_html_template('rp/e_mail', {
-    show_bcc      => $::auth->assert('email_bcc', 'may fail'),
-    print_options => print_options(inline => 1),
-    hidden_values => \@hidden_values,
-  });
-
-  $::lxdebug->leave_sub;
-}
-
 sub send_email {
   $main::lxdebug->enter_sub();
 
@@ -1156,8 +1158,11 @@ sub send_email {
 
   RP->aging(\%myconfig, \%$form);
 
-  $form->{"statement_1"} = 1;
 
+  my $email_form  = delete $form->{email_form};
+  my %field_names = (to => 'email');
+
+  $form->{ $field_names{$_} // $_ } = $email_form->{$_} for keys %{ $email_form };
   $form->{media} = 'email';
   print_form();
 
@@ -1216,9 +1221,11 @@ sub print_form {
   my %myconfig = %main::myconfig;
   my $locale   = $main::locale;
 
-  $form->{statementdate} = $locale->date(\%myconfig, $form->{todate}, 1);
+  my $defaults = SL::DB::Default->get;
+  $form->error($::locale->text('No print templates have been created for this client yet. Please do so in the client configuration.')) if !$defaults->templates;
+  $form->{templates} = $defaults->templates;
 
-  $form->{templates} = "$myconfig{templates}";
+  $form->{statementdate} = $locale->date(\%myconfig, $form->{todate}, 1);
 
   my $suffix = "html";
   my $attachment_suffix = "html";
@@ -1349,259 +1356,138 @@ sub statement_details {
 }
 
 sub generate_tax_report {
-  $main::lxdebug->enter_sub();
-
-  $main::auth->assert('report');
-
-  my $form     = $main::form;
-  my %myconfig = %main::myconfig;
-  my $locale   = $main::locale;
+  $::lxdebug->enter_sub;
+  $::auth->assert('report');
 
-  RP->tax_report(\%myconfig, \%$form);
+  RP->tax_report(\%::myconfig, $::form);
 
-  my $descvar     = "$form->{accno}_description";
-  my $description = $form->escape($form->{$descvar});
-  my $ratevar     = "$form->{accno}_rate";
+  my $descvar     = "$::form->{accno}_description";
   my ($subtotalnetamount, $subtotaltax, $subtotal) = (0, 0, 0);
 
-  my $department = $form->escape($form->{department});
-
   # construct href
-  my $href =
-    "$form->{script}?&action=generate_tax_report&fromdate=$form->{fromdate}&todate=$form->{todate}&db=$form->{db}&method=$form->{method}&accno=$form->{accno}&$descvar=$description&department=$department&report=$form->{report}";
-
-  # construct callback
-  $description = $form->escape($form->{$descvar},   1);
-  $department  = $form->escape($form->{department}, 1);
-  my $callback    =
-    "$form->{script}?&action=generate_tax_report&fromdate=$form->{fromdate}&todate=$form->{todate}&db=$form->{db}&method=$form->{method}&accno=$form->{accno}&$descvar=$description&department=$department&report=$form->{report}";
+  my $href     =
+  my $callback = build_std_url('action=generate_tax_report', $descvar,
+    qw(fromdate todate db method accno department report title));
 
-  my $title = $form->escape($form->{title});
-  $href .= "&title=$title";
-  $title = $form->escape($form->{title}, 1);
-  $callback .= "&title=$title";
-
-  $form->{title} = qq|$form->{title} $form->{"$form->{accno}_description"} |;
-
-  my @columns =
-    $form->sort_columns(qw(id transdate invnumber name netamount tax amount));
+  my @columns = $::form->sort_columns(qw(id transdate invnumber name netamount tax amount));
   my @column_index;
 
-  foreach my $item (@columns) {
-    if ($form->{"l_$item"} eq "Y") {
-      push @column_index, $item;
-
-      # add column to href and callback
+  for my $item (@columns, 'subtotal') {
+    if ($::form->{"l_$item"} eq "Y") {
       $callback .= "&l_$item=Y";
       $href     .= "&l_$item=Y";
     }
   }
 
-  if ($form->{l_subtotal} eq 'Y') {
-    $callback .= "&l_subtotal=Y";
-    $href     .= "&l_subtotal=Y";
+  for my $item (@columns) {
+    if ($::form->{"l_$item"} eq "Y") {
+      push @column_index, $item;
+    }
   }
 
-  my $option;
-  if ($form->{department}) {
-    ($department) = split /--/, $form->{department};
-    $option = $locale->text('Department') . " : $department";
+  my @options;
+  if ($::form->{department}) {
+    my ($department) = split /--/, $::form->{department};
+    push @options, $::locale->text('Department') . " : $department";
   }
 
-  my ($fromdate, $todate);
   # if there are any dates
-  if ($form->{fromdate} || $form->{todate}) {
-    if ($form->{fromdate}) {
-      $fromdate = $locale->date(\%myconfig, $form->{fromdate}, 1);
-    }
-    if ($form->{todate}) {
-      $todate = $locale->date(\%myconfig, $form->{todate}, 1);
-    }
-
-    $form->{period} = "$fromdate - $todate";
+  if ($::form->{fromdate} || $::form->{todate}) {
+    my $fromdate = $::form->{fromdate} ? $::locale->date(\%::myconfig, $::form->{fromdate}, 1) : '';
+    my $todate   = $::form->{todate}   ? $::locale->date(\%::myconfig, $::form->{todate}, 1)   : '';
+    push @options, "$fromdate - $todate";
   } else {
-    $form->{period} =
-      $locale->date(\%myconfig, $form->current_date(\%myconfig), 1);
+    push @options, $::locale->date(\%::myconfig, $::form->current_date, 1);
   }
 
   my ($name, $invoice, $arap);
-  if ($form->{db} eq 'ar') {
-    $name    = $locale->text('Customer');
+  if ($::form->{db} eq 'ar') {
+    $name    = $::locale->text('Customer');
     $invoice = 'is.pl';
     $arap    = 'ar.pl';
   }
-  if ($form->{db} eq 'ap') {
-    $name    = $locale->text('Vendor');
+  if ($::form->{db} eq 'ap') {
+    $name    = $::locale->text('Vendor');
     $invoice = 'ir.pl';
     $arap    = 'ap.pl';
   }
 
-  $option .= "<br>" if $option;
-  $option .= "$form->{period}";
-
-  my %column_header;
-  $column_header{id}        = qq|<th><a class=listheading href=$href&sort=id>| . $locale->text('ID') . qq|</th>|;
-  $column_header{invnumber} = qq|<th><a class=listheading href=$href&sort=invnumber>| . $locale->text('Invoice') . qq|</th>|;
-  $column_header{transdate} = qq|<th><a class=listheading href=$href&sort=transdate>| . $locale->text('Date') . qq|</th>|;
-  $column_header{netamount} = qq|<th class=listheading>| . $locale->text('Amount') . qq|</th>|;
-  $column_header{tax}       = qq|<th class=listheading>| . $locale->text('Tax') . qq|</th>|;
-  $column_header{amount}    = qq|<th class=listheading>| . $locale->text('Total') . qq|</th>|;
-
-  $column_header{name}      = qq|<th><a class=listheading href=$href&sort=name>$name</th>|;
-
-  $form->header;
-
-  print qq|
-<body>
-
-<table width=100%>
-  <tr>
-    <th class=listtop>$form->{title}</th>
-  </tr>
-  <tr height="5"></tr>
-  <tr>
-    <td>$option</td>
-  </tr>
-  <tr>
-    <td>
-      <table width=100%>
-        <tr class=listheading>
-|;
-
-  map { print "$column_header{$_}\n" } @column_index;
+  my %column_header = (
+    id        => $::locale->text('ID'),
+    invnumber => $::locale->text('Invoice'),
+    transdate => $::locale->text('Date'),
+    netamount => $::locale->text('Amount'),
+    tax       => $::locale->text('Tax'),
+    amount    => $::locale->text('Total'),
+    name      => $name,
+  );
 
-  print qq|
-        </tr>
-|;
+  my %column_sorted = map { $_ => 1 } qw(id invnumber transdate);
 
-  # add sort and escape callback
-  $callback = $form->escape($callback . "&sort=$form->{sort}");
+  $callback .= "&sort=$::form->{sort}";
 
   my $sameitem;
-  if (@{ $form->{TR} }) {
-    $sameitem = $form->{TR}->[0]->{ $form->{sort} };
+  if (@{ $::form->{TR} }) {
+    $sameitem = $::form->{TR}->[0]->{ $::form->{sort} };
   }
 
-  my ($totalnetamount, $totaltax);
-  my ($i);
-  foreach my $ref (@{ $form->{TR} }) {
+  my ($totalnetamount, $totaltax, @data);
+  for my $ref (@{ $::form->{TR} }) {
 
     my $module = ($ref->{invoice}) ? $invoice : $arap;
 
-    if ($form->{l_subtotal} eq 'Y') {
-      if ($sameitem ne $ref->{ $form->{sort} }) {
-        tax_subtotal(\@column_index, \$subtotalnetamount, \$subtotaltax, \$subtotal);
-        $sameitem = $ref->{ $form->{sort} };
+    if ($::form->{l_subtotal} eq 'Y') {
+      if ($sameitem ne $ref->{ $::form->{sort} }) {
+        push @data, {
+          subtotal  => 1,
+          netamount => $subtotalnetamount,
+          tax       => $subtotaltax,
+          amount    => $subtotal,
+        };
+        $subtotalnetamount = 0;
+        $subtotaltax       = 0;
+        $sameitem          = $ref->{ $::form->{sort} };
       }
     }
 
-    $totalnetamount += $ref->{netamount};
-    $totaltax       += $ref->{tax};
-    $ref->{amount} = $ref->{netamount} + $ref->{tax};
-
     $subtotalnetamount += $ref->{netamount};
     $subtotaltax       += $ref->{tax};
+    $totalnetamount    += $ref->{netamount};
+    $totaltax          += $ref->{tax};
+    $ref->{amount}      = $ref->{netamount} + $ref->{tax};
 
-    map {
-      $ref->{$_} = $form->format_amount(\%myconfig, $ref->{$_}, 2, "&nbsp;");
-    } qw(netamount tax amount);
-
-    my %column_data;
-    $column_data{id}        = qq|<td>$ref->{id}</td>|;
-    $column_data{invnumber} =
-      qq|<td><a href=$module?action=edit&id=$ref->{id}&callback=$callback>$ref->{invnumber}</a></td>|;
-    $column_data{transdate} = qq|<td>$ref->{transdate}</td>|;
-    $column_data{name}      = qq|<td>$ref->{name}&nbsp;</td>|;
-
-    map { $column_data{$_} = qq|<td align=right>$ref->{$_}</td>| }
-      qw(netamount tax amount);
-
-    $i++;
-    $i %= 2;
-    print qq|
-        <tr class=listrow$i>
-|;
-
-    map { print "$column_data{$_}\n" } @column_index;
-
-    print qq|
-        </tr>
-|;
-
+    push @data, { map { $_ => { data => $ref->{$_} } } keys %$ref };
+    $data[-1]{invnumber}{link} = "$module?action=edit&id=$ref->{id}&callback=$callback";
+    $data[-1]{$_}{numeric}     = 1 for qw(netamount tax amount);
   }
 
-  if ($form->{l_subtotal} eq 'Y') {
-    tax_subtotal(\@column_index, \$subtotalnetamount, \$subtotaltax, \$subtotal);
+  if ($::form->{l_subtotal} eq 'Y') {
+    push @data, {
+      subtotal  => 1,
+      netamount => $subtotalnetamount,
+      tax       => $subtotaltax,
+      amount    => $subtotal,
+    };
   }
 
-  my %column_data;
-  map { $column_data{$_} = qq|<th>&nbsp;</th>| } @column_index;
-
-  print qq|
-        </tr>
-        <tr class=listtotal>
-|;
-
-  my $total          = $form->format_amount(\%myconfig, $totalnetamount + $totaltax, 2, "&nbsp;");
-  $totalnetamount = $form->format_amount(\%myconfig, $totalnetamount, 2, "&nbsp;");
-  $totaltax       = $form->format_amount(\%myconfig, $totaltax, 2, "&nbsp;");
-
-  $column_data{netamount} = qq|<th class=listtotal align=right>$totalnetamount</th>|;
-  $column_data{tax}    = qq|<th class=listtotal align=right>$totaltax</th>|;
-  $column_data{amount} = qq|<th class=listtotal align=right>$total</th>|;
-
-  map { print "$column_data{$_}\n" } @column_index;
-
-  print qq|
-        </tr>
-      </table>
-    </td>
-  </tr>
-  <tr>
-    <td><hr size=3 noshade></td>
-  </tr>
-</table>
-
-</body>
-</html>
-|;
-
-  $main::lxdebug->leave_sub();
-}
-
-sub tax_subtotal {
-  $main::lxdebug->enter_sub();
-
-  my ($column_index, $subtotalnetamount, $subtotaltax, $subtotal) = @_;
-
-  my $form     = $main::form;
-  my %myconfig = %main::myconfig;
-  my $locale   = $main::locale;
-
-  my %column_data;
-  map { $column_data{$_} = "<td>&nbsp;</td>" } @{ $column_index };
-
-  $$subtotalnetamount = $form->format_amount(\%myconfig, $$subtotalnetamount, 2, "&nbsp;");
-  $$subtotaltax       = $form->format_amount(\%myconfig, $$subtotaltax, 2, "&nbsp;");
-  $$subtotal          = $form->format_amount(\%myconfig, $$subtotalnetamount + $$subtotaltax, 2, "&nbsp;");
-
-  $column_data{netamount} = "<th class=listsubtotal align=right>$$subtotalnetamount</th>";
-  $column_data{tax}       = "<th class=listsubtotal align=right>$$subtotaltax</th>";
-  $column_data{amount}    = "<th class=listsubtotal align=right>$$subtotal</th>";
-
-  $$subtotalnetamount = 0;
-  $$subtotaltax       = 0;
-
-  print qq|
-        <tr class=listsubtotal>
-|;
-  map { print "\n$column_data{$_}" } @{ $column_index };
+  push @data, {
+    total     => 1,
+    netamount => $totalnetamount,
+    tax       => $totaltax,
+    amount    => $totalnetamount + $totaltax,
+  };
 
-  print qq|
-        </tr>
-|;
+  $::form->header;
+  print $::form->parse_html_template('rp/tax_report', {
+    column_index  => \@column_index,
+    column_header => \%column_header,
+    column_sorted => \%column_sorted,
+    sort_base     => $href,
+    DATA          => \@data,
+    options       => \@options,
+  });
 
-  $main::lxdebug->leave_sub();
+  $::lxdebug->leave_sub;
 }
 
 sub list_payments {
@@ -1752,8 +1638,6 @@ sub print_options {
   $::form->{SM}{ $::form->{sendmode} } = "selected";
 
   my $output = $::form->parse_html_template('rp/print_options', {
-    got_printer => $::myconfig{printer},
-    show_latex  => $::lx_office_conf{print_templates}->{latex},
     is_email    => $::form->{media} eq 'email',
   });
 
@@ -1918,8 +1802,7 @@ sub generate_bwa {
     # if (defined ($form->{fromdate|todate}=='..'))
     # immer wahr
     if ($form->{fromdate}){
-      my ($yy, $mm, $dd) = $locale->parse_date(\%myconfig, $form->{fromdate});
-      my $datetime = $locale->parse_date_to_object(\%myconfig, $form->{fromdate});
+      my $datetime = $locale->parse_date_to_object($form->{fromdate});
       $datetime->set( month      => 1,
                       day        => 1);
       $form->{comparefromdate} = $locale->format_date(\%::myconfig, $datetime);
@@ -1960,14 +1843,21 @@ sub generate_bwa {
       . qq| $longtodate|;
   }
 
-  # setup variables for the form
-  my @a = qw(company address businessnumber);
-  map { $form->{$_} = $myconfig{$_} } @a;
-  $form->{templates} = $myconfig{templates};
+  $form->{report_date} = $locale->text('Report date') . ": " . $form->current_date;
 
-  $form->{IN} = "bwa.html";
+  if ( $form->{method} eq 'cash' ) {
+    $form->{accounting_method} = $locale->text('Cash accounting');
+  } elsif ( $form->{method} eq 'accrual' ) {
+    $form->{accounting_method} = $locale->text('Accrual accounting');
+  } else {
+    $form->{accounting_method} = "";
+  };
 
-  $form->parse_template;
+  $form->{title} = $locale->text('BWA');
+
+  $::request->layout->add_stylesheets('bwa.css');
+  $form->header;
+  print $form->parse_html_template('rp/bwa');
 
   $main::lxdebug->leave_sub();
 }
@@ -1999,4 +1889,42 @@ sub hotfix_reformat_date {
   $main::lxdebug->leave_sub();
 
 }
+
+sub setup_rp_aging_action_bar {
+  my %params = @_;
+
+  return unless $params{arap} eq 'ar';
+
+  for my $bar ($::request->layout->get('actionbar')) {
+    $bar->add(
+      combobox => [
+        action => [
+          t8('Print'),
+          call   => [ 'kivi.SalesPurchase.show_print_dialog' ],
+          checks => [ [ 'kivi.check_if_entries_selected', '[name^=statement_]' ] ],
+        ],
+        action => [
+          t8('E Mail'),
+          call   => [ 'kivi.SalesPurchase.show_email_dialog', 'send_email' ],
+          checks => [ [ 'kivi.check_if_entries_selected', '[name^=statement_]' ] ],
+        ],
+      ],
+    );
+  }
+}
+
+sub setup_rp_report_action_bar {
+  my %params = @_;
+
+  for my $bar ($::request->layout->get('actionbar')) {
+    $bar->add(
+      action => [
+        t8('Continue'),
+        submit    => [ '#form', { action => 'continue' } ],
+        accesskey => 'enter',
+      ],
+    );
+  }
+}
+
 1;