1 #=====================================================================
 
   4 # Based on SQL-Ledger Version 2.1.9
 
   5 # Web http://www.lx-office.org
 
   7 #=====================================================================
 
   8 # SQL-Ledger Accounting
 
   9 # Copyright (c) 1998-2002
 
  11 #  Author: Dieter Simader
 
  12 #   Email: dsimader@sql-ledger.org
 
  13 #     Web: http://www.sql-ledger.org
 
  16 # This program is free software; you can redistribute it and/or modify
 
  17 # it under the terms of the GNU General Public License as published by
 
  18 # the Free Software Foundation; either version 2 of the License, or
 
  19 # (at your option) any later version.
 
  21 # This program is distributed in the hope that it will be useful,
 
  22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  24 # GNU General Public License for more details.
 
  25 # You should have received a copy of the GNU General Public License
 
  26 # along with this program; if not, write to the Free Software
 
  27 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
  28 #======================================================================
 
  32 #======================================================================
 
  37 use POSIX qw(strftime);
 
  38 use List::Util qw(sum);
 
  44 use SL::ReportGenerator;
 
  46 require "bin/mozilla/common.pl";
 
  47 require "bin/mozilla/drafts.pl";
 
  48 require "bin/mozilla/reportgenerator.pl";
 
  50 # this is for our long dates
 
  51 # $locale->text('January')
 
  52 # $locale->text('February')
 
  53 # $locale->text('March')
 
  54 # $locale->text('April')
 
  55 # $locale->text('May ')
 
  56 # $locale->text('June')
 
  57 # $locale->text('July')
 
  58 # $locale->text('August')
 
  59 # $locale->text('September')
 
  60 # $locale->text('October')
 
  61 # $locale->text('November')
 
  62 # $locale->text('December')
 
  64 # this is for our short month
 
  65 # $locale->text('Jan')
 
  66 # $locale->text('Feb')
 
  67 # $locale->text('Mar')
 
  68 # $locale->text('Apr')
 
  69 # $locale->text('May')
 
  70 # $locale->text('Jun')
 
  71 # $locale->text('Jul')
 
  72 # $locale->text('Aug')
 
  73 # $locale->text('Sep')
 
  74 # $locale->text('Oct')
 
  75 # $locale->text('Nov')
 
  76 # $locale->text('Dec')
 
  79   $main::lxdebug->enter_sub();
 
  81   $main::auth->assert('general_ledger');
 
  83   my $form     = $main::form;
 
  84   my %myconfig = %main::myconfig;
 
  86   return $main::lxdebug->leave_sub() if (load_draft_maybe());
 
  88   $form->{title} = "Add";
 
  90   $form->{callback} = "gl.pl?action=add" unless $form->{callback};
 
  92   # we use this only to set a default date
 
  93   # yep. aber er holt hier auch schon ALL_CHARTS. Aufwand / Nutzen? jb
 
  94   GL->transaction(\%myconfig, \%$form);
 
  96   $form->{rowcount}  = 2;
 
 103   $form->all_departments(\%myconfig);
 
 104   if (@{ $form->{all_departments} || [] }) {
 
 105     $form->{selectdepartment} = "<option>\n";
 
 108       $form->{selectdepartment} .=
 
 109         "<option>$_->{description}--$_->{id}\n"
 
 110     } (@{ $form->{all_departments} || [] });
 
 113   $form->{show_details} = $myconfig{show_form_details} unless defined $form->{show_details};
 
 116   $main::lxdebug->leave_sub();
 
 120 sub prepare_transaction {
 
 121   $main::lxdebug->enter_sub();
 
 123   $main::auth->assert('general_ledger');
 
 125   my $form     = $main::form;
 
 126   my %myconfig = %main::myconfig;
 
 128   GL->transaction(\%myconfig, \%$form);
 
 130   $form->{amount} = $form->format_amount(\%myconfig, $form->{amount}, 2);
 
 133   $form->all_departments(\%myconfig);
 
 134   if (@{ $form->{all_departments} || [] }) {
 
 135     $form->{selectdepartment} = "<option>\n";
 
 138       $form->{selectdepartment} .=
 
 139         "<option>$_->{description}--$_->{id}\n"
 
 140     } (@{ $form->{all_departments} || [] });
 
 146   foreach my $ref (@{ $form->{GL} }) {
 
 148     if ($tax && ($ref->{accno} eq $taxaccno)) {
 
 149       $form->{"tax_$j"}      = abs($ref->{amount});
 
 150       $form->{"taxchart_$j"} = $ref->{id} . "--" . $ref->{taxrate};
 
 151       if ($form->{taxincluded}) {
 
 152         if ($ref->{amount} < 0) {
 
 153           $form->{"debit_$j"} += $form->{"tax_$j"};
 
 155           $form->{"credit_$j"} += $form->{"tax_$j"};
 
 158       $form->{"project_id_$j"} = $ref->{project_id};
 
 161       $form->{"accno_$i"} = "$ref->{accno}--$ref->{tax_id}";
 
 162       for (qw(fx_transaction source memo)) { $form->{"${_}_$i"} = $ref->{$_} }
 
 163       if ($ref->{amount} < 0) {
 
 164         $form->{totaldebit} -= $ref->{amount};
 
 165         $form->{"debit_$i"} = $ref->{amount} * -1;
 
 167         $form->{totalcredit} += $ref->{amount};
 
 168         $form->{"credit_$i"} = $ref->{amount};
 
 170       $form->{"taxchart_$i"} = "0--0.00";
 
 171       $form->{"project_id_$i"} = $ref->{project_id};
 
 174     if ($ref->{taxaccno} && !$tax) {
 
 175       $taxaccno = $ref->{taxaccno};
 
 183   $form->{rowcount} = $i;
 
 185     ($form->datetonum($form->{transdate}, \%myconfig) <=
 
 186      $form->datetonum($form->{closedto}, \%myconfig));
 
 188   $main::lxdebug->leave_sub();
 
 192   $main::lxdebug->enter_sub();
 
 194   $main::auth->assert('general_ledger');
 
 196   my $form     = $main::form;
 
 197   my %myconfig = %main::myconfig;
 
 199   prepare_transaction();
 
 201   $form->{title} = "Edit";
 
 203   $form->{show_details} = $myconfig{show_form_details} unless defined $form->{show_details};
 
 209   $main::lxdebug->leave_sub();
 
 214   $::lxdebug->enter_sub;
 
 215   $::auth->assert('general_ledger');
 
 217   $::form->all_departments(\%::myconfig);
 
 219     projects  => { key => "ALL_PROJECTS", all => 1 },
 
 221   $::form->{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all(query => [ deleted => 0 ]);
 
 224   print $::form->parse_html_template('gl/search', {
 
 225     department_label => sub { ("$_[0]{description}--$_[0]{id}")x2 },
 
 226     employee_label => sub { "$_[0]{id}--$_[0]{name}" },
 
 229   $::lxdebug->leave_sub;
 
 232 sub create_subtotal_row {
 
 233   $main::lxdebug->enter_sub();
 
 235   my ($totals, $columns, $column_alignment, $subtotal_columns, $class) = @_;
 
 237   my $form     = $main::form;
 
 238   my %myconfig = %main::myconfig;
 
 240   my $row = { map { $_ => { 'data' => '', 'class' => $class, 'align' => $column_alignment->{$_}, } } @{ $columns } };
 
 242   map { $row->{$_}->{data} = $form->format_amount(\%myconfig, $totals->{$_}, 2) } @{ $subtotal_columns };
 
 244   map { $totals->{$_} = 0 } @{ $subtotal_columns };
 
 246   $main::lxdebug->leave_sub();
 
 251 sub generate_report {
 
 252   $main::lxdebug->enter_sub();
 
 254   $main::auth->assert('general_ledger');
 
 256   my $form     = $main::form;
 
 257   my %myconfig = %main::myconfig;
 
 258   my $locale   = $main::locale;
 
 260   # generate_report wird beim ersten Aufruf per Weiter-Knopf und POST mit der hidden Variablen sort mit Wert "datesort" (früher "transdate" als Defaultsortiervariable) übertragen
 
 262   # <form method=post action=gl.pl>
 
 263   # <input type=hidden name=sort value=datesort>    # form->{sort} setzen
 
 264   # <input type=hidden name=nextsub value=generate_report>
 
 266   # anhand von neuer Variable datesort wird jetzt $form->{sort} auf transdate oder gldate gesetzt
 
 267   # damit ist die Hidden Variable "sort" wahrscheinlich sogar überflüssig
 
 269   # ändert man die Sortierreihenfolge per Klick auf eine der Überschriften wird die Variable "sort" per GET übergeben, z.B. id,transdate, gldate, ...
 
 270   # gl.pl?action=generate_report&employee=18383--Jan%20B%c3%bcren&datesort=transdate&category=X&l_transdate=Y&l_gldate=Y&l_id=Y&l_reference=Y&l_description=Y&l_source=Y&l_debit=Y&l_credit=Y&sort=gldate&sortdir=0
 
 272   if ( $form->{sort} eq 'datesort' ) {   # sollte bei einem Post (Aufruf aus Suchmaske) immer wahr sein
 
 273       # je nachdem ob in Suchmaske "transdate" oder "gldate" ausgesucht wurde erstes Suchergebnis entsprechend sortieren
 
 274       $form->{sort} = $form->{datesort};
 
 278   report_generator_set_default_sort("$form->{datesort}", 1);
 
 279 #  report_generator_set_default_sort('transdate', 1);
 
 281   GL->all_transactions(\%myconfig, \%$form);
 
 283   my %acctype = ('A' => $locale->text('Asset'),
 
 284                  'C' => $locale->text('Contra'),
 
 285                  'L' => $locale->text('Liability'),
 
 286                  'Q' => $locale->text('Equity'),
 
 287                  'I' => $locale->text('Revenue'),
 
 288                  'E' => $locale->text('Expense'),);
 
 290   $form->{title} = $locale->text('Journal');
 
 291   if ($form->{category} ne 'X') {
 
 292     $form->{title} .= " : " . $locale->text($acctype{ $form->{category} });
 
 295   $form->{landscape} = 1;
 
 297   my $ml = ($form->{ml} =~ /(A|E|Q)/) ? -1 : 1;
 
 300     gldate         transdate        id             reference      description
 
 301     notes          source           debit          debit_accno
 
 302     credit         credit_accno     debit_tax      debit_tax_accno
 
 303     credit_tax     credit_tax_accno projectnumbers balance employee
 
 306   # add employee here, so that variable is still known and passed in url when choosing a different sort order in resulting table
 
 307   my @hidden_variables = qw(accno source reference department description notes project_id datefrom dateto employee datesort category l_subtotal);
 
 308   push @hidden_variables, map { "l_${_}" } @columns;
 
 309   foreach ( @hidden_variables ) {
 
 313   my (@options, @date_options);
 
 314   push @options,      $locale->text('Account')     . " : $form->{accno} $form->{account_description}" if ($form->{accno});
 
 315   push @options,      $locale->text('Source')      . " : $form->{source}"                             if ($form->{source});
 
 316   push @options,      $locale->text('Reference')   . " : $form->{reference}"                          if ($form->{reference});
 
 317   push @options,      $locale->text('Description') . " : $form->{description}"                        if ($form->{description});
 
 318   push @options,      $locale->text('Notes')       . " : $form->{notes}"                              if ($form->{notes});
 
 319   push @options,      $locale->text('Employee')       . " : $form->{employee_name}"                              if ($form->{employee_name});
 
 320   my $datesorttext = $form->{datesort} eq 'transdate' ? $locale->text('Invoice Date') :  $locale->text('Booking Date');
 
 321   push @date_options,      "$datesorttext"                              if ($form->{datesort} and ($form->{datefrom} or $form->{dateto}));
 
 322   push @date_options, $locale->text('From'), $locale->date(\%myconfig, $form->{datefrom}, 1)          if ($form->{datefrom});
 
 323   push @date_options, $locale->text('Bis'),  $locale->date(\%myconfig, $form->{dateto},   1)          if ($form->{dateto});
 
 324   push @options,      join(' ', @date_options)                                                        if (scalar @date_options);
 
 326   if ($form->{department}) {
 
 327     my ($department) = split /--/, $form->{department};
 
 328     push @options, $locale->text('Department') . " : $department";
 
 332   my $callback = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
 
 336   $form->{l_credit_accno}     = 'Y';
 
 337   $form->{l_debit_accno}      = 'Y';
 
 338   $form->{l_credit_tax}       = 'Y';
 
 339   $form->{l_debit_tax}        = 'Y';
 
 340 #  $form->{l_gldate}           = 'Y';  # Spalte mit gldate immer anzeigen
 
 341   $form->{l_credit_tax_accno} = 'Y';
 
 342   $form->{l_datesort} = 'Y';
 
 343   $form->{l_debit_tax_accno}  = 'Y';
 
 344   $form->{l_balance}          = $form->{accno} ? 'Y' : '';
 
 347     'id'               => { 'text' => $locale->text('ID'), },
 
 348     'transdate'        => { 'text' => $locale->text('Invoice Date'), },
 
 349     'gldate'           => { 'text' => $locale->text('Booking Date'), },
 
 350     'reference'        => { 'text' => $locale->text('Reference'), },
 
 351     'source'           => { 'text' => $locale->text('Source'), },
 
 352     'description'      => { 'text' => $locale->text('Description'), },
 
 353     'notes'            => { 'text' => $locale->text('Notes'), },
 
 354     'debit'            => { 'text' => $locale->text('Debit'), },
 
 355     'debit_accno'      => { 'text' => $locale->text('Debit Account'), },
 
 356     'credit'           => { 'text' => $locale->text('Credit'), },
 
 357     'credit_accno'     => { 'text' => $locale->text('Credit Account'), },
 
 358     'debit_tax'        => { 'text' => $locale->text('Debit Tax'), },
 
 359     'debit_tax_accno'  => { 'text' => $locale->text('Debit Tax Account'), },
 
 360     'credit_tax'       => { 'text' => $locale->text('Credit Tax'), },
 
 361     'credit_tax_accno' => { 'text' => $locale->text('Credit Tax Account'), },
 
 362     'balance'          => { 'text' => $locale->text('Balance'), },
 
 363     'projectnumbers'   => { 'text' => $locale->text('Project Numbers'), },
 
 364     'employee'         => { 'text' => $locale->text('Employee'), },
 
 367   foreach my $name (qw(id transdate gldate reference description debit_accno credit_accno debit_tax_accno credit_tax_accno)) {
 
 368     my $sortname                = $name =~ m/accno/ ? 'accno' : $name;
 
 369     my $sortdir                 = $sortname eq $form->{sort} ? 1 - $form->{sortdir} : $form->{sortdir};
 
 370     $column_defs{$name}->{link} = $callback . "&sort=$sortname&sortdir=$sortdir";
 
 373   map { $column_defs{$_}->{visible} = $form->{"l_${_}"} ? 1 : 0 } @columns;
 
 374   map { $column_defs{$_}->{visible} = 0 } qw(debit_accno credit_accno debit_tax_accno credit_tax_accno) if $form->{accno};
 
 376   my %column_alignment;
 
 377   map { $column_alignment{$_}     = 'right'  } qw(balance id debit credit debit_tax credit_tax balance);
 
 378   map { $column_alignment{$_}     = 'center' } qw(transdate gldate reference debit_accno credit_accno debit_tax_accno credit_tax_accno);
 
 379   map { $column_alignment{$_}     = 'left' } qw(description source notes);
 
 380   map { $column_defs{$_}->{align} = $column_alignment{$_} } keys %column_alignment;
 
 382   my $report = SL::ReportGenerator->new(\%myconfig, $form);
 
 384   $report->set_columns(%column_defs);
 
 385   $report->set_column_order(@columns);
 
 387   $report->set_export_options('generate_report', @hidden_variables, qw(sort sortdir));
 
 389   $report->set_sort_indicator($form->{sort} eq 'accno' ? 'debit_accno' : $form->{sort}, $form->{sortdir});
 
 391   $report->set_options('top_info_text'        => join("\n", @options),
 
 392                        'output_format'        => 'HTML',
 
 393                        'title'                => $form->{title},
 
 394                        'attachment_basename'  => $locale->text('general_ledger_list') . strftime('_%Y%m%d', localtime time),
 
 396   $report->set_options_from_form();
 
 397   $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
 
 399   # add sort to callback
 
 400   $form->{callback} = "$callback&sort=" . E($form->{sort}) . "&sortdir=" . E($form->{sortdir});
 
 403   my @totals_columns = qw(debit credit debit_tax credit_tax);
 
 404   my %subtotals      = map { $_ => 0 } @totals_columns;
 
 405   my %totals         = map { $_ => 0 } @totals_columns;
 
 408   foreach my $ref (@{ $form->{GL} }) {
 
 412     foreach my $key (qw(debit credit debit_tax credit_tax)) {
 
 414       foreach my $idx (sort keys(%{ $ref->{$key} })) {
 
 415         my $value         = $ref->{$key}->{$idx};
 
 416         $subtotals{$key} += $value;
 
 417         $totals{$key}    += $value;
 
 418         if ($key =~ /debit.*/) {
 
 423         $form->{balance}  = $form->{balance} + $value * $ml;
 
 424         push @{ $rows{$key} }, $form->format_amount(\%myconfig, $value, 2);
 
 428     foreach my $key (qw(debit_accno credit_accno debit_tax_accno credit_tax_accno ac_transdate source)) {
 
 429       my $col = $key eq 'ac_transdate' ? 'transdate' : $key;
 
 430       $rows{$col} = [ map { $ref->{$key}->{$_} } sort keys(%{ $ref->{$key} }) ];
 
 434     map { $row->{$_} = { 'data' => '', 'align' => $column_alignment{$_} } } @columns;
 
 437     if ($form->{balance} < 0) {
 
 440     } elsif ($form->{balance} > 0) {
 
 444     my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
 
 447     $row->{balance}->{data}        = $data;
 
 448     $row->{projectnumbers}->{data} = join ", ", sort { lc($a) cmp lc($b) } keys %{ $ref->{projectnumbers} };
 
 450     map { $row->{$_}->{data} = $ref->{$_} } qw(id reference description notes gldate employee);
 
 452     map { $row->{$_}->{data} = \@{ $rows{$_} }; } qw(transdate debit credit debit_accno credit_accno debit_tax_accno credit_tax_accno source);
 
 454     foreach my $col (qw(debit_accno credit_accno debit_tax_accno credit_tax_accno)) {
 
 455       $row->{$col}->{link} = [ map { "${callback}&accno=" . E($_) } @{ $rows{$col} } ];
 
 458     map { $row->{$_}->{data} = \@{ $rows{$_} } if ($ref->{"${_}_accno"} ne "") } qw(debit_tax credit_tax);
 
 460     $row->{reference}->{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'id=' . E($ref->{id}), 'callback');
 
 462     my $row_set = [ $row ];
 
 464     if ( ($form->{l_subtotal} eq 'Y' && !$form->{report_generator_csv_options_for_import} )
 
 465         && (($idx == (scalar @{ $form->{GL} } - 1))
 
 466             || ($ref->{ $form->{sort} } ne $form->{GL}->[$idx + 1]->{ $form->{sort} }))) {
 
 467       push @{ $row_set }, create_subtotal_row(\%subtotals, \@columns, \%column_alignment, [ qw(debit credit) ], 'listsubtotal');
 
 470     $report->add_data($row_set);
 
 475   # = 0 for balanced ledger
 
 476   my $balanced_ledger = $totals{debit} + $totals{debit_tax} - $totals{credit} - $totals{credit_tax};
 
 478   my $row = create_subtotal_row(\%totals, \@columns, \%column_alignment, [ qw(debit credit debit_tax credit_tax) ], 'listtotal');
 
 481   if ($form->{balance} < 0) {
 
 484   } elsif ($form->{balance} > 0) {
 
 488   my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
 
 491   $row->{balance}->{data}        = $data;
 
 493   if ( !$form->{report_generator_csv_options_for_import} ) {
 
 494     $report->add_separator();
 
 495     $report->add_data($row);
 
 498   my $raw_bottom_info_text;
 
 500   if (!$form->{accno} && (abs($balanced_ledger) >  0.001)) {
 
 501     $raw_bottom_info_text .=
 
 502         '<p><span class="unbalanced_ledger">'
 
 503       . $locale->text('Unbalanced Ledger')
 
 505       . $form->format_amount(\%myconfig, $balanced_ledger, 3)
 
 509   $raw_bottom_info_text .= $form->parse_html_template('gl/generate_report_bottom');
 
 511   $report->set_options('raw_bottom_info_text' => $raw_bottom_info_text);
 
 513   $report->generate_with_headers();
 
 515   $main::lxdebug->leave_sub();
 
 519   $main::lxdebug->enter_sub();
 
 521   $main::auth->assert('general_ledger');
 
 523   my $form     = $main::form;
 
 524   my %myconfig = %main::myconfig;
 
 526   $form->{oldtransdate} = $form->{transdate};
 
 534   my ($debitcredit, $amount);
 
 537     qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
 
 539   for my $i (1 .. $form->{rowcount}) {
 
 541     unless (($form->{"debit_$i"} eq "") && ($form->{"credit_$i"} eq "")) {
 
 542       for (qw(debit credit tax)) {
 
 544           $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
 
 548       $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
 
 555       if (($debitcount >= 2) && ($creditcount == 2)) {
 
 556         $form->{"credit_$i"} = 0;
 
 557         $form->{"tax_$i"}    = 0;
 
 559         $form->{creditlock} = 1;
 
 561       if (($creditcount >= 2) && ($debitcount == 2)) {
 
 562         $form->{"debit_$i"} = 0;
 
 563         $form->{"tax_$i"}   = 0;
 
 565         $form->{debitlock} = 1;
 
 567       if (($creditcount == 1) && ($debitcount == 2)) {
 
 568         $form->{creditlock} = 1;
 
 570       if (($creditcount == 2) && ($debitcount == 1)) {
 
 571         $form->{debitlock} = 1;
 
 573       if ($debitcredit && $credittax) {
 
 574         $form->{"taxchart_$i"} = "0--0.00";
 
 576       if (!$debitcredit && $debittax) {
 
 577         $form->{"taxchart_$i"} = "0--0.00";
 
 580         ($form->{"debit_$i"} == 0)
 
 581         ? $form->{"credit_$i"}
 
 582         : $form->{"debit_$i"};
 
 584       if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
 
 585         $form->{"taxchart_$i"} = "0--0.00";
 
 586         $form->{"tax_$i"}      = 0;
 
 588       my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
 
 595         if ($form->{taxincluded}) {
 
 596           $form->{"tax_$i"} = $amount / ($rate + 1) * $rate;
 
 598           $form->{"tax_$i"} = $amount * $rate;
 
 601         $form->{"tax_$i"} = 0;
 
 604       for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
 
 609   for my $i (1 .. $count) {
 
 611     for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
 
 614   for my $i ($count + 1 .. $form->{rowcount}) {
 
 615     for (@flds) { delete $form->{"${_}_$i"} }
 
 618   $form->{rowcount} = $count + 1;
 
 621   $main::lxdebug->leave_sub();
 
 627   $main::lxdebug->enter_sub();
 
 629   $main::auth->assert('general_ledger');
 
 631   my $form     = $main::form;
 
 632   my %myconfig = %main::myconfig;
 
 636   #   for $i (1 .. $form->{rowcount}) {
 
 637   #     $form->{totaldebit} += $form->parse_amount(\%myconfig, $form->{"debit_$i"});
 
 638   #     $form->{totalcredit} += $form->parse_amount(\%myconfig, $form->{"credit_$i"});
 
 642   &display_rows($init);
 
 644   $main::lxdebug->leave_sub();
 
 650   $main::lxdebug->enter_sub();
 
 652   $main::auth->assert('general_ledger');
 
 654   my $form     = $main::form;
 
 655   my %myconfig = %main::myconfig;
 
 656   my $cgi      = $::request->{cgi};
 
 658   $form->{debit_1}     = 0 if !$form->{"debit_1"};
 
 659   $form->{totaldebit}  = 0;
 
 660   $form->{totalcredit} = 0;
 
 662   my %project_labels = ();
 
 663   my @project_values = ("");
 
 664   foreach my $item (@{ $form->{"ALL_PROJECTS"} }) {
 
 665     push(@project_values, $item->{"id"});
 
 666     $project_labels{$item->{"id"}} = $item->{"projectnumber"};
 
 669   my %chart_labels = ();
 
 670   my @chart_values = ();
 
 673   foreach my $item (@{ $form->{ALL_CHARTS} }) {
 
 674     if ($item->{charttype} eq 'H'){ #falls überschrift
 
 675       next;                         #überspringen (Bug 1150)
 
 677     my $key = $item->{accno} . "--" . $item->{tax_id};
 
 678     $taxchart_init = $item->{tax_id} unless (@chart_values);
 
 679     push(@chart_values, $key);
 
 680     $chart_labels{$key} = $item->{accno} . "--" . $item->{description};
 
 681     $charts{$item->{accno}} = $item;
 
 684   my %taxchart_labels = ();
 
 685   my @taxchart_values = ();
 
 687   foreach my $item (@{ $form->{ALL_TAXCHARTS} }) {
 
 688     my $key = $item->{id} . "--" . $item->{rate};
 
 689     $taxchart_init = $key if ($taxchart_init == $item->{id});
 
 690     push(@taxchart_values, $key);
 
 691     $taxchart_labels{$key} = $item->{taxdescription} . " " . $item->{rate} * 100 . ' %';
 
 692     $taxcharts{$item->{id}} = $item;
 
 695   my ($source, $memo, $source_hidden, $memo_hidden);
 
 696   for my $i (1 .. $form->{rowcount}) {
 
 697     if ($form->{show_details}) {
 
 699       <td><input name="source_$i" value="$form->{"source_$i"}" size="16"></td>|;
 
 701       <td><input name="memo_$i" value="$form->{"memo_$i"}" size="16"></td>|;
 
 704       <input type="hidden" name="source_$i" value="$form->{"source_$i"}" size="16">|;
 
 706       <input type="hidden" name="memo_$i" value="$form->{"memo_$i"}" size="16">|;
 
 709     my $selected_accno_full;
 
 710     my ($accno_row) = split(/--/, $form->{"accno_$i"});
 
 711     my $item = $charts{$accno_row};
 
 712     $selected_accno_full = "$item->{accno}--$item->{tax_id}";
 
 714     my $selected_taxchart = $form->{"taxchart_$i"};
 
 715     my ($selected_accno, $selected_tax_id) = split(/--/, $selected_accno_full);
 
 716     my ($previous_accno, $previous_tax_id) = split(/--/, $form->{"previous_accno_$i"});
 
 718     if ($previous_accno &&
 
 719         ($previous_accno eq $selected_accno) &&
 
 720         ($previous_tax_id ne $selected_tax_id)) {
 
 721       my $item = $taxcharts{$selected_tax_id};
 
 722       $selected_taxchart = "$item->{id}--$item->{rate}";
 
 725     $selected_accno      = '' if ($init);
 
 726     $selected_taxchart ||= $taxchart_init;
 
 728     my $accno = qq|<td>| .
 
 729       NTI($cgi->popup_menu('-name' => "accno_$i",
 
 731                            '-onChange' => "setTaxkey($i)",
 
 732                            '-style' => 'width:200px',
 
 733                            '-values' => \@chart_values,
 
 734                            '-labels' => \%chart_labels,
 
 735                            '-default' => $selected_accno_full))
 
 736       . $cgi->hidden('-name' => "previous_accno_$i",
 
 737                      '-default' => $selected_accno_full)
 
 739     my $tax_ddbox = qq|<td>| .
 
 740       NTI($cgi->popup_menu('-name' => "taxchart_$i",
 
 741                            '-id' => "taxchart_$i",
 
 742                            '-style' => 'width:200px',
 
 743                            '-values' => \@taxchart_values,
 
 744                            '-labels' => \%taxchart_labels,
 
 745                            '-default' => $selected_taxchart))
 
 748     my ($fx_transaction, $checked);
 
 750       if ($form->{transfer}) {
 
 751         $fx_transaction = qq|
 
 752         <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
 
 757       if ($form->{"debit_$i"} != 0) {
 
 758         $form->{totaldebit} += $form->{"debit_$i"};
 
 759         if (!$form->{taxincluded}) {
 
 760           $form->{totaldebit} += $form->{"tax_$i"};
 
 763         $form->{totalcredit} += $form->{"credit_$i"};
 
 764         if (!$form->{taxincluded}) {
 
 765           $form->{totalcredit} += $form->{"tax_$i"};
 
 769       for (qw(debit credit tax)) {
 
 772           ? $form->format_amount(\%myconfig, $form->{"${_}_$i"}, 2)
 
 776       if ($i < $form->{rowcount}) {
 
 777         if ($form->{transfer}) {
 
 778           $checked = ($form->{"fx_transaction_$i"}) ? "1" : "";
 
 779           my $x = ($checked) ? "x" : "";
 
 780           $fx_transaction = qq|
 
 781       <td><input type=hidden name="fx_transaction_$i" value="$checked">$x</td>
 
 784         $form->hide_form("accno_$i");
 
 787         if ($form->{transfer}) {
 
 788           $fx_transaction = qq|
 
 789       <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
 
 794     my $debitreadonly  = "";
 
 795     my $creditreadonly = "";
 
 796     if ($i == $form->{rowcount}) {
 
 797       if ($form->{debitlock}) {
 
 798         $debitreadonly = "readonly";
 
 799       } elsif ($form->{creditlock}) {
 
 800         $creditreadonly = "readonly";
 
 805       NTI($cgi->popup_menu('-name' => "project_id_$i",
 
 806                            '-values' => \@project_values,
 
 807                            '-labels' => \%project_labels,
 
 808                            '-default' => $form->{"project_id_$i"} ));
 
 809     my $projectnumber_hidden = qq|
 
 810     <input type="hidden" name="project_id_$i" value="$form->{"project_id_$i"}">|;
 
 812     my $copy2credit = $i == 1 ? 'onkeyup="copy_debit_to_credit()"' : '';
 
 814     print qq|<tr valign=top>
 
 816     <td id="chart_balance_$i" align="right"> </td>
 
 818     <td><input name="debit_$i" size="8" value="$form->{"debit_$i"}" accesskey=$i $copy2credit $debitreadonly></td>
 
 819     <td><input name="credit_$i" size=8 value="$form->{"credit_$i"}" $creditreadonly></td>
 
 820     <td><input type="hidden" name="tax_$i" value="$form->{"tax_$i"}">$form->{"tax_$i"}</td>
 
 823     if ($form->{show_details}) {
 
 827     <td>$projectnumber</td>
 
 833     $projectnumber_hidden
 
 841   $form->hide_form(qw(rowcount selectaccno));
 
 843   $main::lxdebug->leave_sub();
 
 848   return ($::instance_conf->get_gl_changeable == 2) ? ($::form->current_date(\%::myconfig) eq $::form->{gldate}) : ($::instance_conf->get_gl_changeable == 1);
 
 852   $::lxdebug->enter_sub;
 
 853   $::auth->assert('general_ledger');
 
 857   my @old_project_ids = grep { $_ } map{ $::form->{"project_id_$_"} } 1..$::form->{rowcount};
 
 859   $::form->get_lists("projects"  => { "key"       => "ALL_PROJECTS",
 
 861                                     "old_id"    => \@old_project_ids },
 
 862                    "charts"    => { "key"       => "ALL_CHARTS",
 
 863                                     "transdate" => $::form->{transdate} },
 
 864                    "taxcharts" => "ALL_TAXCHARTS");
 
 866   GL->get_chart_balances('charts' => $::form->{ALL_CHARTS});
 
 868   my $title      = $::form->{title};
 
 869   $::form->{title} = $::locale->text("$title General Ledger Transaction");
 
 870   # $locale->text('Add General Ledger Transaction')
 
 871   # $locale->text('Edit General Ledger Transaction')
 
 873   map { $::form->{$_} =~ s/\"/"/g }
 
 876   $::form->{selectdepartment} =~ s/ selected//;
 
 877   $::form->{selectdepartment} =~
 
 878     s/option>\Q$::form->{department}\E/option selected>$::form->{department}/;
 
 881     $::request->{layout}->focus("#reference");
 
 882     $::form->{taxincluded} = "1";
 
 884     $::request->{layout}->focus("#accno_$::form->{rowcount}");
 
 887   $::form->{previous_id}     ||= "--";
 
 888   $::form->{previous_gldate} ||= "--";
 
 891   print $::form->parse_html_template('gl/form_header', {
 
 892     hide_title => $title,
 
 893     readonly   => $::form->{id} && ($::form->{locked} || !_get_radieren()),
 
 896   $::lxdebug->leave_sub;
 
 901   $::lxdebug->enter_sub;
 
 902   $::auth->assert('general_ledger');
 
 904   my ($follow_ups, $follow_ups_due);
 
 907     $follow_ups     = FU->follow_ups('trans_id' => $::form->{id});
 
 908     $follow_ups_due = sum map { $_->{due} * 1 } @{ $follow_ups || [] };
 
 911   print $::form->parse_html_template('gl/form_footer', {
 
 912     radieren       => _get_radieren(),
 
 913     follow_ups     => $follow_ups,
 
 914     follow_ups_due => $follow_ups_due,
 
 917   $::lxdebug->leave_sub;
 
 921   $main::lxdebug->enter_sub();
 
 923   my $form     = $main::form;
 
 924   my $locale   = $main::locale;
 
 929 <form method=post action=gl.pl>
 
 932   map { $form->{$_} =~ s/\"/"/g } qw(reference description);
 
 934   delete $form->{header};
 
 936   foreach my $key (keys %$form) {
 
 937     next if (($key eq 'login') || ($key eq 'password') || ('' ne ref $form->{$key}));
 
 938     print qq|<input type="hidden" name="$key" value="$form->{$key}">\n|;
 
 942 <h2 class=confirm>| . $locale->text('Confirm!') . qq|</h2>
 
 945     . $locale->text('Are you sure you want to delete Transaction')
 
 946     . qq| $form->{reference}</h4>
 
 948 <input name=action class=submit type=submit value="|
 
 949     . $locale->text('Yes') . qq|">
 
 952   $main::lxdebug->leave_sub();
 
 957   $main::lxdebug->enter_sub();
 
 959   my $form     = $main::form;
 
 960   my %myconfig = %main::myconfig;
 
 961   my $locale   = $main::locale;
 
 963   if (GL->delete_transaction(\%myconfig, \%$form)){
 
 965       if(!exists $form->{addition} && $form->{id} ne "") {
 
 966         $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
 
 967         $form->{addition} = "DELETED";
 
 970     # /saving the history
 
 971     $form->redirect($locale->text('Transaction deleted!'))
 
 973   $form->error($locale->text('Cannot delete transaction!'));
 
 974   $main::lxdebug->leave_sub();
 
 978 sub post_transaction {
 
 979   $main::lxdebug->enter_sub();
 
 981   my $form     = $main::form;
 
 982   my %myconfig = %main::myconfig;
 
 983   my $locale   = $main::locale;
 
 985   # check if there is something in reference and date
 
 986   $form->isblank("reference",   $locale->text('Reference missing!'));
 
 987   $form->isblank("transdate",   $locale->text('Transaction Date missing!'));
 
 988   $form->isblank("description", $locale->text('Description missing!'));
 
 990   my $transdate = $form->datetonum($form->{transdate}, \%myconfig);
 
 991   my $closedto  = $form->datetonum($form->{closedto},  \%myconfig);
 
1000   my %split_safety = ();
 
1002   my @flds = qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
 
1004   for my $i (1 .. $form->{rowcount}) {
 
1005     next if $form->{"debit_$i"} eq "" && $form->{"credit_$i"} eq "";
 
1007     for (qw(debit credit tax)) {
 
1008       $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
 
1012     $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
 
1014     $split_safety{   $form->{"debit_$i"}  <=> 0 }++;
 
1015     $split_safety{ - $form->{"credit_$i"} <=> 0 }++;
 
1023     if (($debitcount >= 2) && ($creditcount == 2)) {
 
1024       $form->{"credit_$i"} = 0;
 
1025       $form->{"tax_$i"}    = 0;
 
1027       $form->{creditlock} = 1;
 
1029     if (($creditcount >= 2) && ($debitcount == 2)) {
 
1030       $form->{"debit_$i"} = 0;
 
1031       $form->{"tax_$i"}   = 0;
 
1033       $form->{debitlock} = 1;
 
1035     if (($creditcount == 1) && ($debitcount == 2)) {
 
1036       $form->{creditlock} = 1;
 
1038     if (($creditcount == 2) && ($debitcount == 1)) {
 
1039       $form->{debitlock} = 1;
 
1041     if ($debitcredit && $credittax) {
 
1042       $form->{"taxchart_$i"} = "0--0.00";
 
1044     if (!$debitcredit && $debittax) {
 
1045       $form->{"taxchart_$i"} = "0--0.00";
 
1047     my $amount = ($form->{"debit_$i"} == 0)
 
1048             ? $form->{"credit_$i"}
 
1049             : $form->{"debit_$i"};
 
1051     if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
 
1052       $form->{"taxchart_$i"} = "0--0.00";
 
1053       $form->{"tax_$i"}      = 0;
 
1055     my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
 
1062       if ($form->{taxincluded}) {
 
1063         $form->{"tax_$i"} = $amount / ($rate + 1) * $rate;
 
1065           $form->{"debit_$i"} = $form->{"debit_$i"} - $form->{"tax_$i"};
 
1067           $form->{"credit_$i"} = $form->{"credit_$i"} - $form->{"tax_$i"};
 
1070         $form->{"tax_$i"} = $amount * $rate;
 
1073       $form->{"tax_$i"} = 0;
 
1076     for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
 
1080   if ($split_safety{-1} > 1 && $split_safety{1} > 1) {
 
1081     $::form->error($::locale->text("Split entry detected. The values you have entered will result in an entry with more than one position on both debit and credit. Due to known problems involving accounting software Lx-Office does not allow these."));
 
1084   for my $i (1 .. $count) {
 
1086     for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
 
1089   for my $i ($count + 1 .. $form->{rowcount}) {
 
1090     for (@flds) { delete $form->{"${_}_$i"} }
 
1093   my ($debit, $credit, $taxtotal);
 
1094   for my $i (1 .. $form->{rowcount}) {
 
1095     my $dr  = $form->{"debit_$i"};
 
1096     my $cr  = $form->{"credit_$i"};
 
1097     my $tax = $form->{"tax_$i"};
 
1099       $form->error($locale->text('Cannot post transaction with a debit and credit entry for the same account!'));
 
1101     $debit    += $dr + $tax if $dr;
 
1102     $credit   += $cr + $tax if $cr;
 
1103     $taxtotal += $tax if $form->{taxincluded}
 
1106   $form->{taxincluded} = 0 if !$taxtotal;
 
1108   # this is just for the wise guys
 
1109   $form->error($locale->text('Cannot post transaction for a closed period!'))
 
1110     if ($form->date_closed($form->{"transdate"}, \%myconfig));
 
1111   if ($form->round_amount($debit, 2) != $form->round_amount($credit, 2)) {
 
1112     $form->error($locale->text('Out of balance transaction!'));
 
1115   if ($form->round_amount($debit, 2) + $form->round_amount($credit, 2) == 0) {
 
1116     $form->error($locale->text('Empty transaction!'));
 
1119   if ((my $errno = GL->post_transaction(\%myconfig, \%$form)) <= -1) {
 
1122     $err[1] = $locale->text('Cannot have a value in both Debit and Credit!');
 
1123     $err[2] = $locale->text('Debit and credit out of balance!');
 
1124     $err[3] = $locale->text('Cannot post a transaction without a value!');
 
1126     $form->error($err[$errno]);
 
1128   undef($form->{callback});
 
1129   # saving the history
 
1130   if(!exists $form->{addition} && $form->{id} ne "") {
 
1131     $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
 
1132     $form->{addition} = "SAVED";
 
1133     $form->{what_done} = $locale->text("Buchungsnummer") . " = " . $form->{id};
 
1134     $form->save_history;
 
1136   # /saving the history
 
1138   $main::lxdebug->leave_sub();
 
1142   $main::lxdebug->enter_sub();
 
1144   $main::auth->assert('general_ledger');
 
1146   my $form     = $main::form;
 
1147   my $locale   = $main::locale;
 
1149   if ($::myconfig{mandatory_departments} && !$form->{department}) {
 
1150     $form->{saved_message} = $::locale->text('You have to specify a department.');
 
1155   $form->{title}  = $locale->text("$form->{title} General Ledger Transaction");
 
1156   $form->{storno} = 0;
 
1160   remove_draft() if $form->{remove_draft};
 
1162   $form->{callback} = build_std_url("action=add&DONT_LOAD_DRAFT=1", "show_details");
 
1163   $form->redirect($form->{callback});
 
1165   $main::lxdebug->leave_sub();
 
1169   $main::lxdebug->enter_sub();
 
1171   $main::auth->assert('general_ledger');
 
1173   my $form     = $main::form;
 
1177   $main::lxdebug->leave_sub();
 
1182   $main::lxdebug->enter_sub();
 
1184   $main::auth->assert('general_ledger');
 
1186   my $form     = $main::form;
 
1187   my %myconfig = %main::myconfig;
 
1188   my $locale   = $main::locale;
 
1190   # don't cancel cancelled transactions
 
1191   if (IS->has_storno(\%myconfig, $form, 'gl')) {
 
1192     $form->{title} = $locale->text("Cancel Accounts Receivables Transaction");
 
1193     $form->error($locale->text("Transaction has already been cancelled!"));
 
1196   GL->storno($form, \%myconfig, $form->{id});
 
1198   # saving the history
 
1199   if(!exists $form->{addition} && $form->{id} ne "") {
 
1200     $form->{snumbers} = "ordnumber_$form->{ordnumber}";
 
1201     $form->{addition} = "STORNO";
 
1202     $form->save_history;
 
1204   # /saving the history
 
1206   $form->redirect(sprintf $locale->text("Transaction %d cancelled."), $form->{storno_id});
 
1208   $main::lxdebug->leave_sub();
 
1212   call_sub($main::form->{nextsub});