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 },
220 employees => "ALL_EMPLOYEES",
223 my $onload = "focus()"
224 . qq|;setupDateFormat('|. $::myconfig{dateformat} . qq|', '| . $::locale->text("Falsches Datumsformat!") . qq|')|
225 . qq|;setupPoints('|. $::myconfig{numberformat} . qq|', '| . $::locale->text("wrongformat") . qq|')|;
228 print $::form->parse_html_template('gl/search', {
230 department_label => sub { ("$_[0]{description}--$_[0]{id}")x2 },
231 employee_label => sub { "$_[0]{id}--$_[0]{name}" },
234 $::lxdebug->leave_sub;
237 sub create_subtotal_row {
238 $main::lxdebug->enter_sub();
240 my ($totals, $columns, $column_alignment, $subtotal_columns, $class) = @_;
242 my $form = $main::form;
243 my %myconfig = %main::myconfig;
245 my $row = { map { $_ => { 'data' => '', 'class' => $class, 'align' => $column_alignment->{$_}, } } @{ $columns } };
247 map { $row->{$_}->{data} = $form->format_amount(\%myconfig, $totals->{$_}, 2) } @{ $subtotal_columns };
249 map { $totals->{$_} = 0 } @{ $subtotal_columns };
251 $main::lxdebug->leave_sub();
256 sub generate_report {
257 $main::lxdebug->enter_sub();
259 $main::auth->assert('general_ledger');
261 my $form = $main::form;
262 my %myconfig = %main::myconfig;
263 my $locale = $main::locale;
265 # generate_report wird beim ersten Aufruf per Weiter-Knopf und POST mit der hidden Variablen sort mit Wert "datesort" (früher "transdate" als Defaultsortiervariable) übertragen
267 # <form method=post action=gl.pl>
268 # <input type=hidden name=sort value=datesort> # form->{sort} setzen
269 # <input type=hidden name=nextsub value=generate_report>
271 # anhand von neuer Variable datesort wird jetzt $form->{sort} auf transdate oder gldate gesetzt
272 # damit ist die Hidden Variable "sort" wahrscheinlich sogar überflüssig
274 # ändert man die Sortierreihenfolge per Klick auf eine der Überschriften wird die Variable "sort" per GET übergeben, z.B. id,transdate, gldate, ...
275 # gl.pl?action=generate_report&employee=18383--Jan%20B%c3%bcren&datesort=transdate&category=X&l_transdate=Y&l_gldate=Y&l_id=Y&l_reference=Y&l_description=Y&l_source=Y&l_debit=Y&l_credit=Y&sort=gldate&sortdir=0
277 if ( $form->{sort} eq 'datesort' ) { # sollte bei einem Post (Aufruf aus Suchmaske) immer wahr sein
278 # je nachdem ob in Suchmaske "transdate" oder "gldate" ausgesucht wurde erstes Suchergebnis entsprechend sortieren
279 $form->{sort} = $form->{datesort};
283 report_generator_set_default_sort("$form->{datesort}", 1);
284 # report_generator_set_default_sort('transdate', 1);
286 GL->all_transactions(\%myconfig, \%$form);
288 my %acctype = ('A' => $locale->text('Asset'),
289 'C' => $locale->text('Contra'),
290 'L' => $locale->text('Liability'),
291 'Q' => $locale->text('Equity'),
292 'I' => $locale->text('Revenue'),
293 'E' => $locale->text('Expense'),);
295 $form->{title} = $locale->text('Journal');
296 if ($form->{category} ne 'X') {
297 $form->{title} .= " : " . $locale->text($acctype{ $form->{category} });
300 $form->{landscape} = 1;
302 my $ml = ($form->{ml} =~ /(A|E|Q)/) ? -1 : 1;
305 gldate transdate id reference description
306 notes source debit debit_accno
307 credit credit_accno debit_tax debit_tax_accno
308 credit_tax credit_tax_accno projectnumbers balance employee
311 # add employee here, so that variable is still known and passed in url when choosing a different sort order in resulting table
312 my @hidden_variables = qw(accno source reference department description notes project_id datefrom dateto employee datesort category l_subtotal);
313 push @hidden_variables, map { "l_${_}" } @columns;
314 foreach ( @hidden_variables ) {
318 my (@options, @date_options);
319 push @options, $locale->text('Account') . " : $form->{accno} $form->{account_description}" if ($form->{accno});
320 push @options, $locale->text('Source') . " : $form->{source}" if ($form->{source});
321 push @options, $locale->text('Reference') . " : $form->{reference}" if ($form->{reference});
322 push @options, $locale->text('Description') . " : $form->{description}" if ($form->{description});
323 push @options, $locale->text('Notes') . " : $form->{notes}" if ($form->{notes});
324 push @options, $locale->text('Employee') . " : $form->{employee_name}" if ($form->{employee_name});
325 my $datesorttext = $form->{datesort} eq 'transdate' ? $locale->text('Invoice Date') : $locale->text('Booking Date');
326 push @date_options, "$datesorttext" if ($form->{datesort} and ($form->{datefrom} or $form->{dateto}));
327 push @date_options, $locale->text('From'), $locale->date(\%myconfig, $form->{datefrom}, 1) if ($form->{datefrom});
328 push @date_options, $locale->text('Bis'), $locale->date(\%myconfig, $form->{dateto}, 1) if ($form->{dateto});
329 push @options, join(' ', @date_options) if (scalar @date_options);
331 if ($form->{department}) {
332 my ($department) = split /--/, $form->{department};
333 push @options, $locale->text('Department') . " : $department";
337 my $callback = build_std_url('action=generate_report', grep { $form->{$_} } @hidden_variables);
341 $form->{l_credit_accno} = 'Y';
342 $form->{l_debit_accno} = 'Y';
343 $form->{l_credit_tax} = 'Y';
344 $form->{l_debit_tax} = 'Y';
345 # $form->{l_gldate} = 'Y'; # Spalte mit gldate immer anzeigen
346 $form->{l_credit_tax_accno} = 'Y';
347 $form->{l_datesort} = 'Y';
348 $form->{l_debit_tax_accno} = 'Y';
349 $form->{l_balance} = $form->{accno} ? 'Y' : '';
352 'id' => { 'text' => $locale->text('ID'), },
353 'transdate' => { 'text' => $locale->text('Invoice Date'), },
354 'gldate' => { 'text' => $locale->text('Booking Date'), },
355 'reference' => { 'text' => $locale->text('Reference'), },
356 'source' => { 'text' => $locale->text('Source'), },
357 'description' => { 'text' => $locale->text('Description'), },
358 'notes' => { 'text' => $locale->text('Notes'), },
359 'debit' => { 'text' => $locale->text('Debit'), },
360 'debit_accno' => { 'text' => $locale->text('Debit Account'), },
361 'credit' => { 'text' => $locale->text('Credit'), },
362 'credit_accno' => { 'text' => $locale->text('Credit Account'), },
363 'debit_tax' => { 'text' => $locale->text('Debit Tax'), },
364 'debit_tax_accno' => { 'text' => $locale->text('Debit Tax Account'), },
365 'credit_tax' => { 'text' => $locale->text('Credit Tax'), },
366 'credit_tax_accno' => { 'text' => $locale->text('Credit Tax Account'), },
367 'balance' => { 'text' => $locale->text('Balance'), },
368 'projectnumbers' => { 'text' => $locale->text('Project Numbers'), },
369 'employee' => { 'text' => $locale->text('Employee'), },
372 foreach my $name (qw(id transdate gldate reference description debit_accno credit_accno debit_tax_accno credit_tax_accno)) {
373 my $sortname = $name =~ m/accno/ ? 'accno' : $name;
374 my $sortdir = $sortname eq $form->{sort} ? 1 - $form->{sortdir} : $form->{sortdir};
375 $column_defs{$name}->{link} = $callback . "&sort=$sortname&sortdir=$sortdir";
378 map { $column_defs{$_}->{visible} = $form->{"l_${_}"} ? 1 : 0 } @columns;
379 map { $column_defs{$_}->{visible} = 0 } qw(debit_accno credit_accno debit_tax_accno credit_tax_accno) if $form->{accno};
381 my %column_alignment;
382 map { $column_alignment{$_} = 'right' } qw(balance id debit credit debit_tax credit_tax balance);
383 map { $column_alignment{$_} = 'center' } qw(transdate gldate reference debit_accno credit_accno debit_tax_accno credit_tax_accno);
384 map { $column_alignment{$_} = 'left' } qw(description source notes);
385 map { $column_defs{$_}->{align} = $column_alignment{$_} } keys %column_alignment;
387 my $report = SL::ReportGenerator->new(\%myconfig, $form);
389 $report->set_columns(%column_defs);
390 $report->set_column_order(@columns);
392 $report->set_export_options('generate_report', @hidden_variables, qw(sort sortdir));
394 $report->set_sort_indicator($form->{sort} eq 'accno' ? 'debit_accno' : $form->{sort}, $form->{sortdir});
396 $report->set_options('top_info_text' => join("\n", @options),
397 'output_format' => 'HTML',
398 'title' => $form->{title},
399 'attachment_basename' => $locale->text('general_ledger_list') . strftime('_%Y%m%d', localtime time),
401 $report->set_options_from_form();
402 $locale->set_numberformat_wo_thousands_separator(\%myconfig) if lc($report->{options}->{output_format}) eq 'csv';
404 # add sort to callback
405 $form->{callback} = "$callback&sort=" . E($form->{sort}) . "&sortdir=" . E($form->{sortdir});
408 my @totals_columns = qw(debit credit debit_tax credit_tax);
409 my %subtotals = map { $_ => 0 } @totals_columns;
410 my %totals = map { $_ => 0 } @totals_columns;
413 foreach my $ref (@{ $form->{GL} }) {
417 foreach my $key (qw(debit credit debit_tax credit_tax)) {
419 foreach my $idx (sort keys(%{ $ref->{$key} })) {
420 my $value = $ref->{$key}->{$idx};
421 $subtotals{$key} += $value;
422 $totals{$key} += $value;
423 if ($key =~ /debit.*/) {
428 $form->{balance} = $form->{balance} + $value * $ml;
429 push @{ $rows{$key} }, $form->format_amount(\%myconfig, $value, 2);
433 foreach my $key (qw(debit_accno credit_accno debit_tax_accno credit_tax_accno ac_transdate source)) {
434 my $col = $key eq 'ac_transdate' ? 'transdate' : $key;
435 $rows{$col} = [ map { $ref->{$key}->{$_} } sort keys(%{ $ref->{$key} }) ];
439 map { $row->{$_} = { 'data' => '', 'align' => $column_alignment{$_} } } @columns;
442 if ($form->{balance} < 0) {
445 } elsif ($form->{balance} > 0) {
449 my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
452 $row->{balance}->{data} = $data;
453 $row->{projectnumbers}->{data} = join ", ", sort { lc($a) cmp lc($b) } keys %{ $ref->{projectnumbers} };
455 map { $row->{$_}->{data} = $ref->{$_} } qw(id reference description notes gldate employee);
457 map { $row->{$_}->{data} = \@{ $rows{$_} }; } qw(transdate debit credit debit_accno credit_accno debit_tax_accno credit_tax_accno source);
459 foreach my $col (qw(debit_accno credit_accno debit_tax_accno credit_tax_accno)) {
460 $row->{$col}->{link} = [ map { "${callback}&accno=" . E($_) } @{ $rows{$col} } ];
463 map { $row->{$_}->{data} = \@{ $rows{$_} } if ($ref->{"${_}_accno"} ne "") } qw(debit_tax credit_tax);
465 $row->{reference}->{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'id=' . E($ref->{id}), 'callback');
467 my $row_set = [ $row ];
469 if (($form->{l_subtotal} eq 'Y')
470 && (($idx == (scalar @{ $form->{GL} } - 1))
471 || ($ref->{ $form->{sort} } ne $form->{GL}->[$idx + 1]->{ $form->{sort} }))) {
472 push @{ $row_set }, create_subtotal_row(\%subtotals, \@columns, \%column_alignment, [ qw(debit credit) ], 'listsubtotal');
475 $report->add_data($row_set);
480 $report->add_separator();
482 # = 0 for balanced ledger
483 my $balanced_ledger = $totals{debit} + $totals{debit_tax} - $totals{credit} - $totals{credit_tax};
485 my $row = create_subtotal_row(\%totals, \@columns, \%column_alignment, [ qw(debit credit debit_tax credit_tax) ], 'listtotal');
488 if ($form->{balance} < 0) {
491 } elsif ($form->{balance} > 0) {
495 my $data = $form->format_amount(\%myconfig, ($form->{balance} * $ml), 2);
498 $row->{balance}->{data} = $data;
500 $report->add_data($row);
502 my $raw_bottom_info_text;
504 if (!$form->{accno} && (abs($balanced_ledger) > 0.001)) {
505 $raw_bottom_info_text .=
506 '<p><span class="unbalanced_ledger">'
507 . $locale->text('Unbalanced Ledger')
509 . $form->format_amount(\%myconfig, $balanced_ledger, 3)
513 $raw_bottom_info_text .= $form->parse_html_template('gl/generate_report_bottom');
515 $report->set_options('raw_bottom_info_text' => $raw_bottom_info_text);
517 $report->generate_with_headers();
519 $main::lxdebug->leave_sub();
523 $main::lxdebug->enter_sub();
525 $main::auth->assert('general_ledger');
527 my $form = $main::form;
528 my %myconfig = %main::myconfig;
530 $form->{oldtransdate} = $form->{transdate};
538 my ($debitcredit, $amount);
541 qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
543 for my $i (1 .. $form->{rowcount}) {
545 unless (($form->{"debit_$i"} eq "") && ($form->{"credit_$i"} eq "")) {
546 for (qw(debit credit tax)) {
548 $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
552 $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
559 if (($debitcount >= 2) && ($creditcount == 2)) {
560 $form->{"credit_$i"} = 0;
561 $form->{"tax_$i"} = 0;
563 $form->{creditlock} = 1;
565 if (($creditcount >= 2) && ($debitcount == 2)) {
566 $form->{"debit_$i"} = 0;
567 $form->{"tax_$i"} = 0;
569 $form->{debitlock} = 1;
571 if (($creditcount == 1) && ($debitcount == 2)) {
572 $form->{creditlock} = 1;
574 if (($creditcount == 2) && ($debitcount == 1)) {
575 $form->{debitlock} = 1;
577 if ($debitcredit && $credittax) {
578 $form->{"taxchart_$i"} = "0--0.00";
580 if (!$debitcredit && $debittax) {
581 $form->{"taxchart_$i"} = "0--0.00";
584 ($form->{"debit_$i"} == 0)
585 ? $form->{"credit_$i"}
586 : $form->{"debit_$i"};
588 if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
589 $form->{"taxchart_$i"} = "0--0.00";
590 $form->{"tax_$i"} = 0;
592 my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
599 if ($form->{taxincluded}) {
600 $form->{"tax_$i"} = $amount / ($rate + 1) * $rate;
602 $form->{"tax_$i"} = $amount * $rate;
605 $form->{"tax_$i"} = 0;
608 for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
613 for my $i (1 .. $count) {
615 for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
618 for my $i ($count + 1 .. $form->{rowcount}) {
619 for (@flds) { delete $form->{"${_}_$i"} }
622 $form->{rowcount} = $count + 1;
625 $main::lxdebug->leave_sub();
631 $main::lxdebug->enter_sub();
633 $main::auth->assert('general_ledger');
635 my $form = $main::form;
636 my %myconfig = %main::myconfig;
640 # for $i (1 .. $form->{rowcount}) {
641 # $form->{totaldebit} += $form->parse_amount(\%myconfig, $form->{"debit_$i"});
642 # $form->{totalcredit} += $form->parse_amount(\%myconfig, $form->{"credit_$i"});
646 &display_rows($init);
648 $main::lxdebug->leave_sub();
654 $main::lxdebug->enter_sub();
656 $main::auth->assert('general_ledger');
658 my $form = $main::form;
659 my %myconfig = %main::myconfig;
660 my $cgi = $::request->{cgi};
662 $form->{debit_1} = 0 if !$form->{"debit_1"};
663 $form->{totaldebit} = 0;
664 $form->{totalcredit} = 0;
666 my %project_labels = ();
667 my @project_values = ("");
668 foreach my $item (@{ $form->{"ALL_PROJECTS"} }) {
669 push(@project_values, $item->{"id"});
670 $project_labels{$item->{"id"}} = $item->{"projectnumber"};
673 my %chart_labels = ();
674 my @chart_values = ();
677 foreach my $item (@{ $form->{ALL_CHARTS} }) {
678 if ($item->{charttype} eq 'H'){ #falls überschrift
679 next; #überspringen (Bug 1150)
681 my $key = $item->{accno} . "--" . $item->{tax_id};
682 $taxchart_init = $item->{tax_id} unless (@chart_values);
683 push(@chart_values, $key);
684 $chart_labels{$key} = $item->{accno} . "--" . $item->{description};
685 $charts{$item->{accno}} = $item;
688 my %taxchart_labels = ();
689 my @taxchart_values = ();
691 foreach my $item (@{ $form->{ALL_TAXCHARTS} }) {
692 my $key = $item->{id} . "--" . $item->{rate};
693 $taxchart_init = $key if ($taxchart_init == $item->{id});
694 push(@taxchart_values, $key);
695 $taxchart_labels{$key} = $item->{taxdescription} . " " . $item->{rate} * 100 . ' %';
696 $taxcharts{$item->{id}} = $item;
699 my ($source, $memo, $source_hidden, $memo_hidden);
700 for my $i (1 .. $form->{rowcount}) {
701 if ($form->{show_details}) {
703 <td><input name="source_$i" value="$form->{"source_$i"}" size="16"></td>|;
705 <td><input name="memo_$i" value="$form->{"memo_$i"}" size="16"></td>|;
708 <input type="hidden" name="source_$i" value="$form->{"source_$i"}" size="16">|;
710 <input type="hidden" name="memo_$i" value="$form->{"memo_$i"}" size="16">|;
713 my $selected_accno_full;
714 my ($accno_row) = split(/--/, $form->{"accno_$i"});
715 my $item = $charts{$accno_row};
716 $selected_accno_full = "$item->{accno}--$item->{tax_id}";
718 my $selected_taxchart = $form->{"taxchart_$i"};
719 my ($selected_accno, $selected_tax_id) = split(/--/, $selected_accno_full);
720 my ($previous_accno, $previous_tax_id) = split(/--/, $form->{"previous_accno_$i"});
722 if ($previous_accno &&
723 ($previous_accno eq $selected_accno) &&
724 ($previous_tax_id ne $selected_tax_id)) {
725 my $item = $taxcharts{$selected_tax_id};
726 $selected_taxchart = "$item->{id}--$item->{rate}";
729 $selected_accno = '' if ($init);
730 $selected_taxchart ||= $taxchart_init;
732 my $accno = qq|<td>| .
733 NTI($cgi->popup_menu('-name' => "accno_$i",
735 '-onChange' => "setTaxkey($i)",
736 '-style' => 'width:200px',
737 '-values' => \@chart_values,
738 '-labels' => \%chart_labels,
739 '-default' => $selected_accno_full))
740 . $cgi->hidden('-name' => "previous_accno_$i",
741 '-default' => $selected_accno_full)
743 my $tax_ddbox = qq|<td>| .
744 NTI($cgi->popup_menu('-name' => "taxchart_$i",
745 '-id' => "taxchart_$i",
746 '-style' => 'width:200px',
747 '-values' => \@taxchart_values,
748 '-labels' => \%taxchart_labels,
749 '-default' => $selected_taxchart))
752 my ($fx_transaction, $checked);
754 if ($form->{transfer}) {
755 $fx_transaction = qq|
756 <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
761 if ($form->{"debit_$i"} != 0) {
762 $form->{totaldebit} += $form->{"debit_$i"};
763 if (!$form->{taxincluded}) {
764 $form->{totaldebit} += $form->{"tax_$i"};
767 $form->{totalcredit} += $form->{"credit_$i"};
768 if (!$form->{taxincluded}) {
769 $form->{totalcredit} += $form->{"tax_$i"};
773 for (qw(debit credit tax)) {
776 ? $form->format_amount(\%myconfig, $form->{"${_}_$i"}, 2)
780 if ($i < $form->{rowcount}) {
781 if ($form->{transfer}) {
782 $checked = ($form->{"fx_transaction_$i"}) ? "1" : "";
783 my $x = ($checked) ? "x" : "";
784 $fx_transaction = qq|
785 <td><input type=hidden name="fx_transaction_$i" value="$checked">$x</td>
788 $form->hide_form("accno_$i");
791 if ($form->{transfer}) {
792 $fx_transaction = qq|
793 <td><input name="fx_transaction_$i" class=checkbox type=checkbox value=1></td>
798 my $debitreadonly = "";
799 my $creditreadonly = "";
800 if ($i == $form->{rowcount}) {
801 if ($form->{debitlock}) {
802 $debitreadonly = "readonly";
803 } elsif ($form->{creditlock}) {
804 $creditreadonly = "readonly";
809 NTI($cgi->popup_menu('-name' => "project_id_$i",
810 '-values' => \@project_values,
811 '-labels' => \%project_labels,
812 '-default' => $form->{"project_id_$i"} ));
813 my $projectnumber_hidden = qq|
814 <input type="hidden" name="project_id_$i" value="$form->{"project_id_$i"}">|;
816 my $copy2credit = $i == 1 ? 'onkeyup="copy_debit_to_credit()"' : '';
818 print qq|<tr valign=top>
820 <td id="chart_balance_$i" align="right"> </td>
822 <td><input name="debit_$i" size="8" value="$form->{"debit_$i"}" accesskey=$i $copy2credit $debitreadonly></td>
823 <td><input name="credit_$i" size=8 value="$form->{"credit_$i"}" $creditreadonly></td>
824 <td><input type="hidden" name="tax_$i" value="$form->{"tax_$i"}">$form->{"tax_$i"}</td>
827 if ($form->{show_details}) {
831 <td>$projectnumber</td>
837 $projectnumber_hidden
845 $form->hide_form(qw(rowcount selectaccno));
847 $main::lxdebug->leave_sub();
853 $main::lxdebug->enter_sub();
855 $main::auth->assert('general_ledger');
857 my $form = $main::form;
858 my %myconfig = %main::myconfig;
859 my $locale = $main::locale;
861 my @old_project_ids = ();
862 map({ push(@old_project_ids, $form->{"project_id_$_"})
863 if ($form->{"project_id_$_"}); } (1..$form->{"rowcount"}));
865 $form->get_lists("projects" => { "key" => "ALL_PROJECTS",
867 "old_id" => \@old_project_ids },
868 "charts" => { "key" => "ALL_CHARTS",
869 "transdate" => $form->{transdate} },
870 "taxcharts" => "ALL_TAXCHARTS");
872 GL->get_chart_balances('charts' => $form->{ALL_CHARTS});
874 my $title = $form->{title};
875 $form->{title} = $locale->text("$title General Ledger Transaction");
876 my $readonly = ($form->{id}) ? "readonly" : "";
878 my $show_details_checked = $form->{show_details} ? "checked" : '';
879 my $ob_transaction_checked = $form->{ob_transaction} ? "checked" : '';
880 my $cb_transaction_checked = $form->{cb_transaction} ? "checked" : '';
882 # $locale->text('Add General Ledger Transaction')
883 # $locale->text('Edit General Ledger Transaction')
885 map { $form->{$_} =~ s/\"/"/g }
886 qw(reference description chart taxchart);
888 $form->{javascript} = qq|<script type="text/javascript">
890 function setTaxkey(row) {
891 var accno = document.getElementById('accno_' + row);
892 var taxkey = accno.options[accno.selectedIndex].value;
893 var reg = /--([0-9]*)/;
894 var found = reg.exec(taxkey);
895 var index = found[1];
896 index = parseInt(index);
897 var tax = 'taxchart_' + row;
898 for (var i = 0; i < document.getElementById(tax).options.length; ++i) {
899 var reg2 = new RegExp("^"+ index, "");
900 if (reg2.exec(document.getElementById(tax).options[i].value)) {
901 document.getElementById(tax).options[i].selected = true;
907 function copy_debit_to_credit() {
908 var txt = document.getElementsByName('debit_1')[0].value;
909 document.getElementsByName('credit_2')[0].value = txt;
913 <script type="text/javascript" src="js/show_form_details.js"></script>
914 <script type="text/javascript" src="js/jquery.js"></script>
917 $form->{selectdepartment} =~ s/ selected//;
918 $form->{selectdepartment} =~
919 s/option>\Q$form->{department}\E/option selected>$form->{department}/;
922 if ((my $rows = $form->numtextrows($form->{description}, 50)) > 1) {
924 qq|<textarea name=description rows=$rows cols=50 wrap=soft $readonly >$form->{description}</textarea>|;
927 qq|<input name=description size=50 value="$form->{description}" $readonly>|;
930 my $taxincluded = ($form->{taxincluded}) ? "checked" : "";
933 $taxincluded = "checked";
939 <th align=right nowrap>| . $locale->text('Department') . qq|</th>
940 <td colspan=3><select name=department>$form->{selectdepartment}</select></td>
941 <input type=hidden name=selectdepartment value="$form->{selectdepartment}">
943 | if $form->{selectdepartment};
945 $form->{fokus} = "gl.reference";
947 $form->{fokus} = qq|gl.accno_$form->{rowcount}|;
950 # use JavaScript Calendar or not
951 $form->{jsscript} = 1;
953 my ($button1, $button2);
954 if ($form->{jsscript}) {
956 # with JavaScript Calendar
958 <td><input name=transdate id=transdate size=11 title="$myconfig{dateformat}" value="$form->{transdate}" $readonly onBlur=\"check_right_date_format(this)\">
959 <input type=button name=transdate id="trigger1" value=|
960 . $locale->text('button') . qq|></td>
965 Form->write_trigger(\%myconfig, "1", "transdate", "BL", "trigger1");
968 # without JavaScript Calendar
970 qq|<td><input name=transdate id=transdate size=11 title="$myconfig{dateformat}" value="$form->{transdate}" $readonly onBlur=\"check_right_date_format(this)\"></td>|;
973 $form->{previous_id} ||= "--";
974 $form->{previous_gldate} ||= "--";
976 $jsscript .= $form->parse_html_template('gl/form_header_chart_balances_js');
981 <body onLoad="focus()">
983 <script type="text/javascript" src="js/follow_up.js"></script>
985 <form method=post name="gl" action=gl.pl>
988 $form->hide_form(qw(id closedto locked storno storno_id previous_id previous_gldate));
991 <input type=hidden name=title value="$title">
993 <input type="hidden" name="follow_up_trans_id_1" value="| . H($form->{id}) . qq|">
994 <input type="hidden" name="follow_up_trans_type_1" value="gl_transaction">
995 <input type="hidden" name="follow_up_trans_info_1" value="| . H($form->{id}) . qq|">
996 <input type="hidden" name="follow_up_rowcount" value="1">
1000 <th class=listtop>$form->{title}</th>
1003 ($form->{saved_message} ? qq|
1005 <td>$form->{saved_message}</th>
1009 <tr height="5"></tr>
1014 <td colspan="6" align="left">|
1015 . $locale->text("Previous transnumber text")
1016 . " $form->{previous_id} "
1017 . $locale->text("Previous transdate text")
1018 . " $form->{previous_gldate}"
1022 <th align=right>| . $locale->text('Reference') . qq|</th>
1023 <td><input name=reference size=20 value="$form->{reference}" $readonly></td>
1027 <th align=right nowrap>| . $locale->text('Date') . qq|</th>
1036 <th align=right>| . $locale->text('Belegnummer') . qq|</th>
1037 <td><input name=id size=20 value="$form->{id}" $readonly></td>
1041 <th align=right width=50%>| . $locale->text('Buchungsdatum') . qq|</th>
1042 <td align=left><input name=gldate size=11 title="$myconfig{dateformat}" value=$form->{gldate} $readonly onBlur=\"check_right_date_format(this)\"></td>
1053 <th align=right width=1%>| . $locale->text('Description') . qq|</th>
1054 <td width=1%>$description</td>
1058 <th align=left>| . $locale->text('MwSt. inkl.') . qq|</th>
1059 <td><input type=checkbox name=taxincluded value=1 $taxincluded></td>
1066 <th align=right width=50%>| . $locale->text('Mitarbeiter') . qq|</th>
1067 <td align=left><input name=employee size=20 value="| . H($form->{employee}) . qq|" readonly></td>
1075 <th align=left width=1%>| . $locale->text('Description') . qq|</th>
1076 <td width=1%>$description</td>
1080 <th align=left>| . $locale->text('MwSt. inkl.') . qq|</th>
1081 <td><input type=checkbox name=taxincluded value=1 $taxincluded></td>
1090 <tr><td colspan=4><table><tr>
1092 | . $locale->text('OB Transaction') . qq|<input type="checkbox" name="ob_transaction" value="1" $ob_transaction_checked>
1095 | . $locale->text('CB Transaction') . qq|<input type="checkbox" name="cb_transaction" value="1" $cb_transaction_checked>
1097 </tr></table></td></tr>
1099 <td width="1%" align="right" nowrap>| . $locale->text('Show details') . qq|</td>
1100 <td width="1%"><input type="checkbox" onclick="show_form_details();" name="show_details" value="1" $show_details_checked></td>
1107 <tr class=listheading>
1108 <th class=listheading style="width:15%">|
1109 . $locale->text('Account') . qq|</th>
1110 <th class=listheading style="width:10%">| . $locale->text('Chart balance') . qq|</th>
1111 <th class=listheading style="width:10%">|
1112 . $locale->text('Debit') . qq|</th>
1113 <th class=listheading style="width:10%">|
1114 . $locale->text('Credit') . qq|</th>
1115 <th class=listheading style="width:10%">|
1116 . $locale->text('Tax') . qq|</th>
1117 <th class=listheading style="width:5%">|
1118 . $locale->text('Taxkey') . qq|</th>|;
1120 if ($form->{show_details}) {
1122 <th class=listheading style="width:20%">| . $locale->text('Source') . qq|</th>
1123 <th class=listheading style="width:20%">| . $locale->text('Memo') . qq|</th>
1124 <th class=listheading style="width:20%">| . $locale->text('Project Number') . qq|</th>
1133 $main::lxdebug->leave_sub();
1138 $main::lxdebug->enter_sub();
1140 $main::auth->assert('general_ledger');
1142 my $form = $main::form;
1143 my %myconfig = %main::myconfig;
1144 my $locale = $main::locale;
1145 my $cgi = $::request->{cgi};
1147 my $follow_ups_block;
1149 my $follow_ups = FU->follow_ups('trans_id' => $form->{id});
1151 if (@{ $follow_ups} ) {
1152 my $num_due = sum map { $_->{due} * 1 } @{ $follow_ups };
1153 $follow_ups_block = qq|<p>| . $locale->text("There are #1 unfinished follow-ups of which #2 are due.", scalar @{ $follow_ups }, $num_due) . qq|</p>|;
1157 my ($dec) = ($form->{totaldebit} =~ /\.(\d+)/);
1159 my $decimalplaces = ($dec > 2) ? $dec : 2;
1160 my $radieren = ($form->current_date(\%myconfig) eq $form->{gldate}) ? 1 : 0;
1163 $form->{$_} = $form->format_amount(\%myconfig, $form->{$_}, 2, " ")
1164 } qw(totaldebit totalcredit);
1167 <tr class=listtotal>
1168 <th colspan="3" align=right class=listtotal> $form->{totaldebit}</th>
1169 <th align=right class=listtotal> $form->{totalcredit}</th>
1177 <input name=callback type=hidden value="$form->{callback}">
1184 my $transdate = $form->datetonum($form->{transdate}, \%myconfig);
1185 my $closedto = $form->datetonum($form->{closedto}, \%myconfig);
1189 if (!$form->{storno}) {
1190 print qq|<input class=submit type=submit name=action value="| . $locale->text('Storno') . qq|">|;
1193 # Löschen und Ändern von Buchungen nicht mehr möglich (GoB) nur am selben Tag möglich
1194 if (!$form->{locked} && $radieren) {
1196 <input class=submit type=submit name=action value="| . $locale->text('Post') . qq|" accesskey="b">
1197 <input class=submit type=submit name=action value="| . $locale->text('Delete') . qq|">|;
1201 <input class=submit type=submit name=action id=update_button value="| . $locale->text('Update') . qq|">
1202 <input type="button" class="submit" onclick="follow_up_window()" value="|
1203 . $locale->text('Follow-Up')
1207 if ($form->{draft_id}) {
1208 my $remove_draft_checked = $form->{remove_draft} ? 'checked' : '';
1210 . qq| <input name="remove_draft" id="remove_draft" type="checkbox" class="checkbox" ${remove_draft_checked}>|
1211 . qq| <label for="remove_draft">| . $locale->text('Remove Draft') . qq|</label>\n|
1216 <input class=submit type=submit name=action id=update_button value="| . $locale->text('Update') . qq|">
1217 <input class=submit type=submit name=action value="| . $locale->text('Post') . qq|"> |
1218 . NTI($cgi->submit('-name' => 'action', '-value' => $locale->text('Save draft'), '-class' => 'submit'))
1219 . $cgi->hidden('-name' => 'draft_id', '-default' => [$form->{draft_id}])
1220 . $cgi->hidden('-name' => 'draft_description', '-default' => [$form->{draft_description}]);
1229 $main::lxdebug->leave_sub();
1234 $main::lxdebug->enter_sub();
1236 my $form = $main::form;
1237 my $locale = $main::locale;
1244 <form method=post action=gl.pl>
1247 map { $form->{$_} =~ s/\"/"/g } qw(reference description);
1249 delete $form->{header};
1251 foreach my $key (keys %$form) {
1252 next if (($key eq 'login') || ($key eq 'password') || ('' ne ref $form->{$key}));
1253 print qq|<input type="hidden" name="$key" value="$form->{$key}">\n|;
1257 <h2 class=confirm>| . $locale->text('Confirm!') . qq|</h2>
1260 . $locale->text('Are you sure you want to delete Transaction')
1261 . qq| $form->{reference}</h4>
1263 <input name=action class=submit type=submit value="|
1264 . $locale->text('Yes') . qq|">
1267 $main::lxdebug->leave_sub();
1272 $main::lxdebug->enter_sub();
1274 my $form = $main::form;
1275 my %myconfig = %main::myconfig;
1276 my $locale = $main::locale;
1278 if (GL->delete_transaction(\%myconfig, \%$form)){
1279 # saving the history
1280 if(!exists $form->{addition} && $form->{id} ne "") {
1281 $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
1282 $form->{addition} = "DELETED";
1283 $form->save_history;
1285 # /saving the history
1286 $form->redirect($locale->text('Transaction deleted!'))
1288 $form->error($locale->text('Cannot delete transaction!'));
1289 $main::lxdebug->leave_sub();
1293 sub post_transaction {
1294 $main::lxdebug->enter_sub();
1296 my $form = $main::form;
1297 my %myconfig = %main::myconfig;
1298 my $locale = $main::locale;
1300 # check if there is something in reference and date
1301 $form->isblank("reference", $locale->text('Reference missing!'));
1302 $form->isblank("transdate", $locale->text('Transaction Date missing!'));
1303 $form->isblank("description", $locale->text('Description missing!'));
1305 my $transdate = $form->datetonum($form->{transdate}, \%myconfig);
1306 my $closedto = $form->datetonum($form->{closedto}, \%myconfig);
1313 my $creditcount = 0;
1315 my %split_safety = ();
1317 my @flds = qw(accno debit credit projectnumber fx_transaction source memo tax taxchart);
1319 for my $i (1 .. $form->{rowcount}) {
1320 next if $form->{"debit_$i"} eq "" && $form->{"credit_$i"} eq "";
1322 for (qw(debit credit tax)) {
1323 $form->{"${_}_$i"} = $form->parse_amount(\%myconfig, $form->{"${_}_$i"});
1327 $debitcredit = ($form->{"debit_$i"} == 0) ? "0" : "1";
1329 $split_safety{ $form->{"debit_$i"} <=> 0 }++;
1330 $split_safety{ - $form->{"credit_$i"} <=> 0 }++;
1338 if (($debitcount >= 2) && ($creditcount == 2)) {
1339 $form->{"credit_$i"} = 0;
1340 $form->{"tax_$i"} = 0;
1342 $form->{creditlock} = 1;
1344 if (($creditcount >= 2) && ($debitcount == 2)) {
1345 $form->{"debit_$i"} = 0;
1346 $form->{"tax_$i"} = 0;
1348 $form->{debitlock} = 1;
1350 if (($creditcount == 1) && ($debitcount == 2)) {
1351 $form->{creditlock} = 1;
1353 if (($creditcount == 2) && ($debitcount == 1)) {
1354 $form->{debitlock} = 1;
1356 if ($debitcredit && $credittax) {
1357 $form->{"taxchart_$i"} = "0--0.00";
1359 if (!$debitcredit && $debittax) {
1360 $form->{"taxchart_$i"} = "0--0.00";
1362 my $amount = ($form->{"debit_$i"} == 0)
1363 ? $form->{"credit_$i"}
1364 : $form->{"debit_$i"};
1366 if (($debitcredit && $credittax) || (!$debitcredit && $debittax)) {
1367 $form->{"taxchart_$i"} = "0--0.00";
1368 $form->{"tax_$i"} = 0;
1370 my ($taxkey, $rate) = split(/--/, $form->{"taxchart_$i"});
1377 if ($form->{taxincluded}) {
1378 $form->{"tax_$i"} = $amount / ($rate + 1) * $rate;
1380 $form->{"debit_$i"} = $form->{"debit_$i"} - $form->{"tax_$i"};
1382 $form->{"credit_$i"} = $form->{"credit_$i"} - $form->{"tax_$i"};
1385 $form->{"tax_$i"} = $amount * $rate;
1388 $form->{"tax_$i"} = 0;
1391 for (@flds) { $a[$j]->{$_} = $form->{"${_}_$i"} }
1395 if ($split_safety{-1} > 1 && $split_safety{1} > 1) {
1396 $::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."));
1399 for my $i (1 .. $count) {
1401 for (@flds) { $form->{"${_}_$i"} = $a[$j]->{$_} }
1404 for my $i ($count + 1 .. $form->{rowcount}) {
1405 for (@flds) { delete $form->{"${_}_$i"} }
1408 my ($debit, $credit, $taxtotal);
1409 for my $i (1 .. $form->{rowcount}) {
1410 my $dr = $form->{"debit_$i"};
1411 my $cr = $form->{"credit_$i"};
1412 my $tax = $form->{"tax_$i"};
1414 $form->error($locale->text('Cannot post transaction with a debit and credit entry for the same account!'));
1416 $debit += $dr + $tax if $dr;
1417 $credit += $cr + $tax if $cr;
1418 $taxtotal += $tax if $form->{taxincluded}
1421 $form->{taxincluded} = 0 if !$taxtotal;
1423 # this is just for the wise guys
1424 $form->error($locale->text('Cannot post transaction for a closed period!'))
1425 if ($form->date_closed($form->{"transdate"}, \%myconfig));
1426 if ($form->round_amount($debit, 2) != $form->round_amount($credit, 2)) {
1427 $form->error($locale->text('Out of balance transaction!'));
1430 if ($form->round_amount($debit, 2) + $form->round_amount($credit, 2) == 0) {
1431 $form->error($locale->text('Empty transaction!'));
1434 if ((my $errno = GL->post_transaction(\%myconfig, \%$form)) <= -1) {
1437 $err[1] = $locale->text('Cannot have a value in both Debit and Credit!');
1438 $err[2] = $locale->text('Debit and credit out of balance!');
1439 $err[3] = $locale->text('Cannot post a transaction without a value!');
1441 $form->error($err[$errno]);
1443 undef($form->{callback});
1444 # saving the history
1445 if(!exists $form->{addition} && $form->{id} ne "") {
1446 $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber};
1447 $form->{addition} = "SAVED";
1448 $form->{what_done} = $locale->text("Buchungsnummer") . " = " . $form->{id};
1449 $form->save_history;
1451 # /saving the history
1453 $main::lxdebug->leave_sub();
1457 $main::lxdebug->enter_sub();
1459 $main::auth->assert('general_ledger');
1461 my $form = $main::form;
1462 my $locale = $main::locale;
1464 if ($::myconfig{mandatory_departments} && !$form->{department}) {
1465 $form->{saved_message} = $::locale->text('You have to specify a department.');
1470 $form->{title} = $locale->text("$form->{title} General Ledger Transaction");
1471 $form->{storno} = 0;
1475 remove_draft() if $form->{remove_draft};
1477 $form->{callback} = build_std_url("action=add&DONT_LOAD_DRAFT=1", "show_details");
1478 $form->redirect($form->{callback});
1480 $main::lxdebug->leave_sub();
1484 $main::lxdebug->enter_sub();
1486 $main::auth->assert('general_ledger');
1488 my $form = $main::form;
1492 $main::lxdebug->leave_sub();
1497 $main::lxdebug->enter_sub();
1499 $main::auth->assert('general_ledger');
1501 my $form = $main::form;
1502 my %myconfig = %main::myconfig;
1503 my $locale = $main::locale;
1505 # don't cancel cancelled transactions
1506 if (IS->has_storno(\%myconfig, $form, 'gl')) {
1507 $form->{title} = $locale->text("Cancel Accounts Receivables Transaction");
1508 $form->error($locale->text("Transaction has already been cancelled!"));
1511 GL->storno($form, \%myconfig, $form->{id});
1513 # saving the history
1514 if(!exists $form->{addition} && $form->{id} ne "") {
1515 $form->{snumbers} = "ordnumber_$form->{ordnumber}";
1516 $form->{addition} = "STORNO";
1517 $form->save_history;
1519 # /saving the history
1521 $form->redirect(sprintf $locale->text("Transaction %d cancelled."), $form->{storno_id});
1523 $main::lxdebug->leave_sub();
1527 call_sub($main::form->{nextsub});