Aufrufe von focus() entfernt.
[kivitendo-erp.git] / bin / mozilla / gl.pl
1 #=====================================================================
2 # LX-Office ERP
3 # Copyright (C) 2004
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
6 #
7 #=====================================================================
8 # SQL-Ledger Accounting
9 # Copyright (c) 1998-2002
10 #
11 #  Author: Dieter Simader
12 #   Email: dsimader@sql-ledger.org
13 #     Web: http://www.sql-ledger.org
14 #
15 #
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.
20 #
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 #======================================================================
29 #
30 # Genereal Ledger
31 #
32 #======================================================================
33
34 use utf8;
35 use strict;
36
37 use POSIX qw(strftime);
38 use List::Util qw(sum);
39
40 use SL::FU;
41 use SL::GL;
42 use SL::IS;
43 use SL::PE;
44 use SL::ReportGenerator;
45
46 require "bin/mozilla/common.pl";
47 require "bin/mozilla/drafts.pl";
48 require "bin/mozilla/reportgenerator.pl";
49
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')
63
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')
77
78 sub add {
79   $main::lxdebug->enter_sub();
80
81   $main::auth->assert('general_ledger');
82
83   my $form     = $main::form;
84   my %myconfig = %main::myconfig;
85
86   return $main::lxdebug->leave_sub() if (load_draft_maybe());
87
88   $form->{title} = "Add";
89
90   $form->{callback} = "gl.pl?action=add" unless $form->{callback};
91
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);
95
96   $form->{rowcount}  = 2;
97
98   $form->{debit}  = 0;
99   $form->{credit} = 0;
100   $form->{tax}    = 0;
101
102   # departments
103   $form->all_departments(\%myconfig);
104   if (@{ $form->{all_departments} || [] }) {
105     $form->{selectdepartment} = "<option>\n";
106
107     map {
108       $form->{selectdepartment} .=
109         "<option>$_->{description}--$_->{id}\n"
110     } (@{ $form->{all_departments} || [] });
111   }
112
113   $form->{show_details} = $myconfig{show_form_details} unless defined $form->{show_details};
114
115   &display_form(1);
116   $main::lxdebug->leave_sub();
117
118 }
119
120 sub prepare_transaction {
121   $main::lxdebug->enter_sub();
122
123   $main::auth->assert('general_ledger');
124
125   my $form     = $main::form;
126   my %myconfig = %main::myconfig;
127
128   GL->transaction(\%myconfig, \%$form);
129
130   $form->{amount} = $form->format_amount(\%myconfig, $form->{amount}, 2);
131
132   # departments
133   $form->all_departments(\%myconfig);
134   if (@{ $form->{all_departments} || [] }) {
135     $form->{selectdepartment} = "<option>\n";
136
137     map {
138       $form->{selectdepartment} .=
139         "<option>$_->{description}--$_->{id}\n"
140     } (@{ $form->{all_departments} || [] });
141   }
142
143   my $i        = 1;
144   my $tax      = 0;
145   my $taxaccno = "";
146   foreach my $ref (@{ $form->{GL} }) {
147     my $j = $i - 1;
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"};
154         } else {
155           $form->{"credit_$j"} += $form->{"tax_$j"};
156         }
157       }
158       $form->{"project_id_$j"} = $ref->{project_id};
159
160     } else {
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;
166       } else {
167         $form->{totalcredit} += $ref->{amount};
168         $form->{"credit_$i"} = $ref->{amount};
169       }
170       $form->{"taxchart_$i"} = "0--0.00";
171       $form->{"project_id_$i"} = $ref->{project_id};
172       $i++;
173     }
174     if ($ref->{taxaccno} && !$tax) {
175       $taxaccno = $ref->{taxaccno};
176       $tax      = 1;
177     } else {
178       $taxaccno = "";
179       $tax      = 0;
180     }
181   }
182
183   $form->{rowcount} = $i;
184   $form->{locked}   =
185     ($form->datetonum($form->{transdate}, \%myconfig) <=
186      $form->datetonum($form->{closedto}, \%myconfig));
187
188   $main::lxdebug->leave_sub();
189 }
190
191 sub edit {
192   $main::lxdebug->enter_sub();
193
194   $main::auth->assert('general_ledger');
195
196   my $form     = $main::form;
197   my %myconfig = %main::myconfig;
198
199   prepare_transaction();
200
201   $form->{title} = "Edit";
202
203   $form->{show_details} = $myconfig{show_form_details} unless defined $form->{show_details};
204
205   form_header();
206   display_rows();
207   form_footer();
208
209   $main::lxdebug->leave_sub();
210 }
211
212
213 sub search {
214   $::lxdebug->enter_sub;
215   $::auth->assert('general_ledger');
216
217   $::form->all_departments(\%::myconfig);
218   $::form->get_lists(
219     projects  => { key => "ALL_PROJECTS", all => 1 },
220   );
221   $::form->{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all(query => [ deleted => 0 ]);
222
223   $::form->header;
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}" },
227   });
228
229   $::lxdebug->leave_sub;
230 }
231
232 sub create_subtotal_row {
233   $main::lxdebug->enter_sub();
234
235   my ($totals, $columns, $column_alignment, $subtotal_columns, $class) = @_;
236
237   my $form     = $main::form;
238   my %myconfig = %main::myconfig;
239
240   my $row = { map { $_ => { 'data' => '', 'class' => $class, 'align' => $column_alignment->{$_}, } } @{ $columns } };
241
242   map { $row->{$_}->{data} = $form->format_amount(\%myconfig, $totals->{$_}, 2) } @{ $subtotal_columns };
243
244   map { $totals->{$_} = 0 } @{ $subtotal_columns };
245
246   $main::lxdebug->leave_sub();
247
248   return $row;
249 }
250
251 sub generate_report {
252   $main::lxdebug->enter_sub();
253
254   $main::auth->assert('general_ledger');
255
256   my $form     = $main::form;
257   my %myconfig = %main::myconfig;
258   my $locale   = $main::locale;
259
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
261
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>
265
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
268
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
271
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};
275   };
276
277   # was passiert hier?
278   report_generator_set_default_sort("$form->{datesort}", 1);
279 #  report_generator_set_default_sort('transdate', 1);
280
281   GL->all_transactions(\%myconfig, \%$form);
282
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'),);
289
290   $form->{title} = $locale->text('Journal');
291   if ($form->{category} ne 'X') {
292     $form->{title} .= " : " . $locale->text($acctype{ $form->{category} });
293   }
294
295   $form->{landscape} = 1;
296
297   my $ml = ($form->{ml} =~ /(A|E|Q)/) ? -1 : 1;
298
299   my @columns = qw(
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
304   );
305
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 ) {
310       print URL "$_\n";
311   };
312
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);
325
326   if ($form->{department}) {
327     my ($department) = split /--/, $form->{department};
328     push @options, $locale->text('Department') . " : $department";
329   }
330
331
332   my $callback = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
333   print URL $callback;
334   close URL;
335
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' : '';
345
346   my %column_defs = (
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'), },
365   );
366
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";
371   }
372
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};
375
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;
381
382   my $report = SL::ReportGenerator->new(\%myconfig, $form);
383
384   $report->set_columns(%column_defs);
385   $report->set_column_order(@columns);
386
387   $report->set_export_options('generate_report', @hidden_variables, qw(sort sortdir));
388
389   $report->set_sort_indicator($form->{sort} eq 'accno' ? 'debit_accno' : $form->{sort}, $form->{sortdir});
390
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),
395     );
396   $report->set_options_from_form();
397   $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
398
399   # add sort to callback
400   $form->{callback} = "$callback&sort=" . E($form->{sort}) . "&sortdir=" . E($form->{sortdir});
401
402
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;
406   my $idx            = 0;
407
408   foreach my $ref (@{ $form->{GL} }) {
409
410     my %rows;
411
412     foreach my $key (qw(debit credit debit_tax credit_tax)) {
413       $rows{$key} = [];
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.*/) {
419           $ml = -1;
420         } else {
421           $ml = 1;
422         }
423         $form->{balance}  = $form->{balance} + $value * $ml;
424         push @{ $rows{$key} }, $form->format_amount(\%myconfig, $value, 2);
425       }
426     }
427
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} }) ];
431     }
432
433     my $row = { };
434     map { $row->{$_} = { 'data' => '', 'align' => $column_alignment{$_} } } @columns;
435
436     my $sh = "";
437     if ($form->{balance} < 0) {
438       $sh = " S";
439       $ml = -1;
440     } elsif ($form->{balance} > 0) {
441       $sh = " H";
442       $ml = 1;
443     }
444     my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
445     $data .= $sh;
446
447     $row->{balance}->{data}        = $data;
448     $row->{projectnumbers}->{data} = join ", ", sort { lc($a) cmp lc($b) } keys %{ $ref->{projectnumbers} };
449
450     map { $row->{$_}->{data} = $ref->{$_} } qw(id reference description notes gldate employee);
451
452     map { $row->{$_}->{data} = \@{ $rows{$_} }; } qw(transdate debit credit debit_accno credit_accno debit_tax_accno credit_tax_accno source);
453
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} } ];
456     }
457
458     map { $row->{$_}->{data} = \@{ $rows{$_} } if ($ref->{"${_}_accno"} ne "") } qw(debit_tax credit_tax);
459
460     $row->{reference}->{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'id=' . E($ref->{id}), 'callback');
461
462     my $row_set = [ $row ];
463
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');
468     }
469
470     $report->add_data($row_set);
471
472     $idx++;
473   }
474
475   # = 0 for balanced ledger
476   my $balanced_ledger = $totals{debit} + $totals{debit_tax} - $totals{credit} - $totals{credit_tax};
477
478   my $row = create_subtotal_row(\%totals, \@columns, \%column_alignment, [ qw(debit credit debit_tax credit_tax) ], 'listtotal');
479
480   my $sh = "";
481   if ($form->{balance} < 0) {
482     $sh = " S";
483     $ml = -1;
484   } elsif ($form->{balance} > 0) {
485     $sh = " H";
486     $ml = 1;
487   }
488   my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
489   $data .= $sh;
490
491   $row->{balance}->{data}        = $data;
492
493   if ( !$form->{report_generator_csv_options_for_import} ) {
494     $report->add_separator();
495     $report->add_data($row);
496   }
497
498   my $raw_bottom_info_text;
499
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')
504       . ': '
505       . $form->format_amount(\%myconfig, $balanced_ledger, 3)
506       . '</span></p> ';
507   }
508
509   $raw_bottom_info_text .= $form->parse_html_template('gl/generate_report_bottom');
510
511   $report->set_options('raw_bottom_info_text' => $raw_bottom_info_text);
512
513   $report->generate_with_headers();
514
515   $main::lxdebug->leave_sub();
516 }
517
518 sub update {
519   $main::lxdebug->enter_sub();
520
521   $main::auth->assert('general_ledger');
522
523   my $form     = $main::form;
524   my %myconfig = %main::myconfig;
525
526   $form->{oldtransdate} = $form->{transdate};
527
528   my @a           = ();
529   my $count       = 0;
530   my $debittax    = 0;
531   my $credittax   = 0;
532   my $debitcount  = 0;
533   my $creditcount = 0;
534   my ($debitcredit, $amount);
535
536   my @flds =
537     qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
538
539   for my $i (1 .. $form->{rowcount}) {
540
541     unless (($form->{"debit_$i"} eq "") && ($form->{"credit_$i"} eq "")) {
542       for (qw(debit credit tax)) {
543         $form->{"${_}_$i"} =
544           $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
545       }
546
547       push @a, {};
548       $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
549       if ($debitcredit) {
550         $debitcount++;
551       } else {
552         $creditcount++;
553       }
554
555       if (($debitcount >= 2) && ($creditcount == 2)) {
556         $form->{"credit_$i"} = 0;
557         $form->{"tax_$i"}    = 0;
558         $creditcount--;
559         $form->{creditlock} = 1;
560       }
561       if (($creditcount >= 2) && ($debitcount == 2)) {
562         $form->{"debit_$i"} = 0;
563         $form->{"tax_$i"}   = 0;
564         $debitcount--;
565         $form->{debitlock} = 1;
566       }
567       if (($creditcount == 1) && ($debitcount == 2)) {
568         $form->{creditlock} = 1;
569       }
570       if (($creditcount == 2) && ($debitcount == 1)) {
571         $form->{debitlock} = 1;
572       }
573       if ($debitcredit && $credittax) {
574         $form->{"taxchart_$i"} = "0--0.00";
575       }
576       if (!$debitcredit && $debittax) {
577         $form->{"taxchart_$i"} = "0--0.00";
578       }
579       $amount =
580         ($form->{"debit_$i"} == 0)
581         ? $form->{"credit_$i"}
582         : $form->{"debit_$i"};
583       my $j = $#a;
584       if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
585         $form->{"taxchart_$i"} = "0--0.00";
586         $form->{"tax_$i"}      = 0;
587       }
588       my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
589       if ($taxkey > 1) {
590         if ($debitcredit) {
591           $debittax = 1;
592         } else {
593           $credittax = 1;
594         }
595         if ($form->{taxincluded}) {
596           $form->{"tax_$i"} = $amount / ($rate + 1) * $rate;
597         } else {
598           $form->{"tax_$i"} = $amount * $rate;
599         }
600       } else {
601         $form->{"tax_$i"} = 0;
602       }
603
604       for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
605       $count++;
606     }
607   }
608
609   for my $i (1 .. $count) {
610     my $j = $i - 1;
611     for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
612   }
613
614   for my $i ($count + 1 .. $form->{rowcount}) {
615     for (@flds) { delete $form->{"${_}_$i"} }
616   }
617
618   $form->{rowcount} = $count + 1;
619
620   &display_form;
621   $main::lxdebug->leave_sub();
622
623 }
624
625 sub display_form {
626   my ($init) = @_;
627   $main::lxdebug->enter_sub();
628
629   $main::auth->assert('general_ledger');
630
631   my $form     = $main::form;
632   my %myconfig = %main::myconfig;
633
634   &form_header($init);
635
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"});
639   #
640   #     &form_row($i);
641   #   }
642   &display_rows($init);
643   &form_footer;
644   $main::lxdebug->leave_sub();
645
646 }
647
648 sub display_rows {
649   my ($init) = @_;
650   $main::lxdebug->enter_sub();
651
652   $main::auth->assert('general_ledger');
653
654   my $form     = $main::form;
655   my %myconfig = %main::myconfig;
656   my $cgi      = $::request->{cgi};
657
658   $form->{debit_1}     = 0 if !$form->{"debit_1"};
659   $form->{totaldebit}  = 0;
660   $form->{totalcredit} = 0;
661
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"};
667   }
668
669   my %chart_labels = ();
670   my @chart_values = ();
671   my %charts = ();
672   my $taxchart_init;
673   foreach my $item (@{ $form->{ALL_CHARTS} }) {
674     if ($item->{charttype} eq 'H'){ #falls Ã¼berschrift
675       next;                         #überspringen (Bug 1150)
676     }
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;
682   }
683
684   my %taxchart_labels = ();
685   my @taxchart_values = ();
686   my %taxcharts = ();
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;
693   }
694
695   my ($source, $memo, $source_hidden, $memo_hidden);
696   for my $i (1 .. $form->{rowcount}) {
697     if ($form->{show_details}) {
698       $source = qq|
699       <td><input name="source_$i" value="$form->{"source_$i"}" size="16"></td>|;
700       $memo = qq|
701       <td><input name="memo_$i" value="$form->{"memo_$i"}" size="16"></td>|;
702     } else {
703       $source_hidden = qq|
704       <input type="hidden" name="source_$i" value="$form->{"source_$i"}" size="16">|;
705       $memo_hidden = qq|
706       <input type="hidden" name="memo_$i" value="$form->{"memo_$i"}" size="16">|;
707     }
708
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}";
713
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"});
717
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}";
723     }
724
725     $selected_accno      = '' if ($init);
726     $selected_taxchart ||= $taxchart_init;
727
728     my $accno = qq|<td>| .
729       NTI($cgi->popup_menu('-name' => "accno_$i",
730                            '-id' => "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)
738       . qq|</td>|;
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))
746       . qq|</td>|;
747
748     my ($fx_transaction, $checked);
749     if ($init) {
750       if ($form->{transfer}) {
751         $fx_transaction = qq|
752         <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
753     |;
754       }
755
756     } else {
757       if ($form->{"debit_$i"} != 0) {
758         $form->{totaldebit} += $form->{"debit_$i"};
759         if (!$form->{taxincluded}) {
760           $form->{totaldebit} += $form->{"tax_$i"};
761         }
762       } else {
763         $form->{totalcredit} += $form->{"credit_$i"};
764         if (!$form->{taxincluded}) {
765           $form->{totalcredit} += $form->{"tax_$i"};
766         }
767       }
768
769       for (qw(debit credit tax)) {
770         $form->{"${_}_$i"} =
771           ($form->{"${_}_$i"})
772           ? $form->format_amount(\%myconfig, $form->{"${_}_$i"}, 2)
773           : "";
774       }
775
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>
782     |;
783         }
784         $form->hide_form("accno_$i");
785
786       } else {
787         if ($form->{transfer}) {
788           $fx_transaction = qq|
789       <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
790     |;
791         }
792       }
793     }
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";
801       }
802     }
803
804     my $projectnumber =
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"}">|;
811
812     my $copy2credit = $i == 1 ? 'onkeyup="copy_debit_to_credit()"' : '';
813
814     print qq|<tr valign=top>
815     $accno
816     <td id="chart_balance_$i" align="right">&nbsp;</td>
817     $fx_transaction
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>
821     $tax_ddbox|;
822
823     if ($form->{show_details}) {
824       print qq|
825     $source
826     $memo
827     <td>$projectnumber</td>
828 |;
829     } else {
830     print qq|
831     $source_hidden
832     $memo_hidden
833     $projectnumber_hidden
834     |;
835     }
836     print qq|
837   </tr>
838 |;
839   }
840
841   $form->hide_form(qw(rowcount selectaccno));
842
843   $main::lxdebug->leave_sub();
844
845 }
846
847 sub form_header {
848   $::lxdebug->enter_sub;
849   $::auth->assert('general_ledger');
850
851   my ($init) = @_;
852
853   my @old_project_ids = grep { $_ } map{ $::form->{"project_id_$_"} } 1..$::form->{rowcount};
854
855   $::form->get_lists("projects"  => { "key"       => "ALL_PROJECTS",
856                                     "all"       => 0,
857                                     "old_id"    => \@old_project_ids },
858                    "charts"    => { "key"       => "ALL_CHARTS",
859                                     "transdate" => $::form->{transdate} },
860                    "taxcharts" => "ALL_TAXCHARTS");
861
862   GL->get_chart_balances('charts' => $::form->{ALL_CHARTS});
863
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')
868
869   map { $::form->{$_} =~ s/\"/&quot;/g }
870     qw(chart taxchart);
871
872   $::form->{selectdepartment} =~ s/ selected//;
873   $::form->{selectdepartment} =~
874     s/option>\Q$::form->{department}\E/option selected>$::form->{department}/;
875
876   if ($init) {
877     $::form->{fokus} = "gl.reference";
878     $::form->{taxincluded} = "1";
879   } else {
880     $::form->{fokus} = qq|gl.accno_$::form->{rowcount}|;
881   }
882
883   $::form->{previous_id}     ||= "--";
884   $::form->{previous_gldate} ||= "--";
885
886   $::form->header;
887   print $::form->parse_html_template('gl/form_header', {
888     hide_title => $title,
889   });
890
891   $::lxdebug->leave_sub;
892
893 }
894
895 sub form_footer {
896   $::lxdebug->enter_sub;
897   $::auth->assert('general_ledger');
898
899   my ($follow_ups, $follow_ups_due);
900
901   if ($::form->{id}) {
902     $follow_ups     = FU->follow_ups('trans_id' => $::form->{id});
903     $follow_ups_due = sum map { $_->{due} * 1 } @{ $follow_ups || [] };
904   }
905
906   my $radieren = $::form->current_date(\%::myconfig) eq $::form->{gldate};
907
908   print $::form->parse_html_template('gl/form_footer', {
909     radieren       => $radieren,
910     follow_ups     => $follow_ups,
911     follow_ups_due => $follow_ups_due,
912   });
913
914   $::lxdebug->leave_sub;
915 }
916
917 sub delete {
918   $main::lxdebug->enter_sub();
919
920   my $form     = $main::form;
921   my $locale   = $main::locale;
922
923   $form->header;
924
925   print qq|
926 <form method=post action=gl.pl>
927 |;
928
929   map { $form->{$_} =~ s/\"/&quot;/g } qw(reference description);
930
931   delete $form->{header};
932
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|;
936   }
937
938   print qq|
939 <h2 class=confirm>| . $locale->text('Confirm!') . qq|</h2>
940
941 <h4>|
942     . $locale->text('Are you sure you want to delete Transaction')
943     . qq| $form->{reference}</h4>
944
945 <input name=action class=submit type=submit value="|
946     . $locale->text('Yes') . qq|">
947 </form>
948 |;
949   $main::lxdebug->leave_sub();
950
951 }
952
953 sub yes {
954   $main::lxdebug->enter_sub();
955
956   my $form     = $main::form;
957   my %myconfig = %main::myconfig;
958   my $locale   = $main::locale;
959
960   if (GL->delete_transaction(\%myconfig, \%$form)){
961     # saving the history
962       if(!exists $form->{addition} && $form->{id} ne "") {
963         $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
964         $form->{addition} = "DELETED";
965         $form->save_history;
966       }
967     # /saving the history
968     $form->redirect($locale->text('Transaction deleted!'))
969   }
970   $form->error($locale->text('Cannot delete transaction!'));
971   $main::lxdebug->leave_sub();
972
973 }
974
975 sub post_transaction {
976   $main::lxdebug->enter_sub();
977
978   my $form     = $main::form;
979   my %myconfig = %main::myconfig;
980   my $locale   = $main::locale;
981
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!'));
986
987   my $transdate = $form->datetonum($form->{transdate}, \%myconfig);
988   my $closedto  = $form->datetonum($form->{closedto},  \%myconfig);
989
990   my @a           = ();
991   my $count       = 0;
992   my $debittax    = 0;
993   my $credittax   = 0;
994   my $debitcount  = 0;
995   my $creditcount = 0;
996   my $debitcredit;
997   my %split_safety = ();
998
999   my @flds = qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
1000
1001   for my $i (1 .. $form->{rowcount}) {
1002     next if $form->{"debit_$i"} eq "" && $form->{"credit_$i"} eq "";
1003
1004     for (qw(debit credit tax)) {
1005       $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
1006     }
1007
1008     push @a, {};
1009     $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
1010
1011     $split_safety{   $form->{"debit_$i"}  <=> 0 }++;
1012     $split_safety{ - $form->{"credit_$i"} <=> 0 }++;
1013
1014     if ($debitcredit) {
1015       $debitcount++;
1016     } else {
1017       $creditcount++;
1018     }
1019
1020     if (($debitcount >= 2) && ($creditcount == 2)) {
1021       $form->{"credit_$i"} = 0;
1022       $form->{"tax_$i"}    = 0;
1023       $creditcount--;
1024       $form->{creditlock} = 1;
1025     }
1026     if (($creditcount >= 2) && ($debitcount == 2)) {
1027       $form->{"debit_$i"} = 0;
1028       $form->{"tax_$i"}   = 0;
1029       $debitcount--;
1030       $form->{debitlock} = 1;
1031     }
1032     if (($creditcount == 1) && ($debitcount == 2)) {
1033       $form->{creditlock} = 1;
1034     }
1035     if (($creditcount == 2) && ($debitcount == 1)) {
1036       $form->{debitlock} = 1;
1037     }
1038     if ($debitcredit && $credittax) {
1039       $form->{"taxchart_$i"} = "0--0.00";
1040     }
1041     if (!$debitcredit && $debittax) {
1042       $form->{"taxchart_$i"} = "0--0.00";
1043     }
1044     my $amount = ($form->{"debit_$i"} == 0)
1045             ? $form->{"credit_$i"}
1046             : $form->{"debit_$i"};
1047     my $j = $#a;
1048     if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
1049       $form->{"taxchart_$i"} = "0--0.00";
1050       $form->{"tax_$i"}      = 0;
1051     }
1052     my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
1053     if ($taxkey > 1) {
1054       if ($debitcredit) {
1055         $debittax = 1;
1056       } else {
1057         $credittax = 1;
1058       }
1059       if ($form->{taxincluded}) {
1060         $form->{"tax_$i"} = $amount / ($rate + 1) * $rate;
1061         if ($debitcredit) {
1062           $form->{"debit_$i"} = $form->{"debit_$i"} - $form->{"tax_$i"};
1063         } else {
1064           $form->{"credit_$i"} = $form->{"credit_$i"} - $form->{"tax_$i"};
1065         }
1066       } else {
1067         $form->{"tax_$i"} = $amount * $rate;
1068       }
1069     } else {
1070       $form->{"tax_$i"} = 0;
1071     }
1072
1073     for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
1074     $count++;
1075   }
1076
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."));
1079   }
1080
1081   for my $i (1 .. $count) {
1082     my $j = $i - 1;
1083     for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
1084   }
1085
1086   for my $i ($count + 1 .. $form->{rowcount}) {
1087     for (@flds) { delete $form->{"${_}_$i"} }
1088   }
1089
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"};
1095     if ($dr && $cr) {
1096       $form->error($locale->text('Cannot post transaction with a debit and credit entry for the same account!'));
1097     }
1098     $debit    += $dr + $tax if $dr;
1099     $credit   += $cr + $tax if $cr;
1100     $taxtotal += $tax if $form->{taxincluded}
1101   }
1102
1103   $form->{taxincluded} = 0 if !$taxtotal;
1104
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!'));
1110   }
1111
1112   if ($form->round_amount($debit, 2) + $form->round_amount($credit, 2) == 0) {
1113     $form->error($locale->text('Empty transaction!'));
1114   }
1115
1116   if ((my $errno = GL->post_transaction(\%myconfig, \%$form)) <= -1) {
1117     $errno *= -1;
1118     my @err;
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!');
1122
1123     $form->error($err[$errno]);
1124   }
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;
1132   }
1133   # /saving the history
1134
1135   $main::lxdebug->leave_sub();
1136 }
1137
1138 sub post {
1139   $main::lxdebug->enter_sub();
1140
1141   $main::auth->assert('general_ledger');
1142
1143   my $form     = $main::form;
1144   my $locale   = $main::locale;
1145
1146   if ($::myconfig{mandatory_departments} && !$form->{department}) {
1147     $form->{saved_message} = $::locale->text('You have to specify a department.');
1148     update();
1149     exit;
1150   }
1151
1152   $form->{title}  = $locale->text("$form->{title} General Ledger Transaction");
1153   $form->{storno} = 0;
1154
1155   post_transaction();
1156
1157   remove_draft() if $form->{remove_draft};
1158
1159   $form->{callback} = build_std_url("action=add&DONT_LOAD_DRAFT=1", "show_details");
1160   $form->redirect($form->{callback});
1161
1162   $main::lxdebug->leave_sub();
1163 }
1164
1165 sub post_as_new {
1166   $main::lxdebug->enter_sub();
1167
1168   $main::auth->assert('general_ledger');
1169
1170   my $form     = $main::form;
1171
1172   $form->{id} = 0;
1173   &add;
1174   $main::lxdebug->leave_sub();
1175
1176 }
1177
1178 sub storno {
1179   $main::lxdebug->enter_sub();
1180
1181   $main::auth->assert('general_ledger');
1182
1183   my $form     = $main::form;
1184   my %myconfig = %main::myconfig;
1185   my $locale   = $main::locale;
1186
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!"));
1191   }
1192
1193   GL->storno($form, \%myconfig, $form->{id});
1194
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;
1200   }
1201   # /saving the history
1202
1203   $form->redirect(sprintf $locale->text("Transaction %d cancelled."), $form->{storno_id});
1204
1205   $main::lxdebug->leave_sub();
1206 }
1207
1208 sub continue {
1209   call_sub($main::form->{nextsub});
1210 }
1211
1212 1;