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