+ my $pl_cb_credit_entry = SL::DB::GLTransaction->new(
+ employee_id => $employee_id,
+ transdate => $cb_date,
+ reference => 'SB ' . $cb_date->year,
+ description => 'Automatische SB-Buchungen Erfolgskonten Haben für ' . $cb_date->year,
+ ob_transaction => 0,
+ cb_transaction => 1,
+ taxincluded => 0,
+ 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;
+
+ 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_chart_booking(
+ chart => $chart,
+ tax_id => 0,
+ debit => $profit_loss_account->{amount_with_cb},
+ );
+ };
+ };
+
+ # $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;
+
+ # 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!
+
+ if ( $profit_loss_sum != 0 ) {
+
+ 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 => [],
+ );
+
+ my ($amount1, $amount2);
+ if ( $profit_loss_sum < 0 ) {
+ $amount1 = 'debit';
+ $amount2 = 'credit';
+ } else {
+ $amount1 = 'credit';
+ $amount2 = 'debit';
+ };
+
+ $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_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)
+ from acc_trans
+ where (ob_transaction is true or cb_transaction is true)
+ and (transdate = ? or transdate = ?)
+SQL
+ 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;
+ }) or die $db->error;
+}
+
+sub _report {
+ my (%params) = @_;
+
+ my $start_date = delete $params{start_date};
+ my $cb_date = delete $params{cb_date};
+
+ my $defaults = SL::DB::Default->get;
+ die "no carry over account defined"
+ unless defined $defaults->carry_over_account_chart_id
+ and $defaults->carry_over_account_chart_id > 0;
+
+ my $salden_query = <<SQL;
+select c.id as chart_id,
+ c.accno,
+ c.description,
+ 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,
+ sum(a.amount) filter (where cb_transaction is false ) as amount_without_cb,
+ sum(a.amount) filter (where cb_transaction is true ) as cb_amount,
+ sum(a.amount) as amount_with_cb,
+ case when c.category = ANY( '{I,E}' ) then 'profit_loss_account'
+ when c.category = ANY( '{A,C,L,Q}' ) then 'asset_account'
+ else null
+ end as account_type
+ from acc_trans a
+ inner join chart c on (c.id = a.chart_id)
+ where a.transdate >= ?
+ and a.transdate <= ?
+ and a.chart_id != ?
+ group by c.id, c.accno, c.category
+ order by account_type, c.accno
+SQL
+
+ my $dbh = SL::DB->client->dbh;
+ my $report = selectall_hashref_query($::form, $dbh, $salden_query,
+ $start_date,
+ $cb_date,
+ $defaults->carry_over_account_chart_id,
+ );
+ # profit_loss_sum is the actual profit/loss for the year, without cb, use "amount_without_cb")
+ my $profit_loss_sum = sum map { $_->{amount_without_cb} }
+ grep { $_->{account_type} eq 'profit_loss_account' }
+ @{$report};
+
+ return ($report, $profit_loss_sum);
+}
+
+#
+# auth
+#
+
+sub check_auth {
+ $::auth->assert('general_ledger');