]> wagnertech.de Git - kivitendo-erp.git/blob - bin/mozilla/gl.pl
IC: dispatcher wird nicht mehr gebraucht
[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., 51 Franklin Street, Fifth Floor, Boston,
28 # MA 02110-1335, USA.
29 #======================================================================
30 #
31 # Genereal Ledger
32 #
33 #======================================================================
34
35 use utf8;
36 use strict;
37
38 use POSIX qw(strftime);
39 use List::Util qw(first sum);
40
41 use SL::DB::RecordTemplate;
42 use SL::DB::Tax;
43 use SL::FU;
44 use SL::GL;
45 use SL::Helper::Flash qw(flash);
46 use SL::IS;
47 use SL::ReportGenerator;
48 use SL::DBUtils qw(selectrow_query selectall_hashref_query);
49 use SL::Webdav;
50 use SL::Locale::String qw(t8);
51
52 require "bin/mozilla/common.pl";
53 require "bin/mozilla/reportgenerator.pl";
54
55 # this is for our long dates
56 # $locale->text('January')
57 # $locale->text('February')
58 # $locale->text('March')
59 # $locale->text('April')
60 # $locale->text('May ')
61 # $locale->text('June')
62 # $locale->text('July')
63 # $locale->text('August')
64 # $locale->text('September')
65 # $locale->text('October')
66 # $locale->text('November')
67 # $locale->text('December')
68
69 # this is for our short month
70 # $locale->text('Jan')
71 # $locale->text('Feb')
72 # $locale->text('Mar')
73 # $locale->text('Apr')
74 # $locale->text('May')
75 # $locale->text('Jun')
76 # $locale->text('Jul')
77 # $locale->text('Aug')
78 # $locale->text('Sep')
79 # $locale->text('Oct')
80 # $locale->text('Nov')
81 # $locale->text('Dec')
82
83 sub load_record_template {
84   $::auth->assert('gl_transactions');
85
86   # Load existing template and verify that its one for this module.
87   my $template = SL::DB::RecordTemplate
88     ->new(id => $::form->{id})
89     ->load(
90       with_object => [ qw(customer payment currency record_items record_items.chart) ],
91     );
92
93   die "invalid template type" unless $template->template_type eq 'gl_transaction';
94
95   $template->substitute_variables;
96
97   # Clean the current $::form before rebuilding it from the template.
98   delete @{ $::form }{ grep { !m{^(?:script|login)$}i } keys %{ $::form } };
99
100   my $dummy_form = {};
101   GL->transaction(\%::myconfig, $dummy_form);
102
103   # Fill $::form from the template.
104   my $today                   = DateTime->today_local;
105   $::form->{title}            = "Add";
106   $::form->{transdate}        = $today->to_kivitendo;
107   $::form->{duedate}          = $today->to_kivitendo;
108   $::form->{rowcount}         = @{ $template->items } + 1;
109   $::form->{paidaccounts}     = 1;
110   $::form->{$_}               = $template->$_     for qw(department_id taxincluded ob_transaction cb_transaction reference description);
111   $::form->{$_}               = $dummy_form->{$_} for qw(closedto revtrans previous_id previous_gldate);
112
113   my $row = 0;
114   foreach my $item (@{ $template->items }) {
115     $row++;
116
117     my $active_taxkey = $item->chart->get_active_taxkey;
118     my $taxes         = SL::DB::Manager::Tax->get_all(
119       where   => [ chart_categories => { like => '%' . $item->chart->category . '%' }],
120       sort_by => 'taxkey, rate',
121     );
122
123     my $tax   = first { $item->tax_id          == $_->id } @{ $taxes };
124     $tax    //= first { $active_taxkey->tax_id == $_->id } @{ $taxes };
125     $tax    //= $taxes->[0];
126
127     if (!$tax) {
128       $row--;
129       next;
130     }
131
132     $::form->{"accno_id_${row}"}          = $item->chart_id;
133     $::form->{"previous_accno_id_${row}"} = $item->chart_id;
134     $::form->{"debit_${row}"}             = $::form->format_amount(\%::myconfig, $item->amount1, 2) if $item->amount1 * 1;
135     $::form->{"credit_${row}"}            = $::form->format_amount(\%::myconfig, $item->amount2, 2) if $item->amount2 * 1;
136     $::form->{"taxchart_${row}"}          = $item->tax_id . '--' . $tax->rate;
137     $::form->{"${_}_${row}"}              = $item->$_ for qw(source memo project_id);
138   }
139
140   flash('info', $::locale->text("The record template '#1' has been loaded.", $template->template_name));
141
142   update();
143 }
144
145 sub save_record_template {
146   $::auth->assert('gl_transactions');
147
148   my $template = $::form->{record_template_id} ? SL::DB::RecordTemplate->new(id => $::form->{record_template_id})->load : SL::DB::RecordTemplate->new;
149   my $js       = SL::ClientJS->new(controller => SL::Controller::Base->new);
150   my $new_name = $template->template_name_to_use($::form->{record_template_new_template_name});
151
152   $js->dialog->close('#record_template_dialog');
153
154   my @items = grep {
155     $_->{chart_id} && (($_->{tax_id} // '') ne '') && (($_->{amount1} != 0) || ($_->{amount2} != 0))
156   } map {
157     +{ chart_id   => $::form->{"accno_id_${_}"},
158        amount1    => $::form->parse_amount(\%::myconfig, $::form->{"debit_${_}"}),
159        amount2    => $::form->parse_amount(\%::myconfig, $::form->{"credit_${_}"}),
160        tax_id     => (split m{--}, $::form->{"taxchart_${_}"})[0],
161        project_id => $::form->{"project_id_${_}"} || undef,
162        source     => $::form->{"source_${_}"},
163        memo       => $::form->{"memo_${_}"},
164      }
165   } (1..($::form->{rowcount} || 1));
166
167   $template->assign_attributes(
168     template_type  => 'gl_transaction',
169     template_name  => $new_name,
170
171     currency_id    => $::instance_conf->get_currency_id,
172     department_id  => $::form->{department_id}    || undef,
173     project_id     => $::form->{globalproject_id} || undef,
174     taxincluded    => $::form->{taxincluded}     ? 1 : 0,
175     ob_transaction => $::form->{ob_transaction}  ? 1 : 0,
176     cb_transaction => $::form->{cb_transaction}  ? 1 : 0,
177     reference      => $::form->{reference},
178     description    => $::form->{description},
179
180     items          => \@items,
181   );
182
183   eval {
184     $template->save;
185     1;
186   } or do {
187     return $js
188       ->flash('error', $::locale->text("Saving the record template '#1' failed.", $new_name))
189       ->render;
190   };
191
192   return $js
193     ->flash('info', $::locale->text("The record template '#1' has been saved.", $new_name))
194     ->render;
195 }
196
197 sub add {
198   $main::lxdebug->enter_sub();
199
200   $main::auth->assert('gl_transactions');
201
202   my $form     = $main::form;
203   my %myconfig = %main::myconfig;
204
205   $form->{title} = "Add";
206
207   $form->{callback} = "gl.pl?action=add" unless $form->{callback};
208
209   # we use this only to set a default date
210   # yep. aber er holt hier auch schon ALL_CHARTS. Aufwand / Nutzen? jb
211   GL->transaction(\%myconfig, \%$form);
212
213   $form->{rowcount}  = 2;
214
215   $form->{debit}  = 0;
216   $form->{credit} = 0;
217   $form->{tax}    = 0;
218
219   $::form->{ALL_DEPARTMENTS} = SL::DB::Manager::Department->get_all;
220
221   $form->{show_details} = $myconfig{show_form_details} unless defined $form->{show_details};
222
223   &display_form(1);
224   $main::lxdebug->leave_sub();
225
226 }
227
228 sub prepare_transaction {
229   $main::lxdebug->enter_sub();
230
231   $main::auth->assert('gl_transactions');
232
233   my $form     = $main::form;
234   my %myconfig = %main::myconfig;
235
236   GL->transaction(\%myconfig, \%$form);
237
238   $form->{amount} = $form->format_amount(\%myconfig, $form->{amount}, 2);
239
240   $::form->{ALL_DEPARTMENTS} = SL::DB::Manager::Department->get_all;
241
242   my $i        = 1;
243   my $tax      = 0;
244   my $taxaccno = "";
245   foreach my $ref (@{ $form->{GL} }) {
246     my $j = $i - 1;
247     if ($tax && ($ref->{accno} eq $taxaccno)) {
248       $form->{"tax_$j"}      = abs($ref->{amount});
249       $form->{"taxchart_$j"} = $ref->{id} . "--" . $ref->{taxrate};
250       if ($form->{taxincluded}) {
251         if ($ref->{amount} < 0) {
252           $form->{"debit_$j"} += $form->{"tax_$j"};
253         } else {
254           $form->{"credit_$j"} += $form->{"tax_$j"};
255         }
256       }
257       $form->{"project_id_$j"} = $ref->{project_id};
258
259     } else {
260       $form->{"accno_id_$i"} = $ref->{chart_id};
261       for (qw(fx_transaction source memo)) { $form->{"${_}_$i"} = $ref->{$_} }
262       if ($ref->{amount} < 0) {
263         $form->{totaldebit} -= $ref->{amount};
264         $form->{"debit_$i"} = $ref->{amount} * -1;
265       } else {
266         $form->{totalcredit} += $ref->{amount};
267         $form->{"credit_$i"} = $ref->{amount};
268       }
269       $form->{"taxchart_$i"} = $ref->{id}."--0.00000";
270       $form->{"project_id_$i"} = $ref->{project_id};
271       $i++;
272     }
273     if ($ref->{taxaccno} && !$tax) {
274       $taxaccno = $ref->{taxaccno};
275       $tax      = 1;
276     } else {
277       $taxaccno = "";
278       $tax      = 0;
279     }
280   }
281
282   $form->{rowcount} = $i;
283   $form->{locked}   =
284     ($form->datetonum($form->{transdate}, \%myconfig) <=
285      $form->datetonum($form->{closedto}, \%myconfig));
286
287   $main::lxdebug->leave_sub();
288 }
289
290 sub edit {
291   $main::lxdebug->enter_sub();
292
293   $main::auth->assert('gl_transactions');
294
295   my $form     = $main::form;
296   my %myconfig = %main::myconfig;
297
298   prepare_transaction();
299
300   $form->{title} = "Edit";
301
302   $form->{show_details} = $myconfig{show_form_details} unless defined $form->{show_details};
303
304   if ($form->{reference} && $::instance_conf->get_webdav) {
305     my $webdav = SL::Webdav->new(
306       type     => 'general_ledger',
307       number   => $form->{reference},
308     );
309     my $webdav_path = $webdav->webdav_path;
310     my @all_objects = $webdav->get_all_objects;
311     @{ $form->{WEBDAV} } = map { { name => $_->filename,
312                                    type => t8('File'),
313                                    link => File::Spec->catfile($_->full_filedescriptor),
314                                } } @all_objects;
315   }
316   form_header();
317   display_rows();
318   form_footer();
319
320   $main::lxdebug->leave_sub();
321 }
322
323
324 sub search {
325   $::lxdebug->enter_sub;
326   $::auth->assert('general_ledger | gl_transactions');
327
328   $::form->get_lists(
329     projects  => { key => "ALL_PROJECTS", all => 1 },
330   );
331   $::form->{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all_sorted(query => [ deleted => 0 ]);
332   $::form->{ALL_DEPARTMENTS} = SL::DB::Manager::Department->get_all;
333
334   $::form->header;
335   print $::form->parse_html_template('gl/search', {
336     employee_label => sub { "$_[0]{id}--$_[0]{name}" },
337   });
338
339   $::lxdebug->leave_sub;
340 }
341
342 sub create_subtotal_row {
343   $main::lxdebug->enter_sub();
344
345   my ($totals, $columns, $column_alignment, $subtotal_columns, $class) = @_;
346
347   my $form     = $main::form;
348   my %myconfig = %main::myconfig;
349
350   my $row = { map { $_ => { 'data' => '', 'class' => $class, 'align' => $column_alignment->{$_}, } } @{ $columns } };
351
352   map { $row->{$_}->{data} = $form->format_amount(\%myconfig, $totals->{$_}, 2) } @{ $subtotal_columns };
353
354   map { $totals->{$_} = 0 } @{ $subtotal_columns };
355
356   $main::lxdebug->leave_sub();
357
358   return $row;
359 }
360
361 sub generate_report {
362   $main::lxdebug->enter_sub();
363
364   $main::auth->assert('general_ledger | gl_transactions');
365
366   my $form     = $main::form;
367   my %myconfig = %main::myconfig;
368   my $locale   = $main::locale;
369
370   # 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
371
372   # <form method=post action=gl.pl>
373   # <input type=hidden name=sort value=datesort>    # form->{sort} setzen
374   # <input type=hidden name=nextsub value=generate_report>
375
376   # anhand von neuer Variable datesort wird jetzt $form->{sort} auf transdate oder gldate gesetzt
377   # damit ist die Hidden Variable "sort" wahrscheinlich sogar Ã¼berflüssig
378
379   # Ã¤ndert man die Sortierreihenfolge per Klick auf eine der Ãœberschriften wird die Variable "sort" per GET Ã¼bergeben, z.B. id,transdate, gldate, ...
380   # 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
381
382   if ( $form->{sort} eq 'datesort' ) {   # sollte bei einem Post (Aufruf aus Suchmaske) immer wahr sein
383       # je nachdem ob in Suchmaske "transdate" oder "gldate" ausgesucht wurde erstes Suchergebnis entsprechend sortieren
384       $form->{sort} = $form->{datesort};
385   };
386
387   # was passiert hier?
388   report_generator_set_default_sort("$form->{datesort}", 1);
389 #  report_generator_set_default_sort('transdate', 1);
390
391   GL->all_transactions(\%myconfig, \%$form);
392
393   my %acctype = ('A' => $locale->text('Asset'),
394                  'C' => $locale->text('Contra'),
395                  'L' => $locale->text('Liability'),
396                  'Q' => $locale->text('Equity'),
397                  'I' => $locale->text('Revenue'),
398                  'E' => $locale->text('Expense'),);
399
400   $form->{title} = $locale->text('Journal');
401   if ($form->{category} ne 'X') {
402     $form->{title} .= " : " . $locale->text($acctype{ $form->{category} });
403   }
404
405   $form->{landscape} = 1;
406
407   my $ml = ($form->{ml} =~ /(A|E|Q)/) ? -1 : 1;
408
409   my @columns = qw(
410     gldate         transdate        id             reference      description
411     notes          source           debit          debit_accno
412     credit         credit_accno     debit_tax      debit_tax_accno
413     credit_tax     credit_tax_accno projectnumbers balance employee
414   );
415
416   # add employee here, so that variable is still known and passed in url when choosing a different sort order in resulting table
417   my @hidden_variables = qw(accno source reference description notes project_id datefrom dateto employee_id datesort category l_subtotal);
418   push @hidden_variables, map { "l_${_}" } @columns;
419
420   my $employee = $form->{employee_id} ? SL::DB::Employee->new(id => $form->{employee_id})->load->name : '';
421
422   my (@options, @date_options);
423   push @options,      $locale->text('Account')     . " : $form->{accno} $form->{account_description}" if ($form->{accno});
424   push @options,      $locale->text('Source')      . " : $form->{source}"                             if ($form->{source});
425   push @options,      $locale->text('Reference')   . " : $form->{reference}"                          if ($form->{reference});
426   push @options,      $locale->text('Description') . " : $form->{description}"                        if ($form->{description});
427   push @options,      $locale->text('Notes')       . " : $form->{notes}"                              if ($form->{notes});
428   push @options,      $locale->text('Employee')    . " : $employee"                                   if $employee;
429   my $datesorttext = $form->{datesort} eq 'transdate' ? $locale->text('Invoice Date') :  $locale->text('Booking Date');
430   push @date_options,      "$datesorttext"                              if ($form->{datesort} and ($form->{datefrom} or $form->{dateto}));
431   push @date_options, $locale->text('From'), $locale->date(\%myconfig, $form->{datefrom}, 1)          if ($form->{datefrom});
432   push @date_options, $locale->text('Bis'),  $locale->date(\%myconfig, $form->{dateto},   1)          if ($form->{dateto});
433   push @options,      join(' ', @date_options)                                                        if (scalar @date_options);
434
435   if ($form->{department_id}) {
436     my $department = SL::DB::Manager::Department->find_by( id => $form->{department_id} );
437     push @options, $locale->text('Department') . " : " . $department->description;
438   }
439
440   my $callback = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
441
442   $form->{l_credit_accno}     = 'Y';
443   $form->{l_debit_accno}      = 'Y';
444   $form->{l_credit_tax}       = 'Y';
445   $form->{l_debit_tax}        = 'Y';
446 #  $form->{l_gldate}           = 'Y';  # Spalte mit gldate immer anzeigen
447   $form->{l_credit_tax_accno} = 'Y';
448   $form->{l_datesort} = 'Y';
449   $form->{l_debit_tax_accno}  = 'Y';
450   $form->{l_balance}          = $form->{accno} ? 'Y' : '';
451
452   my %column_defs = (
453     'id'               => { 'text' => $locale->text('ID'), },
454     'transdate'        => { 'text' => $locale->text('Invoice Date'), },
455     'gldate'           => { 'text' => $locale->text('Booking Date'), },
456     'reference'        => { 'text' => $locale->text('Reference'), },
457     'source'           => { 'text' => $locale->text('Source'), },
458     'description'      => { 'text' => $locale->text('Description'), },
459     'notes'            => { 'text' => $locale->text('Notes'), },
460     'debit'            => { 'text' => $locale->text('Debit'), },
461     'debit_accno'      => { 'text' => $locale->text('Debit Account'), },
462     'credit'           => { 'text' => $locale->text('Credit'), },
463     'credit_accno'     => { 'text' => $locale->text('Credit Account'), },
464     'debit_tax'        => { 'text' => $locale->text('Debit Tax'), },
465     'debit_tax_accno'  => { 'text' => $locale->text('Debit Tax Account'), },
466     'credit_tax'       => { 'text' => $locale->text('Credit Tax'), },
467     'credit_tax_accno' => { 'text' => $locale->text('Credit Tax Account'), },
468     'balance'          => { 'text' => $locale->text('Balance'), },
469     'projectnumbers'   => { 'text' => $locale->text('Project Numbers'), },
470     'employee'         => { 'text' => $locale->text('Employee'), },
471   );
472
473   foreach my $name (qw(id transdate gldate reference description debit_accno credit_accno debit_tax_accno credit_tax_accno)) {
474     my $sortname                = $name =~ m/accno/ ? 'accno' : $name;
475     my $sortdir                 = $sortname eq $form->{sort} ? 1 - $form->{sortdir} : $form->{sortdir};
476     $column_defs{$name}->{link} = $callback . "&sort=$sortname&sortdir=$sortdir";
477   }
478
479   map { $column_defs{$_}->{visible} = $form->{"l_${_}"} ? 1 : 0 } @columns;
480   map { $column_defs{$_}->{visible} = 0 } qw(debit_accno credit_accno debit_tax_accno credit_tax_accno) if $form->{accno};
481
482   my %column_alignment;
483   map { $column_alignment{$_}     = 'right'  } qw(balance id debit credit debit_tax credit_tax balance);
484   map { $column_alignment{$_}     = 'center' } qw(transdate gldate reference debit_accno credit_accno debit_tax_accno credit_tax_accno);
485   map { $column_alignment{$_}     = 'left' } qw(description source notes);
486   map { $column_defs{$_}->{align} = $column_alignment{$_} } keys %column_alignment;
487
488   my $report = SL::ReportGenerator->new(\%myconfig, $form);
489
490   $report->set_columns(%column_defs);
491   $report->set_column_order(@columns);
492
493   $report->set_export_options('generate_report', @hidden_variables, qw(sort sortdir));
494
495   $report->set_sort_indicator($form->{sort} eq 'accno' ? 'debit_accno' : $form->{sort}, $form->{sortdir});
496
497   $report->set_options('top_info_text'        => join("\n", @options),
498                        'output_format'        => 'HTML',
499                        'title'                => $form->{title},
500                        'attachment_basename'  => $locale->text('general_ledger_list') . strftime('_%Y%m%d', localtime time),
501     );
502   $report->set_options_from_form();
503   $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
504
505   # add sort to callback
506   $form->{callback} = "$callback&sort=" . E($form->{sort}) . "&sortdir=" . E($form->{sortdir});
507
508
509   my @totals_columns = qw(debit credit debit_tax credit_tax);
510   my %subtotals      = map { $_ => 0 } @totals_columns;
511   my %totals         = map { $_ => 0 } @totals_columns;
512   my $idx            = 0;
513
514   foreach my $ref (@{ $form->{GL} }) {
515
516     my %rows;
517
518     foreach my $key (qw(debit credit debit_tax credit_tax)) {
519       $rows{$key} = [];
520       foreach my $idx (sort keys(%{ $ref->{$key} })) {
521         my $value         = $ref->{$key}->{$idx};
522         $subtotals{$key} += $value;
523         $totals{$key}    += $value;
524         if ($key =~ /debit.*/) {
525           $ml = -1;
526         } else {
527           $ml = 1;
528         }
529         $form->{balance}  = $form->{balance} + $value * $ml;
530         push @{ $rows{$key} }, $form->format_amount(\%myconfig, $value, 2);
531       }
532     }
533
534     foreach my $key (qw(debit_accno credit_accno debit_tax_accno credit_tax_accno ac_transdate source)) {
535       my $col = $key eq 'ac_transdate' ? 'transdate' : $key;
536       $rows{$col} = [ map { $ref->{$key}->{$_} } sort keys(%{ $ref->{$key} }) ];
537     }
538
539     my $row = { };
540     map { $row->{$_} = { 'data' => '', 'align' => $column_alignment{$_} } } @columns;
541
542     my $sh = "";
543     if ($form->{balance} < 0) {
544       $sh = " S";
545       $ml = -1;
546     } elsif ($form->{balance} > 0) {
547       $sh = " H";
548       $ml = 1;
549     }
550     my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
551     $data .= $sh;
552
553     $row->{balance}->{data}        = $data;
554     $row->{projectnumbers}->{data} = join ", ", sort { lc($a) cmp lc($b) } keys %{ $ref->{projectnumbers} };
555
556     map { $row->{$_}->{data} = $ref->{$_} } qw(id reference description notes gldate employee);
557
558     map { $row->{$_}->{data} = \@{ $rows{$_} }; } qw(transdate debit credit debit_accno credit_accno debit_tax_accno credit_tax_accno source);
559
560     foreach my $col (qw(debit_accno credit_accno debit_tax_accno credit_tax_accno)) {
561       $row->{$col}->{link} = [ map { "${callback}&accno=" . E($_) } @{ $rows{$col} } ];
562     }
563
564     map { $row->{$_}->{data} = \@{ $rows{$_} } if ($ref->{"${_}_accno"} ne "") } qw(debit_tax credit_tax);
565
566     $row->{reference}->{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'id=' . E($ref->{id}), 'callback');
567
568     my $row_set = [ $row ];
569
570     if ( ($form->{l_subtotal} eq 'Y' && !$form->{report_generator_csv_options_for_import} )
571         && (($idx == (scalar @{ $form->{GL} } - 1))
572             || ($ref->{ $form->{sort} } ne $form->{GL}->[$idx + 1]->{ $form->{sort} }))) {
573       push @{ $row_set }, create_subtotal_row(\%subtotals, \@columns, \%column_alignment, [ qw(debit credit) ], 'listsubtotal');
574     }
575
576     $report->add_data($row_set);
577
578     $idx++;
579   }
580
581   # = 0 for balanced ledger
582   my $balanced_ledger = $totals{debit} + $totals{debit_tax} - $totals{credit} - $totals{credit_tax};
583
584   my $row = create_subtotal_row(\%totals, \@columns, \%column_alignment, [ qw(debit credit debit_tax credit_tax) ], 'listtotal');
585
586   my $sh = "";
587   if ($form->{balance} < 0) {
588     $sh = " S";
589     $ml = -1;
590   } elsif ($form->{balance} > 0) {
591     $sh = " H";
592     $ml = 1;
593   }
594   my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
595   $data .= $sh;
596
597   $row->{balance}->{data}        = $data;
598
599   if ( !$form->{report_generator_csv_options_for_import} ) {
600     $report->add_separator();
601     $report->add_data($row);
602   }
603
604   my $raw_bottom_info_text;
605
606   if (!$form->{accno} && (abs($balanced_ledger) >  0.001)) {
607     $raw_bottom_info_text .=
608         '<p><span class="unbalanced_ledger">'
609       . $locale->text('Unbalanced Ledger')
610       . ': '
611       . $form->format_amount(\%myconfig, $balanced_ledger, 3)
612       . '</span></p> ';
613   }
614
615   $raw_bottom_info_text .= $form->parse_html_template('gl/generate_report_bottom');
616
617   $report->set_options('raw_bottom_info_text' => $raw_bottom_info_text);
618
619   $report->generate_with_headers();
620
621   $main::lxdebug->leave_sub();
622 }
623
624 sub show_draft {
625   $::form->{transdate} = DateTime->today_local->to_kivitendo if !$::form->{transdate};
626   $::form->{gldate}    = $::form->{transdate} if !$::form->{gldate};
627   update();
628 }
629
630 sub update {
631   $main::lxdebug->enter_sub();
632
633   $main::auth->assert('gl_transactions');
634
635   my $form     = $main::form;
636   my %myconfig = %main::myconfig;
637
638   $form->{oldtransdate} = $form->{transdate};
639
640   my @a           = ();
641   my $count       = 0;
642   my $debittax    = 0;
643   my $credittax   = 0;
644   my $debitcount  = 0;
645   my $creditcount = 0;
646   my ($debitcredit, $amount);
647
648   my $dbh = SL::DB->client->dbh;
649   my ($notax_id) = selectrow_query($form, $dbh, "SELECT id FROM tax WHERE taxkey = 0 LIMIT 1", );
650   my $zerotaxes  = selectall_hashref_query($form, $dbh, "SELECT id FROM tax WHERE rate = 0", );
651
652   my @flds =
653     qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
654
655   for my $i (1 .. $form->{rowcount}) {
656
657     unless (($form->{"debit_$i"} eq "") && ($form->{"credit_$i"} eq "")) {
658       for (qw(debit credit tax)) {
659         $form->{"${_}_$i"} =
660           $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
661       }
662
663       push @a, {};
664       $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
665       if ($debitcredit) {
666         $debitcount++;
667       } else {
668         $creditcount++;
669       }
670
671       if (($debitcount >= 2) && ($creditcount == 2)) {
672         $form->{"credit_$i"} = 0;
673         $form->{"tax_$i"}    = 0;
674         $creditcount--;
675         $form->{creditlock} = 1;
676       }
677       if (($creditcount >= 2) && ($debitcount == 2)) {
678         $form->{"debit_$i"} = 0;
679         $form->{"tax_$i"}   = 0;
680         $debitcount--;
681         $form->{debitlock} = 1;
682       }
683       if (($creditcount == 1) && ($debitcount == 2)) {
684         $form->{creditlock} = 1;
685       }
686       if (($creditcount == 2) && ($debitcount == 1)) {
687         $form->{debitlock} = 1;
688       }
689       if ($debitcredit && $credittax) {
690         $form->{"taxchart_$i"} = "$notax_id--0.00";
691       }
692       if (!$debitcredit && $debittax) {
693         $form->{"taxchart_$i"} = "$notax_id--0.00";
694       }
695       $amount =
696         ($form->{"debit_$i"} == 0)
697         ? $form->{"credit_$i"}
698         : $form->{"debit_$i"};
699       my $j = $#a;
700       if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
701         $form->{"taxchart_$i"} = "$notax_id--0.00";
702         $form->{"tax_$i"}      = 0;
703       }
704       my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
705       my $iswithouttax = grep { $_->{id} == $taxkey } @{ $zerotaxes };
706       if (!$iswithouttax) {
707         if ($debitcredit) {
708           $debittax = 1;
709         } else {
710           $credittax = 1;
711         }
712       };
713       my ($tmpnetamount,$tmpdiff);
714       ($tmpnetamount,$form->{"tax_$i"},$tmpdiff) = $form->calculate_tax($amount,$rate,$form->{taxincluded} *= 1,2);
715
716       for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
717       $count++;
718     }
719   }
720
721   for my $i (1 .. $count) {
722     my $j = $i - 1;
723     for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
724   }
725
726   for my $i ($count + 1 .. $form->{rowcount}) {
727     for (@flds) { delete $form->{"${_}_$i"} }
728   }
729
730   $form->{rowcount} = $count + 1;
731
732   &display_form;
733   $main::lxdebug->leave_sub();
734
735 }
736
737 sub display_form {
738   my ($init) = @_;
739   $main::lxdebug->enter_sub();
740
741   $main::auth->assert('gl_transactions');
742
743   my $form     = $main::form;
744   my %myconfig = %main::myconfig;
745
746   &form_header($init);
747
748   #   for $i (1 .. $form->{rowcount}) {
749   #     $form->{totaldebit} += $form->parse_amount(\%myconfig, $form->{"debit_$i"});
750   #     $form->{totalcredit} += $form->parse_amount(\%myconfig, $form->{"credit_$i"});
751   #
752   #     &form_row($i);
753   #   }
754   &display_rows($init);
755   &form_footer;
756   $main::lxdebug->leave_sub();
757
758 }
759
760 sub display_rows {
761   my ($init) = @_;
762   $main::lxdebug->enter_sub();
763
764   $main::auth->assert('gl_transactions');
765
766   my $form     = $main::form;
767   my %myconfig = %main::myconfig;
768   my $cgi      = $::request->{cgi};
769
770   my %balances = GL->get_chart_balances(map { $_->{id} } @{ $form->{ALL_CHARTS} });
771
772   $form->{debit_1}     = 0 if !$form->{"debit_1"};
773   $form->{totaldebit}  = 0;
774   $form->{totalcredit} = 0;
775
776   my %project_labels = ();
777   my @project_values = ("");
778   foreach my $item (@{ $form->{"ALL_PROJECTS"} }) {
779     push(@project_values, $item->{"id"});
780     $project_labels{$item->{"id"}} = $item->{"projectnumber"};
781   }
782
783   my %charts_by_id  = map { ($_->{id} => $_) } @{ $::form->{ALL_CHARTS} };
784   my $default_chart = $::form->{ALL_CHARTS}[0];
785   my $transdate     = $::form->{transdate} ? DateTime->from_kivitendo($::form->{transdate}) : DateTime->today_local;
786
787   my ($source, $memo, $source_hidden, $memo_hidden);
788   for my $i (1 .. $form->{rowcount}) {
789     if ($form->{show_details}) {
790       $source = qq|
791       <td><input name="source_$i" value="$form->{"source_$i"}" size="16"></td>|;
792       $memo = qq|
793       <td><input name="memo_$i" value="$form->{"memo_$i"}" size="16"></td>|;
794     } else {
795       $source_hidden = qq|
796       <input type="hidden" name="source_$i" value="$form->{"source_$i"}" size="16">|;
797       $memo_hidden = qq|
798       <input type="hidden" name="memo_$i" value="$form->{"memo_$i"}" size="16">|;
799     }
800
801     my %taxchart_labels = ();
802     my @taxchart_values = ();
803
804     my $accno_id          = $::form->{"accno_id_$i"};
805     my $chart             = $charts_by_id{$accno_id} // $default_chart;
806     $accno_id             = $chart->{id};
807     my $chart_has_changed = $::form->{"previous_accno_id_$i"} && ($accno_id != $::form->{"previous_accno_id_$i"});
808     my ($first_taxchart, $default_taxchart, $taxchart_to_use);
809
810     foreach my $item ( GL->get_active_taxes_for_chart($accno_id, $transdate) ) {
811       my $key             = $item->id . "--" . $item->rate;
812       $first_taxchart   //= $item;
813       $default_taxchart   = $item if $item->{is_default};
814       $taxchart_to_use    = $item if $key eq $form->{"taxchart_$i"};
815
816       push(@taxchart_values, $key);
817       $taxchart_labels{$key} = $item->taxdescription . " " . $item->rate * 100 . ' %';
818     }
819
820     $taxchart_to_use      = $default_taxchart // $first_taxchart if $chart_has_changed || !$taxchart_to_use;
821     my $selected_taxchart = $taxchart_to_use->id . '--' . $taxchart_to_use->rate;
822
823     my $accno = qq|<td>| .
824       $::request->presenter->chart_picker("accno_id_$i", $accno_id, style => "width: 300px") .
825       $::request->presenter->hidden_tag("previous_accno_id_$i", $accno_id)
826       . qq|</td>|;
827     my $tax_ddbox = qq|<td>| .
828       NTI($cgi->popup_menu('-name' => "taxchart_$i",
829             '-id' => "taxchart_$i",
830             '-style' => 'width:200px',
831             '-values' => \@taxchart_values,
832             '-labels' => \%taxchart_labels,
833             '-default' => $selected_taxchart))
834       . qq|</td>|;
835
836     my ($fx_transaction, $checked);
837     if ($init) {
838       if ($form->{transfer}) {
839         $fx_transaction = qq|
840         <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
841     |;
842       }
843
844     } else {
845       if ($form->{"debit_$i"} != 0) {
846         $form->{totaldebit} += $form->{"debit_$i"};
847         if (!$form->{taxincluded}) {
848           $form->{totaldebit} += $form->{"tax_$i"};
849         }
850       } else {
851         $form->{totalcredit} += $form->{"credit_$i"};
852         if (!$form->{taxincluded}) {
853           $form->{totalcredit} += $form->{"tax_$i"};
854         }
855       }
856
857       for (qw(debit credit tax)) {
858         $form->{"${_}_$i"} =
859           ($form->{"${_}_$i"})
860           ? $form->format_amount(\%myconfig, $form->{"${_}_$i"}, 2)
861           : "";
862       }
863
864       if ($i < $form->{rowcount}) {
865         if ($form->{transfer}) {
866           $checked = ($form->{"fx_transaction_$i"}) ? "1" : "";
867           my $x = ($checked) ? "x" : "";
868           $fx_transaction = qq|
869       <td><input type=hidden name="fx_transaction_$i" value="$checked">$x</td>
870     |;
871         }
872         $form->hide_form("accno_$i");
873
874       } else {
875         if ($form->{transfer}) {
876           $fx_transaction = qq|
877       <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
878     |;
879         }
880       }
881     }
882     my $debitreadonly  = "";
883     my $creditreadonly = "";
884     if ($i == $form->{rowcount}) {
885       if ($form->{debitlock}) {
886         $debitreadonly = "readonly";
887       } elsif ($form->{creditlock}) {
888         $creditreadonly = "readonly";
889       }
890     }
891
892     my $projectnumber =
893       NTI($cgi->popup_menu('-name' => "project_id_$i",
894                            '-values' => \@project_values,
895                            '-labels' => \%project_labels,
896                            '-default' => $form->{"project_id_$i"} ));
897     my $projectnumber_hidden = qq|
898     <input type="hidden" name="project_id_$i" value="$form->{"project_id_$i"}">|;
899
900     my $copy2credit = $i == 1 ? 'onkeyup="copy_debit_to_credit()"' : '';
901     my $balance     = $form->format_amount(\%::myconfig, $balances{$accno_id} // 0, 2, 'DRCR');
902
903     print qq|<tr valign=top>
904     $accno
905     <td id="chart_balance_$i" align="right">${balance}</td>
906     $fx_transaction
907     <td><input name="debit_$i" size="8" value="$form->{"debit_$i"}" accesskey=$i $copy2credit $debitreadonly></td>
908     <td><input name="credit_$i" size=8 value="$form->{"credit_$i"}" $creditreadonly></td>
909     <td><input type="hidden" name="tax_$i" value="$form->{"tax_$i"}">$form->{"tax_$i"}</td>
910     $tax_ddbox|;
911
912     if ($form->{show_details}) {
913       print qq|
914     $source
915     $memo
916     <td>$projectnumber</td>
917 |;
918     } else {
919     print qq|
920     $source_hidden
921     $memo_hidden
922     $projectnumber_hidden
923     |;
924     }
925     print qq|
926   </tr>
927 |;
928   }
929
930   $form->hide_form(qw(rowcount selectaccno));
931
932   $main::lxdebug->leave_sub();
933
934 }
935
936 sub _get_radieren {
937   return ($::instance_conf->get_gl_changeable == 2) ? ($::form->current_date(\%::myconfig) eq $::form->{gldate}) : ($::instance_conf->get_gl_changeable == 1);
938 }
939
940 sub form_header {
941   $::lxdebug->enter_sub;
942   $::auth->assert('gl_transactions');
943
944   my ($init) = @_;
945
946   $::request->layout->add_javascripts("autocomplete_chart.js", "kivi.GL.js", "kivi.RecordTemplate.js");
947
948   my @old_project_ids = grep { $_ } map{ $::form->{"project_id_$_"} } 1..$::form->{rowcount};
949
950   $::form->get_lists("projects"  => { "key"       => "ALL_PROJECTS",
951                                     "all"       => 0,
952                                     "old_id"    => \@old_project_ids },
953
954                    "charts"    => { "key"       => "ALL_CHARTS",
955                                     "transdate" => $::form->{transdate} });
956
957   $::form->{ALL_DEPARTMENTS} = SL::DB::Manager::Department->get_all;
958
959   my $title      = $::form->{title};
960   $::form->{title} = $::locale->text("$title General Ledger Transaction");
961   # $locale->text('Add General Ledger Transaction')
962   # $locale->text('Edit General Ledger Transaction')
963
964   map { $::form->{$_} =~ s/\"/&quot;/g }
965     qw(chart taxchart);
966
967   if ($init) {
968     $::request->{layout}->focus("#reference");
969     $::form->{taxincluded} = "1";
970   } else {
971     $::request->{layout}->focus("#accno_id_$::form->{rowcount}_name");
972   }
973
974   $::form->{previous_id}     ||= "--";
975   $::form->{previous_gldate} ||= "--";
976
977   $::form->header;
978   print $::form->parse_html_template('gl/form_header', {
979     hide_title => $title,
980     readonly   => $::form->{id} && ($::form->{locked} || !_get_radieren()),
981   });
982
983   $::lxdebug->leave_sub;
984
985 }
986
987 sub form_footer {
988   $::lxdebug->enter_sub;
989   $::auth->assert('gl_transactions');
990
991   my ($follow_ups, $follow_ups_due);
992
993   if ($::form->{id}) {
994     $follow_ups     = FU->follow_ups('trans_id' => $::form->{id}, 'not_done' => 1);
995     $follow_ups_due = sum map { $_->{due} * 1 } @{ $follow_ups || [] };
996   }
997
998   print $::form->parse_html_template('gl/form_footer', {
999     radieren       => _get_radieren(),
1000     follow_ups     => $follow_ups,
1001     follow_ups_due => $follow_ups_due,
1002   });
1003
1004   $::lxdebug->leave_sub;
1005 }
1006
1007 sub delete {
1008   $main::lxdebug->enter_sub();
1009
1010   my $form     = $main::form;
1011   my $locale   = $main::locale;
1012
1013   $form->header;
1014
1015   print qq|
1016 <form method=post action=gl.pl>
1017 |;
1018
1019   map { $form->{$_} =~ s/\"/&quot;/g } qw(reference description);
1020
1021   delete $form->{header};
1022
1023   foreach my $key (keys %$form) {
1024     next if (($key eq 'login') || ($key eq 'password') || ('' ne ref $form->{$key}));
1025     print qq|<input type="hidden" name="$key" value="$form->{$key}">\n|;
1026   }
1027
1028   print qq|
1029 <h2 class=confirm>| . $locale->text('Confirm!') . qq|</h2>
1030
1031 <h4>|
1032     . $locale->text('Are you sure you want to delete Transaction')
1033     . qq| $form->{reference}</h4>
1034
1035 <input name=action class=submit type=submit value="|
1036     . $locale->text('Yes') . qq|">
1037 </form>
1038 |;
1039   $main::lxdebug->leave_sub();
1040
1041 }
1042
1043 sub yes {
1044   $main::lxdebug->enter_sub();
1045
1046   my $form     = $main::form;
1047   my %myconfig = %main::myconfig;
1048   my $locale   = $main::locale;
1049
1050   if (GL->delete_transaction(\%myconfig, \%$form)){
1051     # saving the history
1052       if(!exists $form->{addition} && $form->{id} ne "") {
1053         $form->{snumbers} = qq|gltransaction_| . $form->{id};
1054         $form->{addition} = "DELETED";
1055         $form->{what_done} = "gl_transaction";
1056         $form->save_history;
1057       }
1058     # /saving the history
1059     $form->redirect($locale->text('Transaction deleted!'))
1060   }
1061   $form->error($locale->text('Cannot delete transaction!'));
1062   $main::lxdebug->leave_sub();
1063
1064 }
1065
1066 sub post_transaction {
1067   $main::lxdebug->enter_sub();
1068
1069   my $form     = $main::form;
1070   my %myconfig = %main::myconfig;
1071   my $locale   = $main::locale;
1072
1073   # check if there is something in reference and date
1074   $form->isblank("reference",   $locale->text('Reference missing!'));
1075   $form->isblank("transdate",   $locale->text('Transaction Date missing!'));
1076   $form->isblank("description", $locale->text('Description missing!'));
1077
1078   my $transdate = $form->datetonum($form->{transdate}, \%myconfig);
1079   my $closedto  = $form->datetonum($form->{closedto},  \%myconfig);
1080
1081   my @a           = ();
1082   my $count       = 0;
1083   my $debittax    = 0;
1084   my $credittax   = 0;
1085   my $debitcount  = 0;
1086   my $creditcount = 0;
1087   my $debitcredit;
1088   my %split_safety = ();
1089
1090   my $dbh = SL::DB->client->dbh;
1091   my ($notax_id) = selectrow_query($form, $dbh, "SELECT id FROM tax WHERE taxkey = 0 LIMIT 1", );
1092   my $zerotaxes  = selectall_hashref_query($form, $dbh, "SELECT id FROM tax WHERE rate = 0", );
1093
1094   my @flds = qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
1095
1096   for my $i (1 .. $form->{rowcount}) {
1097     next if $form->{"debit_$i"} eq "" && $form->{"credit_$i"} eq "";
1098
1099     for (qw(debit credit tax)) {
1100       $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
1101     }
1102
1103     push @a, {};
1104     $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
1105
1106     $split_safety{   $form->{"debit_$i"}  <=> 0 }++;
1107     $split_safety{ - $form->{"credit_$i"} <=> 0 }++;
1108
1109     if ($debitcredit) {
1110       $debitcount++;
1111     } else {
1112       $creditcount++;
1113     }
1114
1115     if (($debitcount >= 2) && ($creditcount == 2)) {
1116       $form->{"credit_$i"} = 0;
1117       $form->{"tax_$i"}    = 0;
1118       $creditcount--;
1119       $form->{creditlock} = 1;
1120     }
1121     if (($creditcount >= 2) && ($debitcount == 2)) {
1122       $form->{"debit_$i"} = 0;
1123       $form->{"tax_$i"}   = 0;
1124       $debitcount--;
1125       $form->{debitlock} = 1;
1126     }
1127     if (($creditcount == 1) && ($debitcount == 2)) {
1128       $form->{creditlock} = 1;
1129     }
1130     if (($creditcount == 2) && ($debitcount == 1)) {
1131       $form->{debitlock} = 1;
1132     }
1133     if ($debitcredit && $credittax) {
1134       $form->{"taxchart_$i"} = "$notax_id--0.00";
1135     }
1136     if (!$debitcredit && $debittax) {
1137       $form->{"taxchart_$i"} = "$notax_id--0.00";
1138     }
1139     my $amount = ($form->{"debit_$i"} == 0)
1140             ? $form->{"credit_$i"}
1141             : $form->{"debit_$i"};
1142     my $j = $#a;
1143     if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
1144       $form->{"taxchart_$i"} = "$notax_id--0.00";
1145       $form->{"tax_$i"}      = 0;
1146     }
1147     my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
1148     my $iswithouttax = grep { $_->{id} == $taxkey } @{ $zerotaxes };
1149     if (!$iswithouttax) {
1150       if ($debitcredit) {
1151         $debittax = 1;
1152       } else {
1153         $credittax = 1;
1154       }
1155
1156       my ($tmpnetamount,$tmpdiff);
1157       ($tmpnetamount,$form->{"tax_$i"},$tmpdiff) = $form->calculate_tax($amount,$rate,$form->{taxincluded} *= 1,2);
1158       if ($debitcredit) {
1159         $form->{"debit_$i"} = $tmpnetamount;
1160       } else {
1161         $form->{"credit_$i"} = $tmpnetamount;
1162       }
1163
1164     } else {
1165       $form->{"tax_$i"} = 0;
1166     }
1167
1168     for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
1169     $count++;
1170   }
1171
1172   if ($split_safety{-1} > 1 && $split_safety{1} > 1) {
1173     $::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. " .
1174                                    "Due to known problems involving accounting software kivitendo does not allow these."));
1175   }
1176
1177   for my $i (1 .. $count) {
1178     my $j = $i - 1;
1179     for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
1180   }
1181
1182   for my $i ($count + 1 .. $form->{rowcount}) {
1183     for (@flds) { delete $form->{"${_}_$i"} }
1184   }
1185
1186   my ($debit, $credit, $taxtotal);
1187   for my $i (1 .. $form->{rowcount}) {
1188     my $dr  = $form->{"debit_$i"};
1189     my $cr  = $form->{"credit_$i"};
1190     my $tax = $form->{"tax_$i"};
1191     if ($dr && $cr) {
1192       $form->error($locale->text('Cannot post transaction with a debit and credit entry for the same account!'));
1193     }
1194     $debit    += $dr + $tax if $dr;
1195     $credit   += $cr + $tax if $cr;
1196     $taxtotal += $tax if $form->{taxincluded}
1197   }
1198
1199   $form->{taxincluded} = 0 if !$taxtotal;
1200
1201   # this is just for the wise guys
1202
1203   $form->error($locale->text('Cannot post transaction above the maximum future booking date!'))
1204     if ($form->date_max_future($form->{"transdate"}, \%myconfig));
1205   $form->error($locale->text('Cannot post transaction for a closed period!'))
1206     if ($form->date_closed($form->{"transdate"}, \%myconfig));
1207   if ($form->round_amount($debit, 2) != $form->round_amount($credit, 2)) {
1208     $form->error($locale->text('Out of balance transaction!'));
1209   }
1210
1211   if ($form->round_amount($debit, 2) + $form->round_amount($credit, 2) == 0) {
1212     $form->error($locale->text('Empty transaction!'));
1213   }
1214
1215   if ((my $errno = GL->post_transaction(\%myconfig, \%$form)) <= -1) {
1216     $errno *= -1;
1217     my @err;
1218     $err[1] = $locale->text('Cannot have a value in both Debit and Credit!');
1219     $err[2] = $locale->text('Debit and credit out of balance!');
1220     $err[3] = $locale->text('Cannot post a transaction without a value!');
1221
1222     $form->error($err[$errno]);
1223   }
1224   undef($form->{callback});
1225   # saving the history
1226   if(!exists $form->{addition} && $form->{id} ne "") {
1227     $form->{snumbers} = qq|gltransaction_| . $form->{id};
1228     $form->{addition} = "POSTED";
1229     $form->{what_done} = "gl transaction";
1230     $form->save_history;
1231   }
1232   # /saving the history
1233
1234   $main::lxdebug->leave_sub();
1235 }
1236
1237 sub post {
1238   $main::lxdebug->enter_sub();
1239
1240   $main::auth->assert('gl_transactions');
1241
1242   my $form     = $main::form;
1243   my $locale   = $main::locale;
1244
1245   if ($::myconfig{mandatory_departments} && !$form->{department_id}) {
1246     $form->{saved_message} = $::locale->text('You have to specify a department.');
1247     update();
1248     exit;
1249   }
1250
1251   $form->{title}  = $locale->text("$form->{title} General Ledger Transaction");
1252   $form->{storno} = 0;
1253
1254   post_transaction();
1255   if ($::instance_conf->get_webdav) {
1256     SL::Webdav->new(type     => 'general_ledger',
1257                     number   => $form->{reference},
1258                    )->webdav_path;
1259   }
1260
1261   $form->{callback} = build_std_url("action=add", "show_details");
1262   $form->redirect($::locale->text("General ledger transaction '#1' posted", $form->{reference}));
1263
1264   $main::lxdebug->leave_sub();
1265 }
1266
1267 sub post_as_new {
1268   $main::lxdebug->enter_sub();
1269
1270   $main::auth->assert('gl_transactions');
1271
1272   my $form     = $main::form;
1273
1274   $form->{id} = 0;
1275   &add;
1276   $main::lxdebug->leave_sub();
1277
1278 }
1279
1280 sub storno {
1281   $main::lxdebug->enter_sub();
1282
1283   $main::auth->assert('gl_transactions');
1284
1285   my $form     = $main::form;
1286   my %myconfig = %main::myconfig;
1287   my $locale   = $main::locale;
1288
1289   # don't cancel cancelled transactions
1290   if (IS->has_storno(\%myconfig, $form, 'gl')) {
1291     $form->{title} = $locale->text("Cancel Accounts Receivables Transaction");
1292     $form->error($locale->text("Transaction has already been cancelled!"));
1293   }
1294
1295   GL->storno($form, \%myconfig, $form->{id});
1296
1297   # saving the history
1298   if(!exists $form->{addition} && $form->{id} ne "") {
1299     $form->{snumbers} = qq|gltransaction_| . $form->{id};
1300     $form->{addition} = "STORNO";
1301     $form->{what_done} = "gl_transaction";
1302     $form->save_history;
1303   }
1304   # /saving the history
1305
1306   $form->redirect(sprintf $locale->text("Transaction %d cancelled."), $form->{storno_id});
1307
1308   $main::lxdebug->leave_sub();
1309 }
1310
1311 sub continue {
1312   call_sub($main::form->{nextsub});
1313 }
1314
1315 sub get_tax_dropdown {
1316   my $transdate    = $::form->{transdate} ? DateTime->from_kivitendo($::form->{transdate}) : DateTime->today_local;
1317   my @tax_accounts = GL->get_active_taxes_for_chart($::form->{accno_id}, $transdate);
1318   my $html         = $::form->parse_html_template("gl/update_tax_accounts", { TAX_ACCOUNTS => \@tax_accounts });
1319
1320   print $::form->ajax_response_header, $html;
1321 }
1322
1323 sub get_chart_balance {
1324   my %balances = GL->get_chart_balances($::form->{accno_id});
1325   my $balance  = $::form->format_amount(\%::myconfig, $balances{ $::form->{accno_id} }, 2, 'DRCR');
1326
1327   print $::form->ajax_response_header, $balance;
1328 }
1329
1330 1;