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   $::lxdebug->enter_sub;
 
 849   $::auth->assert('general_ledger');
 
 853   my @old_project_ids = grep { $_ } map{ $::form->{"project_id_$_"} } 1..$::form->{rowcount};
 
 855   $::form->get_lists("projects"  => { "key"       => "ALL_PROJECTS",
 
 857                                     "old_id"    => \@old_project_ids },
 
 858                    "charts"    => { "key"       => "ALL_CHARTS",
 
 859                                     "transdate" => $::form->{transdate} },
 
 860                    "taxcharts" => "ALL_TAXCHARTS");
 
 862   GL->get_chart_balances('charts' => $::form->{ALL_CHARTS});
 
 864   my $title      = $::form->{title};
 
 865   $::form->{title} = $::locale->text("$title General Ledger Transaction");
 
 866   # $locale->text('Add General Ledger Transaction')
 
 867   # $locale->text('Edit General Ledger Transaction')
 
 869   map { $::form->{$_} =~ s/\"/"/g }
 
 872   $::form->{selectdepartment} =~ s/ selected//;
 
 873   $::form->{selectdepartment} =~
 
 874     s/option>\Q$::form->{department}\E/option selected>$::form->{department}/;
 
 877     $::form->{fokus} = "gl.reference";
 
 878     $::form->{taxincluded} = "1";
 
 880     $::form->{fokus} = qq|gl.accno_$::form->{rowcount}|;
 
 883   $::form->{previous_id}     ||= "--";
 
 884   $::form->{previous_gldate} ||= "--";
 
 887   print $::form->parse_html_template('gl/form_header', {
 
 888     hide_title => $title,
 
 891   $::lxdebug->leave_sub;
 
 896   $::lxdebug->enter_sub;
 
 897   $::auth->assert('general_ledger');
 
 899   my ($follow_ups, $follow_ups_due);
 
 902     $follow_ups     = FU->follow_ups('trans_id' => $::form->{id});
 
 903     $follow_ups_due = sum map { $_->{due} * 1 } @{ $follow_ups || [] };
 
 906   my $radieren = $::form->current_date(\%::myconfig) eq $::form->{gldate};
 
 908   print $::form->parse_html_template('gl/form_footer', {
 
 909     radieren       => $radieren,
 
 910     follow_ups     => $follow_ups,
 
 911     follow_ups_due => $follow_ups_due,
 
 914   $::lxdebug->leave_sub;
 
 918   $main::lxdebug->enter_sub();
 
 920   my $form     = $main::form;
 
 921   my $locale   = $main::locale;
 
 926 <form method=post action=gl.pl>
 
 929   map { $form->{$_} =~ s/\"/"/g } qw(reference description);
 
 931   delete $form->{header};
 
 933   foreach my $key (keys %$form) {
 
 934     next if (($key eq 'login') || ($key eq 'password') || ('' ne ref $form->{$key}));
 
 935     print qq|<input type="hidden" name="$key" value="$form->{$key}">\n|;
 
 939 <h2 class=confirm>| . $locale->text('Confirm!') . qq|</h2>
 
 942     . $locale->text('Are you sure you want to delete Transaction')
 
 943     . qq| $form->{reference}</h4>
 
 945 <input name=action class=submit type=submit value="|
 
 946     . $locale->text('Yes') . qq|">
 
 949   $main::lxdebug->leave_sub();
 
 954   $main::lxdebug->enter_sub();
 
 956   my $form     = $main::form;
 
 957   my %myconfig = %main::myconfig;
 
 958   my $locale   = $main::locale;
 
 960   if (GL->delete_transaction(\%myconfig, \%$form)){
 
 962       if(!exists $form->{addition} && $form->{id} ne "") {
 
 963         $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
 
 964         $form->{addition} = "DELETED";
 
 967     # /saving the history
 
 968     $form->redirect($locale->text('Transaction deleted!'))
 
 970   $form->error($locale->text('Cannot delete transaction!'));
 
 971   $main::lxdebug->leave_sub();
 
 975 sub post_transaction {
 
 976   $main::lxdebug->enter_sub();
 
 978   my $form     = $main::form;
 
 979   my %myconfig = %main::myconfig;
 
 980   my $locale   = $main::locale;
 
 982   # check if there is something in reference and date
 
 983   $form->isblank("reference",   $locale->text('Reference missing!'));
 
 984   $form->isblank("transdate",   $locale->text('Transaction Date missing!'));
 
 985   $form->isblank("description", $locale->text('Description missing!'));
 
 987   my $transdate = $form->datetonum($form->{transdate}, \%myconfig);
 
 988   my $closedto  = $form->datetonum($form->{closedto},  \%myconfig);
 
 997   my %split_safety = ();
 
 999   my @flds = qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
 
1001   for my $i (1 .. $form->{rowcount}) {
 
1002     next if $form->{"debit_$i"} eq "" && $form->{"credit_$i"} eq "";
 
1004     for (qw(debit credit tax)) {
 
1005       $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
 
1009     $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
 
1011     $split_safety{   $form->{"debit_$i"}  <=> 0 }++;
 
1012     $split_safety{ - $form->{"credit_$i"} <=> 0 }++;
 
1020     if (($debitcount >= 2) && ($creditcount == 2)) {
 
1021       $form->{"credit_$i"} = 0;
 
1022       $form->{"tax_$i"}    = 0;
 
1024       $form->{creditlock} = 1;
 
1026     if (($creditcount >= 2) && ($debitcount == 2)) {
 
1027       $form->{"debit_$i"} = 0;
 
1028       $form->{"tax_$i"}   = 0;
 
1030       $form->{debitlock} = 1;
 
1032     if (($creditcount == 1) && ($debitcount == 2)) {
 
1033       $form->{creditlock} = 1;
 
1035     if (($creditcount == 2) && ($debitcount == 1)) {
 
1036       $form->{debitlock} = 1;
 
1038     if ($debitcredit && $credittax) {
 
1039       $form->{"taxchart_$i"} = "0--0.00";
 
1041     if (!$debitcredit && $debittax) {
 
1042       $form->{"taxchart_$i"} = "0--0.00";
 
1044     my $amount = ($form->{"debit_$i"} == 0)
 
1045             ? $form->{"credit_$i"}
 
1046             : $form->{"debit_$i"};
 
1048     if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
 
1049       $form->{"taxchart_$i"} = "0--0.00";
 
1050       $form->{"tax_$i"}      = 0;
 
1052     my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
 
1059       if ($form->{taxincluded}) {
 
1060         $form->{"tax_$i"} = $amount / ($rate + 1) * $rate;
 
1062           $form->{"debit_$i"} = $form->{"debit_$i"} - $form->{"tax_$i"};
 
1064           $form->{"credit_$i"} = $form->{"credit_$i"} - $form->{"tax_$i"};
 
1067         $form->{"tax_$i"} = $amount * $rate;
 
1070       $form->{"tax_$i"} = 0;
 
1073     for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
 
1077   if ($split_safety{-1} > 1 && $split_safety{1} > 1) {
 
1078     $::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."));
 
1081   for my $i (1 .. $count) {
 
1083     for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
 
1086   for my $i ($count + 1 .. $form->{rowcount}) {
 
1087     for (@flds) { delete $form->{"${_}_$i"} }
 
1090   my ($debit, $credit, $taxtotal);
 
1091   for my $i (1 .. $form->{rowcount}) {
 
1092     my $dr  = $form->{"debit_$i"};
 
1093     my $cr  = $form->{"credit_$i"};
 
1094     my $tax = $form->{"tax_$i"};
 
1096       $form->error($locale->text('Cannot post transaction with a debit and credit entry for the same account!'));
 
1098     $debit    += $dr + $tax if $dr;
 
1099     $credit   += $cr + $tax if $cr;
 
1100     $taxtotal += $tax if $form->{taxincluded}
 
1103   $form->{taxincluded} = 0 if !$taxtotal;
 
1105   # this is just for the wise guys
 
1106   $form->error($locale->text('Cannot post transaction for a closed period!'))
 
1107     if ($form->date_closed($form->{"transdate"}, \%myconfig));
 
1108   if ($form->round_amount($debit, 2) != $form->round_amount($credit, 2)) {
 
1109     $form->error($locale->text('Out of balance transaction!'));
 
1112   if ($form->round_amount($debit, 2) + $form->round_amount($credit, 2) == 0) {
 
1113     $form->error($locale->text('Empty transaction!'));
 
1116   if ((my $errno = GL->post_transaction(\%myconfig, \%$form)) <= -1) {
 
1119     $err[1] = $locale->text('Cannot have a value in both Debit and Credit!');
 
1120     $err[2] = $locale->text('Debit and credit out of balance!');
 
1121     $err[3] = $locale->text('Cannot post a transaction without a value!');
 
1123     $form->error($err[$errno]);
 
1125   undef($form->{callback});
 
1126   # saving the history
 
1127   if(!exists $form->{addition} && $form->{id} ne "") {
 
1128     $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
 
1129     $form->{addition} = "SAVED";
 
1130     $form->{what_done} = $locale->text("Buchungsnummer") . " = " . $form->{id};
 
1131     $form->save_history;
 
1133   # /saving the history
 
1135   $main::lxdebug->leave_sub();
 
1139   $main::lxdebug->enter_sub();
 
1141   $main::auth->assert('general_ledger');
 
1143   my $form     = $main::form;
 
1144   my $locale   = $main::locale;
 
1146   if ($::myconfig{mandatory_departments} && !$form->{department}) {
 
1147     $form->{saved_message} = $::locale->text('You have to specify a department.');
 
1152   $form->{title}  = $locale->text("$form->{title} General Ledger Transaction");
 
1153   $form->{storno} = 0;
 
1157   remove_draft() if $form->{remove_draft};
 
1159   $form->{callback} = build_std_url("action=add&DONT_LOAD_DRAFT=1", "show_details");
 
1160   $form->redirect($form->{callback});
 
1162   $main::lxdebug->leave_sub();
 
1166   $main::lxdebug->enter_sub();
 
1168   $main::auth->assert('general_ledger');
 
1170   my $form     = $main::form;
 
1174   $main::lxdebug->leave_sub();
 
1179   $main::lxdebug->enter_sub();
 
1181   $main::auth->assert('general_ledger');
 
1183   my $form     = $main::form;
 
1184   my %myconfig = %main::myconfig;
 
1185   my $locale   = $main::locale;
 
1187   # don't cancel cancelled transactions
 
1188   if (IS->has_storno(\%myconfig, $form, 'gl')) {
 
1189     $form->{title} = $locale->text("Cancel Accounts Receivables Transaction");
 
1190     $form->error($locale->text("Transaction has already been cancelled!"));
 
1193   GL->storno($form, \%myconfig, $form->{id});
 
1195   # saving the history
 
1196   if(!exists $form->{addition} && $form->{id} ne "") {
 
1197     $form->{snumbers} = "ordnumber_$form->{ordnumber}";
 
1198     $form->{addition} = "STORNO";
 
1199     $form->save_history;
 
1201   # /saving the history
 
1203   $form->redirect(sprintf $locale->text("Transaction %d cancelled."), $form->{storno_id});
 
1205   $main::lxdebug->leave_sub();
 
1209   call_sub($main::form->{nextsub});