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 ]);
 
 223   my $onload = "focus()"
 
 224              . qq|;setupDateFormat('|. $::myconfig{dateformat} . qq|', '| . $::locale->text("Falsches Datumsformat!") . qq|')|
 
 225              . qq|;setupPoints('|. $::myconfig{numberformat} .   qq|', '| . $::locale->text("wrongformat") . qq|')|;
 
 228   print $::form->parse_html_template('gl/search', {
 
 230     department_label => sub { ("$_[0]{description}--$_[0]{id}")x2 },
 
 231     employee_label => sub { "$_[0]{id}--$_[0]{name}" },
 
 234   $::lxdebug->leave_sub;
 
 237 sub create_subtotal_row {
 
 238   $main::lxdebug->enter_sub();
 
 240   my ($totals, $columns, $column_alignment, $subtotal_columns, $class) = @_;
 
 242   my $form     = $main::form;
 
 243   my %myconfig = %main::myconfig;
 
 245   my $row = { map { $_ => { 'data' => '', 'class' => $class, 'align' => $column_alignment->{$_}, } } @{ $columns } };
 
 247   map { $row->{$_}->{data} = $form->format_amount(\%myconfig, $totals->{$_}, 2) } @{ $subtotal_columns };
 
 249   map { $totals->{$_} = 0 } @{ $subtotal_columns };
 
 251   $main::lxdebug->leave_sub();
 
 256 sub generate_report {
 
 257   $main::lxdebug->enter_sub();
 
 259   $main::auth->assert('general_ledger');
 
 261   my $form     = $main::form;
 
 262   my %myconfig = %main::myconfig;
 
 263   my $locale   = $main::locale;
 
 265   # 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
 
 267   # <form method=post action=gl.pl>
 
 268   # <input type=hidden name=sort value=datesort>    # form->{sort} setzen
 
 269   # <input type=hidden name=nextsub value=generate_report>
 
 271   # anhand von neuer Variable datesort wird jetzt $form->{sort} auf transdate oder gldate gesetzt
 
 272   # damit ist die Hidden Variable "sort" wahrscheinlich sogar überflüssig
 
 274   # ändert man die Sortierreihenfolge per Klick auf eine der Überschriften wird die Variable "sort" per GET übergeben, z.B. id,transdate, gldate, ...
 
 275   # 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
 
 277   if ( $form->{sort} eq 'datesort' ) {   # sollte bei einem Post (Aufruf aus Suchmaske) immer wahr sein
 
 278       # je nachdem ob in Suchmaske "transdate" oder "gldate" ausgesucht wurde erstes Suchergebnis entsprechend sortieren
 
 279       $form->{sort} = $form->{datesort};
 
 283   report_generator_set_default_sort("$form->{datesort}", 1);
 
 284 #  report_generator_set_default_sort('transdate', 1);
 
 286   GL->all_transactions(\%myconfig, \%$form);
 
 288   my %acctype = ('A' => $locale->text('Asset'),
 
 289                  'C' => $locale->text('Contra'),
 
 290                  'L' => $locale->text('Liability'),
 
 291                  'Q' => $locale->text('Equity'),
 
 292                  'I' => $locale->text('Revenue'),
 
 293                  'E' => $locale->text('Expense'),);
 
 295   $form->{title} = $locale->text('Journal');
 
 296   if ($form->{category} ne 'X') {
 
 297     $form->{title} .= " : " . $locale->text($acctype{ $form->{category} });
 
 300   $form->{landscape} = 1;
 
 302   my $ml = ($form->{ml} =~ /(A|E|Q)/) ? -1 : 1;
 
 305     gldate         transdate        id             reference      description
 
 306     notes          source           debit          debit_accno
 
 307     credit         credit_accno     debit_tax      debit_tax_accno
 
 308     credit_tax     credit_tax_accno projectnumbers balance employee
 
 311   # add employee here, so that variable is still known and passed in url when choosing a different sort order in resulting table
 
 312   my @hidden_variables = qw(accno source reference department description notes project_id datefrom dateto employee datesort category l_subtotal);
 
 313   push @hidden_variables, map { "l_${_}" } @columns;
 
 314   foreach ( @hidden_variables ) {
 
 318   my (@options, @date_options);
 
 319   push @options,      $locale->text('Account')     . " : $form->{accno} $form->{account_description}" if ($form->{accno});
 
 320   push @options,      $locale->text('Source')      . " : $form->{source}"                             if ($form->{source});
 
 321   push @options,      $locale->text('Reference')   . " : $form->{reference}"                          if ($form->{reference});
 
 322   push @options,      $locale->text('Description') . " : $form->{description}"                        if ($form->{description});
 
 323   push @options,      $locale->text('Notes')       . " : $form->{notes}"                              if ($form->{notes});
 
 324   push @options,      $locale->text('Employee')       . " : $form->{employee_name}"                              if ($form->{employee_name});
 
 325   my $datesorttext = $form->{datesort} eq 'transdate' ? $locale->text('Invoice Date') :  $locale->text('Booking Date');
 
 326   push @date_options,      "$datesorttext"                              if ($form->{datesort} and ($form->{datefrom} or $form->{dateto}));
 
 327   push @date_options, $locale->text('From'), $locale->date(\%myconfig, $form->{datefrom}, 1)          if ($form->{datefrom});
 
 328   push @date_options, $locale->text('Bis'),  $locale->date(\%myconfig, $form->{dateto},   1)          if ($form->{dateto});
 
 329   push @options,      join(' ', @date_options)                                                        if (scalar @date_options);
 
 331   if ($form->{department}) {
 
 332     my ($department) = split /--/, $form->{department};
 
 333     push @options, $locale->text('Department') . " : $department";
 
 337   my $callback = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
 
 341   $form->{l_credit_accno}     = 'Y';
 
 342   $form->{l_debit_accno}      = 'Y';
 
 343   $form->{l_credit_tax}       = 'Y';
 
 344   $form->{l_debit_tax}        = 'Y';
 
 345 #  $form->{l_gldate}           = 'Y';  # Spalte mit gldate immer anzeigen
 
 346   $form->{l_credit_tax_accno} = 'Y';
 
 347   $form->{l_datesort} = 'Y';
 
 348   $form->{l_debit_tax_accno}  = 'Y';
 
 349   $form->{l_balance}          = $form->{accno} ? 'Y' : '';
 
 352     'id'               => { 'text' => $locale->text('ID'), },
 
 353     'transdate'        => { 'text' => $locale->text('Invoice Date'), },
 
 354     'gldate'           => { 'text' => $locale->text('Booking Date'), },
 
 355     'reference'        => { 'text' => $locale->text('Reference'), },
 
 356     'source'           => { 'text' => $locale->text('Source'), },
 
 357     'description'      => { 'text' => $locale->text('Description'), },
 
 358     'notes'            => { 'text' => $locale->text('Notes'), },
 
 359     'debit'            => { 'text' => $locale->text('Debit'), },
 
 360     'debit_accno'      => { 'text' => $locale->text('Debit Account'), },
 
 361     'credit'           => { 'text' => $locale->text('Credit'), },
 
 362     'credit_accno'     => { 'text' => $locale->text('Credit Account'), },
 
 363     'debit_tax'        => { 'text' => $locale->text('Debit Tax'), },
 
 364     'debit_tax_accno'  => { 'text' => $locale->text('Debit Tax Account'), },
 
 365     'credit_tax'       => { 'text' => $locale->text('Credit Tax'), },
 
 366     'credit_tax_accno' => { 'text' => $locale->text('Credit Tax Account'), },
 
 367     'balance'          => { 'text' => $locale->text('Balance'), },
 
 368     'projectnumbers'   => { 'text' => $locale->text('Project Numbers'), },
 
 369     'employee'         => { 'text' => $locale->text('Employee'), },
 
 372   foreach my $name (qw(id transdate gldate reference description debit_accno credit_accno debit_tax_accno credit_tax_accno)) {
 
 373     my $sortname                = $name =~ m/accno/ ? 'accno' : $name;
 
 374     my $sortdir                 = $sortname eq $form->{sort} ? 1 - $form->{sortdir} : $form->{sortdir};
 
 375     $column_defs{$name}->{link} = $callback . "&sort=$sortname&sortdir=$sortdir";
 
 378   map { $column_defs{$_}->{visible} = $form->{"l_${_}"} ? 1 : 0 } @columns;
 
 379   map { $column_defs{$_}->{visible} = 0 } qw(debit_accno credit_accno debit_tax_accno credit_tax_accno) if $form->{accno};
 
 381   my %column_alignment;
 
 382   map { $column_alignment{$_}     = 'right'  } qw(balance id debit credit debit_tax credit_tax balance);
 
 383   map { $column_alignment{$_}     = 'center' } qw(transdate gldate reference debit_accno credit_accno debit_tax_accno credit_tax_accno);
 
 384   map { $column_alignment{$_}     = 'left' } qw(description source notes);
 
 385   map { $column_defs{$_}->{align} = $column_alignment{$_} } keys %column_alignment;
 
 387   my $report = SL::ReportGenerator->new(\%myconfig, $form);
 
 389   $report->set_columns(%column_defs);
 
 390   $report->set_column_order(@columns);
 
 392   $report->set_export_options('generate_report', @hidden_variables, qw(sort sortdir));
 
 394   $report->set_sort_indicator($form->{sort} eq 'accno' ? 'debit_accno' : $form->{sort}, $form->{sortdir});
 
 396   $report->set_options('top_info_text'        => join("\n", @options),
 
 397                        'output_format'        => 'HTML',
 
 398                        'title'                => $form->{title},
 
 399                        'attachment_basename'  => $locale->text('general_ledger_list') . strftime('_%Y%m%d', localtime time),
 
 401   $report->set_options_from_form();
 
 402   $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
 
 404   # add sort to callback
 
 405   $form->{callback} = "$callback&sort=" . E($form->{sort}) . "&sortdir=" . E($form->{sortdir});
 
 408   my @totals_columns = qw(debit credit debit_tax credit_tax);
 
 409   my %subtotals      = map { $_ => 0 } @totals_columns;
 
 410   my %totals         = map { $_ => 0 } @totals_columns;
 
 413   foreach my $ref (@{ $form->{GL} }) {
 
 417     foreach my $key (qw(debit credit debit_tax credit_tax)) {
 
 419       foreach my $idx (sort keys(%{ $ref->{$key} })) {
 
 420         my $value         = $ref->{$key}->{$idx};
 
 421         $subtotals{$key} += $value;
 
 422         $totals{$key}    += $value;
 
 423         if ($key =~ /debit.*/) {
 
 428         $form->{balance}  = $form->{balance} + $value * $ml;
 
 429         push @{ $rows{$key} }, $form->format_amount(\%myconfig, $value, 2);
 
 433     foreach my $key (qw(debit_accno credit_accno debit_tax_accno credit_tax_accno ac_transdate source)) {
 
 434       my $col = $key eq 'ac_transdate' ? 'transdate' : $key;
 
 435       $rows{$col} = [ map { $ref->{$key}->{$_} } sort keys(%{ $ref->{$key} }) ];
 
 439     map { $row->{$_} = { 'data' => '', 'align' => $column_alignment{$_} } } @columns;
 
 442     if ($form->{balance} < 0) {
 
 445     } elsif ($form->{balance} > 0) {
 
 449     my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
 
 452     $row->{balance}->{data}        = $data;
 
 453     $row->{projectnumbers}->{data} = join ", ", sort { lc($a) cmp lc($b) } keys %{ $ref->{projectnumbers} };
 
 455     map { $row->{$_}->{data} = $ref->{$_} } qw(id reference description notes gldate employee);
 
 457     map { $row->{$_}->{data} = \@{ $rows{$_} }; } qw(transdate debit credit debit_accno credit_accno debit_tax_accno credit_tax_accno source);
 
 459     foreach my $col (qw(debit_accno credit_accno debit_tax_accno credit_tax_accno)) {
 
 460       $row->{$col}->{link} = [ map { "${callback}&accno=" . E($_) } @{ $rows{$col} } ];
 
 463     map { $row->{$_}->{data} = \@{ $rows{$_} } if ($ref->{"${_}_accno"} ne "") } qw(debit_tax credit_tax);
 
 465     $row->{reference}->{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'id=' . E($ref->{id}), 'callback');
 
 467     my $row_set = [ $row ];
 
 469     if ( ($form->{l_subtotal} eq 'Y' && !$form->{report_generator_csv_options_for_import} )
 
 470         && (($idx == (scalar @{ $form->{GL} } - 1))
 
 471             || ($ref->{ $form->{sort} } ne $form->{GL}->[$idx + 1]->{ $form->{sort} }))) {
 
 472       push @{ $row_set }, create_subtotal_row(\%subtotals, \@columns, \%column_alignment, [ qw(debit credit) ], 'listsubtotal');
 
 475     $report->add_data($row_set);
 
 480   # = 0 for balanced ledger
 
 481   my $balanced_ledger = $totals{debit} + $totals{debit_tax} - $totals{credit} - $totals{credit_tax};
 
 483   my $row = create_subtotal_row(\%totals, \@columns, \%column_alignment, [ qw(debit credit debit_tax credit_tax) ], 'listtotal');
 
 486   if ($form->{balance} < 0) {
 
 489   } elsif ($form->{balance} > 0) {
 
 493   my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
 
 496   $row->{balance}->{data}        = $data;
 
 498   if ( !$form->{report_generator_csv_options_for_import} ) {
 
 499     $report->add_separator();
 
 500     $report->add_data($row);
 
 503   my $raw_bottom_info_text;
 
 505   if (!$form->{accno} && (abs($balanced_ledger) >  0.001)) {
 
 506     $raw_bottom_info_text .=
 
 507         '<p><span class="unbalanced_ledger">'
 
 508       . $locale->text('Unbalanced Ledger')
 
 510       . $form->format_amount(\%myconfig, $balanced_ledger, 3)
 
 514   $raw_bottom_info_text .= $form->parse_html_template('gl/generate_report_bottom');
 
 516   $report->set_options('raw_bottom_info_text' => $raw_bottom_info_text);
 
 518   $report->generate_with_headers();
 
 520   $main::lxdebug->leave_sub();
 
 524   $main::lxdebug->enter_sub();
 
 526   $main::auth->assert('general_ledger');
 
 528   my $form     = $main::form;
 
 529   my %myconfig = %main::myconfig;
 
 531   $form->{oldtransdate} = $form->{transdate};
 
 539   my ($debitcredit, $amount);
 
 542     qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
 
 544   for my $i (1 .. $form->{rowcount}) {
 
 546     unless (($form->{"debit_$i"} eq "") && ($form->{"credit_$i"} eq "")) {
 
 547       for (qw(debit credit tax)) {
 
 549           $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
 
 553       $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
 
 560       if (($debitcount >= 2) && ($creditcount == 2)) {
 
 561         $form->{"credit_$i"} = 0;
 
 562         $form->{"tax_$i"}    = 0;
 
 564         $form->{creditlock} = 1;
 
 566       if (($creditcount >= 2) && ($debitcount == 2)) {
 
 567         $form->{"debit_$i"} = 0;
 
 568         $form->{"tax_$i"}   = 0;
 
 570         $form->{debitlock} = 1;
 
 572       if (($creditcount == 1) && ($debitcount == 2)) {
 
 573         $form->{creditlock} = 1;
 
 575       if (($creditcount == 2) && ($debitcount == 1)) {
 
 576         $form->{debitlock} = 1;
 
 578       if ($debitcredit && $credittax) {
 
 579         $form->{"taxchart_$i"} = "0--0.00";
 
 581       if (!$debitcredit && $debittax) {
 
 582         $form->{"taxchart_$i"} = "0--0.00";
 
 585         ($form->{"debit_$i"} == 0)
 
 586         ? $form->{"credit_$i"}
 
 587         : $form->{"debit_$i"};
 
 589       if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
 
 590         $form->{"taxchart_$i"} = "0--0.00";
 
 591         $form->{"tax_$i"}      = 0;
 
 593       my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
 
 600         if ($form->{taxincluded}) {
 
 601           $form->{"tax_$i"} = $amount / ($rate + 1) * $rate;
 
 603           $form->{"tax_$i"} = $amount * $rate;
 
 606         $form->{"tax_$i"} = 0;
 
 609       for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
 
 614   for my $i (1 .. $count) {
 
 616     for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
 
 619   for my $i ($count + 1 .. $form->{rowcount}) {
 
 620     for (@flds) { delete $form->{"${_}_$i"} }
 
 623   $form->{rowcount} = $count + 1;
 
 626   $main::lxdebug->leave_sub();
 
 632   $main::lxdebug->enter_sub();
 
 634   $main::auth->assert('general_ledger');
 
 636   my $form     = $main::form;
 
 637   my %myconfig = %main::myconfig;
 
 641   #   for $i (1 .. $form->{rowcount}) {
 
 642   #     $form->{totaldebit} += $form->parse_amount(\%myconfig, $form->{"debit_$i"});
 
 643   #     $form->{totalcredit} += $form->parse_amount(\%myconfig, $form->{"credit_$i"});
 
 647   &display_rows($init);
 
 649   $main::lxdebug->leave_sub();
 
 655   $main::lxdebug->enter_sub();
 
 657   $main::auth->assert('general_ledger');
 
 659   my $form     = $main::form;
 
 660   my %myconfig = %main::myconfig;
 
 661   my $cgi      = $::request->{cgi};
 
 663   $form->{debit_1}     = 0 if !$form->{"debit_1"};
 
 664   $form->{totaldebit}  = 0;
 
 665   $form->{totalcredit} = 0;
 
 667   my %project_labels = ();
 
 668   my @project_values = ("");
 
 669   foreach my $item (@{ $form->{"ALL_PROJECTS"} }) {
 
 670     push(@project_values, $item->{"id"});
 
 671     $project_labels{$item->{"id"}} = $item->{"projectnumber"};
 
 674   my %chart_labels = ();
 
 675   my @chart_values = ();
 
 678   foreach my $item (@{ $form->{ALL_CHARTS} }) {
 
 679     if ($item->{charttype} eq 'H'){ #falls überschrift
 
 680       next;                         #überspringen (Bug 1150)
 
 682     my $key = $item->{accno} . "--" . $item->{tax_id};
 
 683     $taxchart_init = $item->{tax_id} unless (@chart_values);
 
 684     push(@chart_values, $key);
 
 685     $chart_labels{$key} = $item->{accno} . "--" . $item->{description};
 
 686     $charts{$item->{accno}} = $item;
 
 689   my %taxchart_labels = ();
 
 690   my @taxchart_values = ();
 
 692   foreach my $item (@{ $form->{ALL_TAXCHARTS} }) {
 
 693     my $key = $item->{id} . "--" . $item->{rate};
 
 694     $taxchart_init = $key if ($taxchart_init == $item->{id});
 
 695     push(@taxchart_values, $key);
 
 696     $taxchart_labels{$key} = $item->{taxdescription} . " " . $item->{rate} * 100 . ' %';
 
 697     $taxcharts{$item->{id}} = $item;
 
 700   my ($source, $memo, $source_hidden, $memo_hidden);
 
 701   for my $i (1 .. $form->{rowcount}) {
 
 702     if ($form->{show_details}) {
 
 704       <td><input name="source_$i" value="$form->{"source_$i"}" size="16"></td>|;
 
 706       <td><input name="memo_$i" value="$form->{"memo_$i"}" size="16"></td>|;
 
 709       <input type="hidden" name="source_$i" value="$form->{"source_$i"}" size="16">|;
 
 711       <input type="hidden" name="memo_$i" value="$form->{"memo_$i"}" size="16">|;
 
 714     my $selected_accno_full;
 
 715     my ($accno_row) = split(/--/, $form->{"accno_$i"});
 
 716     my $item = $charts{$accno_row};
 
 717     $selected_accno_full = "$item->{accno}--$item->{tax_id}";
 
 719     my $selected_taxchart = $form->{"taxchart_$i"};
 
 720     my ($selected_accno, $selected_tax_id) = split(/--/, $selected_accno_full);
 
 721     my ($previous_accno, $previous_tax_id) = split(/--/, $form->{"previous_accno_$i"});
 
 723     if ($previous_accno &&
 
 724         ($previous_accno eq $selected_accno) &&
 
 725         ($previous_tax_id ne $selected_tax_id)) {
 
 726       my $item = $taxcharts{$selected_tax_id};
 
 727       $selected_taxchart = "$item->{id}--$item->{rate}";
 
 730     $selected_accno      = '' if ($init);
 
 731     $selected_taxchart ||= $taxchart_init;
 
 733     my $accno = qq|<td>| .
 
 734       NTI($cgi->popup_menu('-name' => "accno_$i",
 
 736                            '-onChange' => "setTaxkey($i)",
 
 737                            '-style' => 'width:200px',
 
 738                            '-values' => \@chart_values,
 
 739                            '-labels' => \%chart_labels,
 
 740                            '-default' => $selected_accno_full))
 
 741       . $cgi->hidden('-name' => "previous_accno_$i",
 
 742                      '-default' => $selected_accno_full)
 
 744     my $tax_ddbox = qq|<td>| .
 
 745       NTI($cgi->popup_menu('-name' => "taxchart_$i",
 
 746                            '-id' => "taxchart_$i",
 
 747                            '-style' => 'width:200px',
 
 748                            '-values' => \@taxchart_values,
 
 749                            '-labels' => \%taxchart_labels,
 
 750                            '-default' => $selected_taxchart))
 
 753     my ($fx_transaction, $checked);
 
 755       if ($form->{transfer}) {
 
 756         $fx_transaction = qq|
 
 757         <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
 
 762       if ($form->{"debit_$i"} != 0) {
 
 763         $form->{totaldebit} += $form->{"debit_$i"};
 
 764         if (!$form->{taxincluded}) {
 
 765           $form->{totaldebit} += $form->{"tax_$i"};
 
 768         $form->{totalcredit} += $form->{"credit_$i"};
 
 769         if (!$form->{taxincluded}) {
 
 770           $form->{totalcredit} += $form->{"tax_$i"};
 
 774       for (qw(debit credit tax)) {
 
 777           ? $form->format_amount(\%myconfig, $form->{"${_}_$i"}, 2)
 
 781       if ($i < $form->{rowcount}) {
 
 782         if ($form->{transfer}) {
 
 783           $checked = ($form->{"fx_transaction_$i"}) ? "1" : "";
 
 784           my $x = ($checked) ? "x" : "";
 
 785           $fx_transaction = qq|
 
 786       <td><input type=hidden name="fx_transaction_$i" value="$checked">$x</td>
 
 789         $form->hide_form("accno_$i");
 
 792         if ($form->{transfer}) {
 
 793           $fx_transaction = qq|
 
 794       <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
 
 799     my $debitreadonly  = "";
 
 800     my $creditreadonly = "";
 
 801     if ($i == $form->{rowcount}) {
 
 802       if ($form->{debitlock}) {
 
 803         $debitreadonly = "readonly";
 
 804       } elsif ($form->{creditlock}) {
 
 805         $creditreadonly = "readonly";
 
 810       NTI($cgi->popup_menu('-name' => "project_id_$i",
 
 811                            '-values' => \@project_values,
 
 812                            '-labels' => \%project_labels,
 
 813                            '-default' => $form->{"project_id_$i"} ));
 
 814     my $projectnumber_hidden = qq|
 
 815     <input type="hidden" name="project_id_$i" value="$form->{"project_id_$i"}">|;
 
 817     my $copy2credit = $i == 1 ? 'onkeyup="copy_debit_to_credit()"' : '';
 
 819     print qq|<tr valign=top>
 
 821     <td id="chart_balance_$i" align="right"> </td>
 
 823     <td><input name="debit_$i" size="8" value="$form->{"debit_$i"}" accesskey=$i $copy2credit $debitreadonly></td>
 
 824     <td><input name="credit_$i" size=8 value="$form->{"credit_$i"}" $creditreadonly></td>
 
 825     <td><input type="hidden" name="tax_$i" value="$form->{"tax_$i"}">$form->{"tax_$i"}</td>
 
 828     if ($form->{show_details}) {
 
 832     <td>$projectnumber</td>
 
 838     $projectnumber_hidden
 
 846   $form->hide_form(qw(rowcount selectaccno));
 
 848   $main::lxdebug->leave_sub();
 
 853   $::lxdebug->enter_sub;
 
 854   $::auth->assert('general_ledger');
 
 858   my @old_project_ids = grep { $_ } map{ $::form->{"project_id_$_"} } 1..$::form->{rowcount};
 
 860   $::form->get_lists("projects"  => { "key"       => "ALL_PROJECTS",
 
 862                                     "old_id"    => \@old_project_ids },
 
 863                    "charts"    => { "key"       => "ALL_CHARTS",
 
 864                                     "transdate" => $::form->{transdate} },
 
 865                    "taxcharts" => "ALL_TAXCHARTS");
 
 867   GL->get_chart_balances('charts' => $::form->{ALL_CHARTS});
 
 869   my $title      = $::form->{title};
 
 870   $::form->{title} = $::locale->text("$title General Ledger Transaction");
 
 871   # $locale->text('Add General Ledger Transaction')
 
 872   # $locale->text('Edit General Ledger Transaction')
 
 874   map { $::form->{$_} =~ s/\"/"/g }
 
 877   $::form->{selectdepartment} =~ s/ selected//;
 
 878   $::form->{selectdepartment} =~
 
 879     s/option>\Q$::form->{department}\E/option selected>$::form->{department}/;
 
 882     $::form->{fokus} = "gl.reference";
 
 883     $::form->{taxincluded} = "1";
 
 885     $::form->{fokus} = qq|gl.accno_$::form->{rowcount}|;
 
 888   $::form->{previous_id}     ||= "--";
 
 889   $::form->{previous_gldate} ||= "--";
 
 892   print $::form->parse_html_template('gl/form_header', {
 
 893     hide_title => $title,
 
 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   my $radieren = $::form->current_date(\%::myconfig) eq $::form->{gldate};
 
 913   print $::form->parse_html_template('gl/form_footer', {
 
 914     radieren       => $radieren,
 
 915     follow_ups     => $follow_ups,
 
 916     follow_ups_due => $follow_ups_due,
 
 919   $::lxdebug->leave_sub;
 
 923   $main::lxdebug->enter_sub();
 
 925   my $form     = $main::form;
 
 926   my $locale   = $main::locale;
 
 933 <form method=post action=gl.pl>
 
 936   map { $form->{$_} =~ s/\"/"/g } qw(reference description);
 
 938   delete $form->{header};
 
 940   foreach my $key (keys %$form) {
 
 941     next if (($key eq 'login') || ($key eq 'password') || ('' ne ref $form->{$key}));
 
 942     print qq|<input type="hidden" name="$key" value="$form->{$key}">\n|;
 
 946 <h2 class=confirm>| . $locale->text('Confirm!') . qq|</h2>
 
 949     . $locale->text('Are you sure you want to delete Transaction')
 
 950     . qq| $form->{reference}</h4>
 
 952 <input name=action class=submit type=submit value="|
 
 953     . $locale->text('Yes') . qq|">
 
 956   $main::lxdebug->leave_sub();
 
 961   $main::lxdebug->enter_sub();
 
 963   my $form     = $main::form;
 
 964   my %myconfig = %main::myconfig;
 
 965   my $locale   = $main::locale;
 
 967   if (GL->delete_transaction(\%myconfig, \%$form)){
 
 969       if(!exists $form->{addition} && $form->{id} ne "") {
 
 970         $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
 
 971         $form->{addition} = "DELETED";
 
 974     # /saving the history
 
 975     $form->redirect($locale->text('Transaction deleted!'))
 
 977   $form->error($locale->text('Cannot delete transaction!'));
 
 978   $main::lxdebug->leave_sub();
 
 982 sub post_transaction {
 
 983   $main::lxdebug->enter_sub();
 
 985   my $form     = $main::form;
 
 986   my %myconfig = %main::myconfig;
 
 987   my $locale   = $main::locale;
 
 989   # check if there is something in reference and date
 
 990   $form->isblank("reference",   $locale->text('Reference missing!'));
 
 991   $form->isblank("transdate",   $locale->text('Transaction Date missing!'));
 
 992   $form->isblank("description", $locale->text('Description missing!'));
 
 994   my $transdate = $form->datetonum($form->{transdate}, \%myconfig);
 
 995   my $closedto  = $form->datetonum($form->{closedto},  \%myconfig);
 
1002   my $creditcount = 0;
 
1004   my %split_safety = ();
 
1006   my @flds = qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
 
1008   for my $i (1 .. $form->{rowcount}) {
 
1009     next if $form->{"debit_$i"} eq "" && $form->{"credit_$i"} eq "";
 
1011     for (qw(debit credit tax)) {
 
1012       $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
 
1016     $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
 
1018     $split_safety{   $form->{"debit_$i"}  <=> 0 }++;
 
1019     $split_safety{ - $form->{"credit_$i"} <=> 0 }++;
 
1027     if (($debitcount >= 2) && ($creditcount == 2)) {
 
1028       $form->{"credit_$i"} = 0;
 
1029       $form->{"tax_$i"}    = 0;
 
1031       $form->{creditlock} = 1;
 
1033     if (($creditcount >= 2) && ($debitcount == 2)) {
 
1034       $form->{"debit_$i"} = 0;
 
1035       $form->{"tax_$i"}   = 0;
 
1037       $form->{debitlock} = 1;
 
1039     if (($creditcount == 1) && ($debitcount == 2)) {
 
1040       $form->{creditlock} = 1;
 
1042     if (($creditcount == 2) && ($debitcount == 1)) {
 
1043       $form->{debitlock} = 1;
 
1045     if ($debitcredit && $credittax) {
 
1046       $form->{"taxchart_$i"} = "0--0.00";
 
1048     if (!$debitcredit && $debittax) {
 
1049       $form->{"taxchart_$i"} = "0--0.00";
 
1051     my $amount = ($form->{"debit_$i"} == 0)
 
1052             ? $form->{"credit_$i"}
 
1053             : $form->{"debit_$i"};
 
1055     if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
 
1056       $form->{"taxchart_$i"} = "0--0.00";
 
1057       $form->{"tax_$i"}      = 0;
 
1059     my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
 
1066       if ($form->{taxincluded}) {
 
1067         $form->{"tax_$i"} = $amount / ($rate + 1) * $rate;
 
1069           $form->{"debit_$i"} = $form->{"debit_$i"} - $form->{"tax_$i"};
 
1071           $form->{"credit_$i"} = $form->{"credit_$i"} - $form->{"tax_$i"};
 
1074         $form->{"tax_$i"} = $amount * $rate;
 
1077       $form->{"tax_$i"} = 0;
 
1080     for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
 
1084   if ($split_safety{-1} > 1 && $split_safety{1} > 1) {
 
1085     $::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."));
 
1088   for my $i (1 .. $count) {
 
1090     for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
 
1093   for my $i ($count + 1 .. $form->{rowcount}) {
 
1094     for (@flds) { delete $form->{"${_}_$i"} }
 
1097   my ($debit, $credit, $taxtotal);
 
1098   for my $i (1 .. $form->{rowcount}) {
 
1099     my $dr  = $form->{"debit_$i"};
 
1100     my $cr  = $form->{"credit_$i"};
 
1101     my $tax = $form->{"tax_$i"};
 
1103       $form->error($locale->text('Cannot post transaction with a debit and credit entry for the same account!'));
 
1105     $debit    += $dr + $tax if $dr;
 
1106     $credit   += $cr + $tax if $cr;
 
1107     $taxtotal += $tax if $form->{taxincluded}
 
1110   $form->{taxincluded} = 0 if !$taxtotal;
 
1112   # this is just for the wise guys
 
1113   $form->error($locale->text('Cannot post transaction for a closed period!'))
 
1114     if ($form->date_closed($form->{"transdate"}, \%myconfig));
 
1115   if ($form->round_amount($debit, 2) != $form->round_amount($credit, 2)) {
 
1116     $form->error($locale->text('Out of balance transaction!'));
 
1119   if ($form->round_amount($debit, 2) + $form->round_amount($credit, 2) == 0) {
 
1120     $form->error($locale->text('Empty transaction!'));
 
1123   if ((my $errno = GL->post_transaction(\%myconfig, \%$form)) <= -1) {
 
1126     $err[1] = $locale->text('Cannot have a value in both Debit and Credit!');
 
1127     $err[2] = $locale->text('Debit and credit out of balance!');
 
1128     $err[3] = $locale->text('Cannot post a transaction without a value!');
 
1130     $form->error($err[$errno]);
 
1132   undef($form->{callback});
 
1133   # saving the history
 
1134   if(!exists $form->{addition} && $form->{id} ne "") {
 
1135     $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
 
1136     $form->{addition} = "SAVED";
 
1137     $form->{what_done} = $locale->text("Buchungsnummer") . " = " . $form->{id};
 
1138     $form->save_history;
 
1140   # /saving the history
 
1142   $main::lxdebug->leave_sub();
 
1146   $main::lxdebug->enter_sub();
 
1148   $main::auth->assert('general_ledger');
 
1150   my $form     = $main::form;
 
1151   my $locale   = $main::locale;
 
1153   if ($::myconfig{mandatory_departments} && !$form->{department}) {
 
1154     $form->{saved_message} = $::locale->text('You have to specify a department.');
 
1159   $form->{title}  = $locale->text("$form->{title} General Ledger Transaction");
 
1160   $form->{storno} = 0;
 
1164   remove_draft() if $form->{remove_draft};
 
1166   $form->{callback} = build_std_url("action=add&DONT_LOAD_DRAFT=1", "show_details");
 
1167   $form->redirect($form->{callback});
 
1169   $main::lxdebug->leave_sub();
 
1173   $main::lxdebug->enter_sub();
 
1175   $main::auth->assert('general_ledger');
 
1177   my $form     = $main::form;
 
1181   $main::lxdebug->leave_sub();
 
1186   $main::lxdebug->enter_sub();
 
1188   $main::auth->assert('general_ledger');
 
1190   my $form     = $main::form;
 
1191   my %myconfig = %main::myconfig;
 
1192   my $locale   = $main::locale;
 
1194   # don't cancel cancelled transactions
 
1195   if (IS->has_storno(\%myconfig, $form, 'gl')) {
 
1196     $form->{title} = $locale->text("Cancel Accounts Receivables Transaction");
 
1197     $form->error($locale->text("Transaction has already been cancelled!"));
 
1200   GL->storno($form, \%myconfig, $form->{id});
 
1202   # saving the history
 
1203   if(!exists $form->{addition} && $form->{id} ne "") {
 
1204     $form->{snumbers} = "ordnumber_$form->{ordnumber}";
 
1205     $form->{addition} = "STORNO";
 
1206     $form->save_history;
 
1208   # /saving the history
 
1210   $form->redirect(sprintf $locale->text("Transaction %d cancelled."), $form->{storno_id});
 
1212   $main::lxdebug->leave_sub();
 
1216   call_sub($main::form->{nextsub});