1 #=====================================================================
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
7 #=====================================================================
8 # SQL-Ledger Accounting
9 # Copyright (c) 1998-2002
11 # Author: Dieter Simader
12 # Email: dsimader@sql-ledger.org
13 # Web: http://www.sql-ledger.org
16 # This program is free software; you can redistribute it and/or modify
17 # it under the terms of the GNU General Public License as published by
18 # the Free Software Foundation; either version 2 of the License, or
19 # (at your option) any later version.
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 # GNU General Public License for more details.
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #======================================================================
32 #======================================================================
37 use POSIX qw(strftime);
38 use List::Util qw(sum);
44 use SL::ReportGenerator;
46 require "bin/mozilla/common.pl";
47 require "bin/mozilla/drafts.pl";
48 require "bin/mozilla/reportgenerator.pl";
50 # this is for our long dates
51 # $locale->text('January')
52 # $locale->text('February')
53 # $locale->text('March')
54 # $locale->text('April')
55 # $locale->text('May ')
56 # $locale->text('June')
57 # $locale->text('July')
58 # $locale->text('August')
59 # $locale->text('September')
60 # $locale->text('October')
61 # $locale->text('November')
62 # $locale->text('December')
64 # this is for our short month
65 # $locale->text('Jan')
66 # $locale->text('Feb')
67 # $locale->text('Mar')
68 # $locale->text('Apr')
69 # $locale->text('May')
70 # $locale->text('Jun')
71 # $locale->text('Jul')
72 # $locale->text('Aug')
73 # $locale->text('Sep')
74 # $locale->text('Oct')
75 # $locale->text('Nov')
76 # $locale->text('Dec')
79 $main::lxdebug->enter_sub();
81 $main::auth->assert('general_ledger');
83 my $form = $main::form;
84 my %myconfig = %main::myconfig;
86 return $main::lxdebug->leave_sub() if (load_draft_maybe());
88 $form->{title} = "Add";
90 $form->{callback} = "gl.pl?action=add" unless $form->{callback};
92 # we use this only to set a default date
93 # yep. aber er holt hier auch schon ALL_CHARTS. Aufwand / Nutzen? jb
94 GL->transaction(\%myconfig, \%$form);
96 $form->{rowcount} = 2;
103 $form->all_departments(\%myconfig);
104 if (@{ $form->{all_departments} || [] }) {
105 $form->{selectdepartment} = "<option>\n";
108 $form->{selectdepartment} .=
109 "<option>$_->{description}--$_->{id}\n"
110 } (@{ $form->{all_departments} || [] });
113 $form->{show_details} = $myconfig{show_form_details} unless defined $form->{show_details};
116 $main::lxdebug->leave_sub();
120 sub prepare_transaction {
121 $main::lxdebug->enter_sub();
123 $main::auth->assert('general_ledger');
125 my $form = $main::form;
126 my %myconfig = %main::myconfig;
128 GL->transaction(\%myconfig, \%$form);
130 $form->{amount} = $form->format_amount(\%myconfig, $form->{amount}, 2);
133 $form->all_departments(\%myconfig);
134 if (@{ $form->{all_departments} || [] }) {
135 $form->{selectdepartment} = "<option>\n";
138 $form->{selectdepartment} .=
139 "<option>$_->{description}--$_->{id}\n"
140 } (@{ $form->{all_departments} || [] });
146 foreach my $ref (@{ $form->{GL} }) {
148 if ($tax && ($ref->{accno} eq $taxaccno)) {
149 $form->{"tax_$j"} = abs($ref->{amount});
150 $form->{"taxchart_$j"} = $ref->{id} . "--" . $ref->{taxrate};
151 if ($form->{taxincluded}) {
152 if ($ref->{amount} < 0) {
153 $form->{"debit_$j"} += $form->{"tax_$j"};
155 $form->{"credit_$j"} += $form->{"tax_$j"};
158 $form->{"project_id_$j"} = $ref->{project_id};
161 $form->{"accno_$i"} = "$ref->{accno}--$ref->{tax_id}";
162 for (qw(fx_transaction source memo)) { $form->{"${_}_$i"} = $ref->{$_} }
163 if ($ref->{amount} < 0) {
164 $form->{totaldebit} -= $ref->{amount};
165 $form->{"debit_$i"} = $ref->{amount} * -1;
167 $form->{totalcredit} += $ref->{amount};
168 $form->{"credit_$i"} = $ref->{amount};
170 $form->{"taxchart_$i"} = "0--0.00";
171 $form->{"project_id_$i"} = $ref->{project_id};
174 if ($ref->{taxaccno} && !$tax) {
175 $taxaccno = $ref->{taxaccno};
183 $form->{rowcount} = $i;
185 ($form->datetonum($form->{transdate}, \%myconfig) <=
186 $form->datetonum($form->{closedto}, \%myconfig));
188 $main::lxdebug->leave_sub();
192 $main::lxdebug->enter_sub();
194 $main::auth->assert('general_ledger');
196 my $form = $main::form;
197 my %myconfig = %main::myconfig;
199 prepare_transaction();
201 $form->{title} = "Edit";
203 $form->{show_details} = $myconfig{show_form_details} unless defined $form->{show_details};
209 $main::lxdebug->leave_sub();
214 $::lxdebug->enter_sub;
215 $::auth->assert('general_ledger');
217 $::form->all_departments(\%::myconfig);
219 projects => { key => "ALL_PROJECTS", all => 1 },
221 $::form->{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all(query => [ deleted => 0 ]);
223 my $onload = "focus()";
226 print $::form->parse_html_template('gl/search', {
228 department_label => sub { ("$_[0]{description}--$_[0]{id}")x2 },
229 employee_label => sub { "$_[0]{id}--$_[0]{name}" },
232 $::lxdebug->leave_sub;
235 sub create_subtotal_row {
236 $main::lxdebug->enter_sub();
238 my ($totals, $columns, $column_alignment, $subtotal_columns, $class) = @_;
240 my $form = $main::form;
241 my %myconfig = %main::myconfig;
243 my $row = { map { $_ => { 'data' => '', 'class' => $class, 'align' => $column_alignment->{$_}, } } @{ $columns } };
245 map { $row->{$_}->{data} = $form->format_amount(\%myconfig, $totals->{$_}, 2) } @{ $subtotal_columns };
247 map { $totals->{$_} = 0 } @{ $subtotal_columns };
249 $main::lxdebug->leave_sub();
254 sub generate_report {
255 $main::lxdebug->enter_sub();
257 $main::auth->assert('general_ledger');
259 my $form = $main::form;
260 my %myconfig = %main::myconfig;
261 my $locale = $main::locale;
263 # 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
265 # <form method=post action=gl.pl>
266 # <input type=hidden name=sort value=datesort> # form->{sort} setzen
267 # <input type=hidden name=nextsub value=generate_report>
269 # anhand von neuer Variable datesort wird jetzt $form->{sort} auf transdate oder gldate gesetzt
270 # damit ist die Hidden Variable "sort" wahrscheinlich sogar überflüssig
272 # ändert man die Sortierreihenfolge per Klick auf eine der Überschriften wird die Variable "sort" per GET übergeben, z.B. id,transdate, gldate, ...
273 # 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
275 if ( $form->{sort} eq 'datesort' ) { # sollte bei einem Post (Aufruf aus Suchmaske) immer wahr sein
276 # je nachdem ob in Suchmaske "transdate" oder "gldate" ausgesucht wurde erstes Suchergebnis entsprechend sortieren
277 $form->{sort} = $form->{datesort};
281 report_generator_set_default_sort("$form->{datesort}", 1);
282 # report_generator_set_default_sort('transdate', 1);
284 GL->all_transactions(\%myconfig, \%$form);
286 my %acctype = ('A' => $locale->text('Asset'),
287 'C' => $locale->text('Contra'),
288 'L' => $locale->text('Liability'),
289 'Q' => $locale->text('Equity'),
290 'I' => $locale->text('Revenue'),
291 'E' => $locale->text('Expense'),);
293 $form->{title} = $locale->text('Journal');
294 if ($form->{category} ne 'X') {
295 $form->{title} .= " : " . $locale->text($acctype{ $form->{category} });
298 $form->{landscape} = 1;
300 my $ml = ($form->{ml} =~ /(A|E|Q)/) ? -1 : 1;
303 gldate transdate id reference description
304 notes source debit debit_accno
305 credit credit_accno debit_tax debit_tax_accno
306 credit_tax credit_tax_accno projectnumbers balance employee
309 # add employee here, so that variable is still known and passed in url when choosing a different sort order in resulting table
310 my @hidden_variables = qw(accno source reference department description notes project_id datefrom dateto employee datesort category l_subtotal);
311 push @hidden_variables, map { "l_${_}" } @columns;
312 foreach ( @hidden_variables ) {
316 my (@options, @date_options);
317 push @options, $locale->text('Account') . " : $form->{accno} $form->{account_description}" if ($form->{accno});
318 push @options, $locale->text('Source') . " : $form->{source}" if ($form->{source});
319 push @options, $locale->text('Reference') . " : $form->{reference}" if ($form->{reference});
320 push @options, $locale->text('Description') . " : $form->{description}" if ($form->{description});
321 push @options, $locale->text('Notes') . " : $form->{notes}" if ($form->{notes});
322 push @options, $locale->text('Employee') . " : $form->{employee_name}" if ($form->{employee_name});
323 my $datesorttext = $form->{datesort} eq 'transdate' ? $locale->text('Invoice Date') : $locale->text('Booking Date');
324 push @date_options, "$datesorttext" if ($form->{datesort} and ($form->{datefrom} or $form->{dateto}));
325 push @date_options, $locale->text('From'), $locale->date(\%myconfig, $form->{datefrom}, 1) if ($form->{datefrom});
326 push @date_options, $locale->text('Bis'), $locale->date(\%myconfig, $form->{dateto}, 1) if ($form->{dateto});
327 push @options, join(' ', @date_options) if (scalar @date_options);
329 if ($form->{department}) {
330 my ($department) = split /--/, $form->{department};
331 push @options, $locale->text('Department') . " : $department";
335 my $callback = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
339 $form->{l_credit_accno} = 'Y';
340 $form->{l_debit_accno} = 'Y';
341 $form->{l_credit_tax} = 'Y';
342 $form->{l_debit_tax} = 'Y';
343 # $form->{l_gldate} = 'Y'; # Spalte mit gldate immer anzeigen
344 $form->{l_credit_tax_accno} = 'Y';
345 $form->{l_datesort} = 'Y';
346 $form->{l_debit_tax_accno} = 'Y';
347 $form->{l_balance} = $form->{accno} ? 'Y' : '';
350 'id' => { 'text' => $locale->text('ID'), },
351 'transdate' => { 'text' => $locale->text('Invoice Date'), },
352 'gldate' => { 'text' => $locale->text('Booking Date'), },
353 'reference' => { 'text' => $locale->text('Reference'), },
354 'source' => { 'text' => $locale->text('Source'), },
355 'description' => { 'text' => $locale->text('Description'), },
356 'notes' => { 'text' => $locale->text('Notes'), },
357 'debit' => { 'text' => $locale->text('Debit'), },
358 'debit_accno' => { 'text' => $locale->text('Debit Account'), },
359 'credit' => { 'text' => $locale->text('Credit'), },
360 'credit_accno' => { 'text' => $locale->text('Credit Account'), },
361 'debit_tax' => { 'text' => $locale->text('Debit Tax'), },
362 'debit_tax_accno' => { 'text' => $locale->text('Debit Tax Account'), },
363 'credit_tax' => { 'text' => $locale->text('Credit Tax'), },
364 'credit_tax_accno' => { 'text' => $locale->text('Credit Tax Account'), },
365 'balance' => { 'text' => $locale->text('Balance'), },
366 'projectnumbers' => { 'text' => $locale->text('Project Numbers'), },
367 'employee' => { 'text' => $locale->text('Employee'), },
370 foreach my $name (qw(id transdate gldate reference description debit_accno credit_accno debit_tax_accno credit_tax_accno)) {
371 my $sortname = $name =~ m/accno/ ? 'accno' : $name;
372 my $sortdir = $sortname eq $form->{sort} ? 1 - $form->{sortdir} : $form->{sortdir};
373 $column_defs{$name}->{link} = $callback . "&sort=$sortname&sortdir=$sortdir";
376 map { $column_defs{$_}->{visible} = $form->{"l_${_}"} ? 1 : 0 } @columns;
377 map { $column_defs{$_}->{visible} = 0 } qw(debit_accno credit_accno debit_tax_accno credit_tax_accno) if $form->{accno};
379 my %column_alignment;
380 map { $column_alignment{$_} = 'right' } qw(balance id debit credit debit_tax credit_tax balance);
381 map { $column_alignment{$_} = 'center' } qw(transdate gldate reference debit_accno credit_accno debit_tax_accno credit_tax_accno);
382 map { $column_alignment{$_} = 'left' } qw(description source notes);
383 map { $column_defs{$_}->{align} = $column_alignment{$_} } keys %column_alignment;
385 my $report = SL::ReportGenerator->new(\%myconfig, $form);
387 $report->set_columns(%column_defs);
388 $report->set_column_order(@columns);
390 $report->set_export_options('generate_report', @hidden_variables, qw(sort sortdir));
392 $report->set_sort_indicator($form->{sort} eq 'accno' ? 'debit_accno' : $form->{sort}, $form->{sortdir});
394 $report->set_options('top_info_text' => join("\n", @options),
395 'output_format' => 'HTML',
396 'title' => $form->{title},
397 'attachment_basename' => $locale->text('general_ledger_list') . strftime('_%Y%m%d', localtime time),
399 $report->set_options_from_form();
400 $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
402 # add sort to callback
403 $form->{callback} = "$callback&sort=" . E($form->{sort}) . "&sortdir=" . E($form->{sortdir});
406 my @totals_columns = qw(debit credit debit_tax credit_tax);
407 my %subtotals = map { $_ => 0 } @totals_columns;
408 my %totals = map { $_ => 0 } @totals_columns;
411 foreach my $ref (@{ $form->{GL} }) {
415 foreach my $key (qw(debit credit debit_tax credit_tax)) {
417 foreach my $idx (sort keys(%{ $ref->{$key} })) {
418 my $value = $ref->{$key}->{$idx};
419 $subtotals{$key} += $value;
420 $totals{$key} += $value;
421 if ($key =~ /debit.*/) {
426 $form->{balance} = $form->{balance} + $value * $ml;
427 push @{ $rows{$key} }, $form->format_amount(\%myconfig, $value, 2);
431 foreach my $key (qw(debit_accno credit_accno debit_tax_accno credit_tax_accno ac_transdate source)) {
432 my $col = $key eq 'ac_transdate' ? 'transdate' : $key;
433 $rows{$col} = [ map { $ref->{$key}->{$_} } sort keys(%{ $ref->{$key} }) ];
437 map { $row->{$_} = { 'data' => '', 'align' => $column_alignment{$_} } } @columns;
440 if ($form->{balance} < 0) {
443 } elsif ($form->{balance} > 0) {
447 my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
450 $row->{balance}->{data} = $data;
451 $row->{projectnumbers}->{data} = join ", ", sort { lc($a) cmp lc($b) } keys %{ $ref->{projectnumbers} };
453 map { $row->{$_}->{data} = $ref->{$_} } qw(id reference description notes gldate employee);
455 map { $row->{$_}->{data} = \@{ $rows{$_} }; } qw(transdate debit credit debit_accno credit_accno debit_tax_accno credit_tax_accno source);
457 foreach my $col (qw(debit_accno credit_accno debit_tax_accno credit_tax_accno)) {
458 $row->{$col}->{link} = [ map { "${callback}&accno=" . E($_) } @{ $rows{$col} } ];
461 map { $row->{$_}->{data} = \@{ $rows{$_} } if ($ref->{"${_}_accno"} ne "") } qw(debit_tax credit_tax);
463 $row->{reference}->{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'id=' . E($ref->{id}), 'callback');
465 my $row_set = [ $row ];
467 if ( ($form->{l_subtotal} eq 'Y' && !$form->{report_generator_csv_options_for_import} )
468 && (($idx == (scalar @{ $form->{GL} } - 1))
469 || ($ref->{ $form->{sort} } ne $form->{GL}->[$idx + 1]->{ $form->{sort} }))) {
470 push @{ $row_set }, create_subtotal_row(\%subtotals, \@columns, \%column_alignment, [ qw(debit credit) ], 'listsubtotal');
473 $report->add_data($row_set);
478 # = 0 for balanced ledger
479 my $balanced_ledger = $totals{debit} + $totals{debit_tax} - $totals{credit} - $totals{credit_tax};
481 my $row = create_subtotal_row(\%totals, \@columns, \%column_alignment, [ qw(debit credit debit_tax credit_tax) ], 'listtotal');
484 if ($form->{balance} < 0) {
487 } elsif ($form->{balance} > 0) {
491 my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
494 $row->{balance}->{data} = $data;
496 if ( !$form->{report_generator_csv_options_for_import} ) {
497 $report->add_separator();
498 $report->add_data($row);
501 my $raw_bottom_info_text;
503 if (!$form->{accno} && (abs($balanced_ledger) > 0.001)) {
504 $raw_bottom_info_text .=
505 '<p><span class="unbalanced_ledger">'
506 . $locale->text('Unbalanced Ledger')
508 . $form->format_amount(\%myconfig, $balanced_ledger, 3)
512 $raw_bottom_info_text .= $form->parse_html_template('gl/generate_report_bottom');
514 $report->set_options('raw_bottom_info_text' => $raw_bottom_info_text);
516 $report->generate_with_headers();
518 $main::lxdebug->leave_sub();
522 $main::lxdebug->enter_sub();
524 $main::auth->assert('general_ledger');
526 my $form = $main::form;
527 my %myconfig = %main::myconfig;
529 $form->{oldtransdate} = $form->{transdate};
537 my ($debitcredit, $amount);
540 qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
542 for my $i (1 .. $form->{rowcount}) {
544 unless (($form->{"debit_$i"} eq "") && ($form->{"credit_$i"} eq "")) {
545 for (qw(debit credit tax)) {
547 $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
551 $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
558 if (($debitcount >= 2) && ($creditcount == 2)) {
559 $form->{"credit_$i"} = 0;
560 $form->{"tax_$i"} = 0;
562 $form->{creditlock} = 1;
564 if (($creditcount >= 2) && ($debitcount == 2)) {
565 $form->{"debit_$i"} = 0;
566 $form->{"tax_$i"} = 0;
568 $form->{debitlock} = 1;
570 if (($creditcount == 1) && ($debitcount == 2)) {
571 $form->{creditlock} = 1;
573 if (($creditcount == 2) && ($debitcount == 1)) {
574 $form->{debitlock} = 1;
576 if ($debitcredit && $credittax) {
577 $form->{"taxchart_$i"} = "0--0.00";
579 if (!$debitcredit && $debittax) {
580 $form->{"taxchart_$i"} = "0--0.00";
583 ($form->{"debit_$i"} == 0)
584 ? $form->{"credit_$i"}
585 : $form->{"debit_$i"};
587 if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
588 $form->{"taxchart_$i"} = "0--0.00";
589 $form->{"tax_$i"} = 0;
591 my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
598 if ($form->{taxincluded}) {
599 $form->{"tax_$i"} = $amount / ($rate + 1) * $rate;
601 $form->{"tax_$i"} = $amount * $rate;
604 $form->{"tax_$i"} = 0;
607 for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
612 for my $i (1 .. $count) {
614 for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
617 for my $i ($count + 1 .. $form->{rowcount}) {
618 for (@flds) { delete $form->{"${_}_$i"} }
621 $form->{rowcount} = $count + 1;
624 $main::lxdebug->leave_sub();
630 $main::lxdebug->enter_sub();
632 $main::auth->assert('general_ledger');
634 my $form = $main::form;
635 my %myconfig = %main::myconfig;
639 # for $i (1 .. $form->{rowcount}) {
640 # $form->{totaldebit} += $form->parse_amount(\%myconfig, $form->{"debit_$i"});
641 # $form->{totalcredit} += $form->parse_amount(\%myconfig, $form->{"credit_$i"});
645 &display_rows($init);
647 $main::lxdebug->leave_sub();
653 $main::lxdebug->enter_sub();
655 $main::auth->assert('general_ledger');
657 my $form = $main::form;
658 my %myconfig = %main::myconfig;
659 my $cgi = $::request->{cgi};
661 $form->{debit_1} = 0 if !$form->{"debit_1"};
662 $form->{totaldebit} = 0;
663 $form->{totalcredit} = 0;
665 my %project_labels = ();
666 my @project_values = ("");
667 foreach my $item (@{ $form->{"ALL_PROJECTS"} }) {
668 push(@project_values, $item->{"id"});
669 $project_labels{$item->{"id"}} = $item->{"projectnumber"};
672 my %chart_labels = ();
673 my @chart_values = ();
676 foreach my $item (@{ $form->{ALL_CHARTS} }) {
677 if ($item->{charttype} eq 'H'){ #falls überschrift
678 next; #überspringen (Bug 1150)
680 my $key = $item->{accno} . "--" . $item->{tax_id};
681 $taxchart_init = $item->{tax_id} unless (@chart_values);
682 push(@chart_values, $key);
683 $chart_labels{$key} = $item->{accno} . "--" . $item->{description};
684 $charts{$item->{accno}} = $item;
687 my %taxchart_labels = ();
688 my @taxchart_values = ();
690 foreach my $item (@{ $form->{ALL_TAXCHARTS} }) {
691 my $key = $item->{id} . "--" . $item->{rate};
692 $taxchart_init = $key if ($taxchart_init == $item->{id});
693 push(@taxchart_values, $key);
694 $taxchart_labels{$key} = $item->{taxdescription} . " " . $item->{rate} * 100 . ' %';
695 $taxcharts{$item->{id}} = $item;
698 my ($source, $memo, $source_hidden, $memo_hidden);
699 for my $i (1 .. $form->{rowcount}) {
700 if ($form->{show_details}) {
702 <td><input name="source_$i" value="$form->{"source_$i"}" size="16"></td>|;
704 <td><input name="memo_$i" value="$form->{"memo_$i"}" size="16"></td>|;
707 <input type="hidden" name="source_$i" value="$form->{"source_$i"}" size="16">|;
709 <input type="hidden" name="memo_$i" value="$form->{"memo_$i"}" size="16">|;
712 my $selected_accno_full;
713 my ($accno_row) = split(/--/, $form->{"accno_$i"});
714 my $item = $charts{$accno_row};
715 $selected_accno_full = "$item->{accno}--$item->{tax_id}";
717 my $selected_taxchart = $form->{"taxchart_$i"};
718 my ($selected_accno, $selected_tax_id) = split(/--/, $selected_accno_full);
719 my ($previous_accno, $previous_tax_id) = split(/--/, $form->{"previous_accno_$i"});
721 if ($previous_accno &&
722 ($previous_accno eq $selected_accno) &&
723 ($previous_tax_id ne $selected_tax_id)) {
724 my $item = $taxcharts{$selected_tax_id};
725 $selected_taxchart = "$item->{id}--$item->{rate}";
728 $selected_accno = '' if ($init);
729 $selected_taxchart ||= $taxchart_init;
731 my $accno = qq|<td>| .
732 NTI($cgi->popup_menu('-name' => "accno_$i",
734 '-onChange' => "setTaxkey($i)",
735 '-style' => 'width:200px',
736 '-values' => \@chart_values,
737 '-labels' => \%chart_labels,
738 '-default' => $selected_accno_full))
739 . $cgi->hidden('-name' => "previous_accno_$i",
740 '-default' => $selected_accno_full)
742 my $tax_ddbox = qq|<td>| .
743 NTI($cgi->popup_menu('-name' => "taxchart_$i",
744 '-id' => "taxchart_$i",
745 '-style' => 'width:200px',
746 '-values' => \@taxchart_values,
747 '-labels' => \%taxchart_labels,
748 '-default' => $selected_taxchart))
751 my ($fx_transaction, $checked);
753 if ($form->{transfer}) {
754 $fx_transaction = qq|
755 <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
760 if ($form->{"debit_$i"} != 0) {
761 $form->{totaldebit} += $form->{"debit_$i"};
762 if (!$form->{taxincluded}) {
763 $form->{totaldebit} += $form->{"tax_$i"};
766 $form->{totalcredit} += $form->{"credit_$i"};
767 if (!$form->{taxincluded}) {
768 $form->{totalcredit} += $form->{"tax_$i"};
772 for (qw(debit credit tax)) {
775 ? $form->format_amount(\%myconfig, $form->{"${_}_$i"}, 2)
779 if ($i < $form->{rowcount}) {
780 if ($form->{transfer}) {
781 $checked = ($form->{"fx_transaction_$i"}) ? "1" : "";
782 my $x = ($checked) ? "x" : "";
783 $fx_transaction = qq|
784 <td><input type=hidden name="fx_transaction_$i" value="$checked">$x</td>
787 $form->hide_form("accno_$i");
790 if ($form->{transfer}) {
791 $fx_transaction = qq|
792 <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
797 my $debitreadonly = "";
798 my $creditreadonly = "";
799 if ($i == $form->{rowcount}) {
800 if ($form->{debitlock}) {
801 $debitreadonly = "readonly";
802 } elsif ($form->{creditlock}) {
803 $creditreadonly = "readonly";
808 NTI($cgi->popup_menu('-name' => "project_id_$i",
809 '-values' => \@project_values,
810 '-labels' => \%project_labels,
811 '-default' => $form->{"project_id_$i"} ));
812 my $projectnumber_hidden = qq|
813 <input type="hidden" name="project_id_$i" value="$form->{"project_id_$i"}">|;
815 my $copy2credit = $i == 1 ? 'onkeyup="copy_debit_to_credit()"' : '';
817 print qq|<tr valign=top>
819 <td id="chart_balance_$i" align="right"> </td>
821 <td><input name="debit_$i" size="8" value="$form->{"debit_$i"}" accesskey=$i $copy2credit $debitreadonly></td>
822 <td><input name="credit_$i" size=8 value="$form->{"credit_$i"}" $creditreadonly></td>
823 <td><input type="hidden" name="tax_$i" value="$form->{"tax_$i"}">$form->{"tax_$i"}</td>
826 if ($form->{show_details}) {
830 <td>$projectnumber</td>
836 $projectnumber_hidden
844 $form->hide_form(qw(rowcount selectaccno));
846 $main::lxdebug->leave_sub();
851 $::lxdebug->enter_sub;
852 $::auth->assert('general_ledger');
856 my @old_project_ids = grep { $_ } map{ $::form->{"project_id_$_"} } 1..$::form->{rowcount};
858 $::form->get_lists("projects" => { "key" => "ALL_PROJECTS",
860 "old_id" => \@old_project_ids },
861 "charts" => { "key" => "ALL_CHARTS",
862 "transdate" => $::form->{transdate} },
863 "taxcharts" => "ALL_TAXCHARTS");
865 GL->get_chart_balances('charts' => $::form->{ALL_CHARTS});
867 my $title = $::form->{title};
868 $::form->{title} = $::locale->text("$title General Ledger Transaction");
869 # $locale->text('Add General Ledger Transaction')
870 # $locale->text('Edit General Ledger Transaction')
872 map { $::form->{$_} =~ s/\"/"/g }
875 $::form->{selectdepartment} =~ s/ selected//;
876 $::form->{selectdepartment} =~
877 s/option>\Q$::form->{department}\E/option selected>$::form->{department}/;
880 $::form->{fokus} = "gl.reference";
881 $::form->{taxincluded} = "1";
883 $::form->{fokus} = qq|gl.accno_$::form->{rowcount}|;
886 $::form->{previous_id} ||= "--";
887 $::form->{previous_gldate} ||= "--";
890 print $::form->parse_html_template('gl/form_header', {
891 hide_title => $title,
894 $::lxdebug->leave_sub;
899 $::lxdebug->enter_sub;
900 $::auth->assert('general_ledger');
902 my ($follow_ups, $follow_ups_due);
905 $follow_ups = FU->follow_ups('trans_id' => $::form->{id});
906 $follow_ups_due = sum map { $_->{due} * 1 } @{ $follow_ups || [] };
909 my $radieren = $::form->current_date(\%::myconfig) eq $::form->{gldate};
911 print $::form->parse_html_template('gl/form_footer', {
912 radieren => $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});