Pflichtenheftaufträge: Pauschalpos. in Ang./Auftr. erstellen können
[kivitendo-erp.git] / SL / RP.pm
1 #=====================================================================
2 # LX-Office ERP
3 # Copyright (C) 2004
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
6 #
7 #=====================================================================
8 # SQL-Ledger Accounting
9 # Copyright (C) 1998-2002
10 #
11 #  Author: Dieter Simader
12 #   Email: dsimader@sql-ledger.org
13 #     Web: http://www.sql-ledger.org
14 #
15 #  Contributors: Benjamin Lee <benjaminlee@consultant.com>
16 #
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation; either version 2 of the License, or
20 # (at your option) any later version.
21 #
22 # This program is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 # GNU General Public License for more details.
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #======================================================================
30 #
31 # backend code for reports
32 #
33 #======================================================================
34
35 package RP;
36
37 use SL::DBUtils;
38 use Data::Dumper;
39 use List::Util qw(sum);
40
41 # use warnings;
42 use strict;
43
44 # new implementation of balance sheet
45 # readme!
46 #
47 # stuff missing from the original implementation:
48 # - bold stuff
49 # - subdescription
50 # - proper testing for heading charts
51 # - transmission from $form to TMPL realm is not as clear as i'd like
52
53 sub get_balance_starting_date {
54
55   # determine date from which the balance is calculated. The method is
56   # configured in the client configuration.
57
58   my $asofdate = shift;
59   return unless $asofdate;
60
61   $asofdate = $::locale->parse_date_to_object($asofdate);
62
63   my $form = $main::form;
64   my $dbh  = $::form->get_standard_dbh;
65
66   my $startdate_method = $::instance_conf->get_balance_startdate_method;
67
68   # We could use the following objects to determine the starting date for
69   # calculating the balance from asofdate (the reference date for the balance):
70   # * start_of_year - 1.1., no deviating fiscal year supported
71   # * closed_to - all transactions since the books were last closed
72   # * last_ob - all transactions since last opening balance transaction (usually 1.1.)
73   # * mindate - all transactions in database
74
75   my $start_of_year = $asofdate->clone();
76   $start_of_year->set_day(1);
77   $start_of_year->set_month(1);
78
79   # closedto assumes that we only close the books at the end of a fiscal year,
80   # never during the fiscal year. If this assumption is valid closedto should
81   # also work for deviating fiscal years. But as the trial balance (SuSa)
82   # doesn't yet deal with deviating fiscal years, and is useful to also close
83   # the books after a month has been exported via DATEV, so this method of
84   # determining the starting date isn't recommended and has been removed as
85   # default.
86   my ($closedto) = selectfirst_array_query($form, $dbh, 'SELECT closedto FROM defaults');
87   if ($closedto) {
88     $closedto = $::locale->parse_date_to_object($closedto);
89     $closedto->subtract(years => 1) while ($asofdate - $closedto)->is_negative;
90     $closedto->add(days => 1);
91   };
92
93   my ($query, $startdate, $last_ob, $mindate);
94   $query = qq|select max(transdate) from acc_trans where ob_transaction is true and transdate <= ?|;
95   ($last_ob) = selectrow_query($::form, $dbh, $query, $::locale->format_date(\%::myconfig, $asofdate));
96   $last_ob = $::locale->parse_date_to_object($last_ob) if $last_ob;
97
98   $query = qq|select min(transdate) from acc_trans|;
99   ($mindate) = selectrow_query($::form, $dbh, $query);
100   $mindate = $::locale->parse_date_to_object($mindate);
101
102   # the default method is to use all transactions ($mindate)
103
104   if ( $startdate_method eq 'closed_to' and $closedto ) {
105     # if no closedto is configured use default
106     return $::locale->format_date(\%::myconfig, $closedto);
107
108   } elsif ( $startdate_method eq 'start_of_year' ) {
109
110     return $::locale->format_date(\%::myconfig, $start_of_year);
111
112   } elsif ( $startdate_method eq 'all_transactions' ) {
113
114     return $::locale->format_date(\%::myconfig, $mindate);
115
116   } elsif ( $startdate_method eq 'last_ob_or_all_transactions' and $last_ob ) {
117     # use default if there are no ob transactions
118
119     return $::locale->format_date(\%::myconfig, $last_ob);
120
121   } elsif ( $startdate_method eq 'last_ob_or_start_of_year' ) {
122
123     if ( $last_ob ) {
124       return $::locale->format_date(\%::myconfig, $last_ob);
125     } else {
126       return $::locale->format_date(\%::myconfig, $start_of_year);
127     };
128
129   } else {
130     # default action, also used for closedto and last_ob_or_all_transactions if
131     # there are no valid dates
132
133     return $::locale->format_date(\%::myconfig, $mindate);
134   };
135
136 };
137
138 sub balance_sheet {
139   $main::lxdebug->enter_sub();
140
141   my $myconfig = \%main::myconfig;
142   my $form     = $main::form;
143   my $dbh      = $::form->get_standard_dbh;
144
145   my $last_period = 0;
146   my @categories  = qw(A C L Q);
147
148   # if there are any dates construct a where
149   if ($form->{asofdate}) {
150     $form->{period} = $form->{this_period} = conv_dateq($form->{asofdate});
151   }
152
153   # get starting date for calculating balance
154   $form->{this_startdate} = get_balance_starting_date($form->{asofdate});
155
156   get_accounts($dbh, $last_period, $form->{this_startdate}, $form->{asofdate}, $form, \@categories);
157
158   # if there are any compare dates
159   if ($form->{compareasofdate}) {
160     $last_period = 1;
161
162     $form->{last_startdate} = get_balance_starting_date($form->{compareasofdate});
163
164     get_accounts($dbh, $last_period, $form->{last_startdate} , $form->{compareasofdate}, $form, \@categories);
165     $form->{last_period} = conv_dateq($form->{compareasofdate});
166   }
167
168   # now we got $form->{A}{accno}{ }    assets
169   # and $form->{L}{accno}{ }           liabilities
170   # and $form->{Q}{accno}{ }           equity
171   # build asset accounts
172
173   my %account = ('A' => { 'ml'     => -1 },
174                  'L' => { 'ml'     =>  1 },
175                  'Q' => { 'ml'     =>  1 });
176
177   my $TMPL_DATA = {};
178
179   foreach my $category (grep { !/C/ } @categories) {
180
181     $TMPL_DATA->{$category} = [];
182     my $ml  = $account{$category}{ml};
183
184     foreach my $key (sort keys %{ $form->{$category} }) {
185
186       my $row = { %{ $form->{$category}{$key} } };
187
188       # if charttype "heading" - calculate this entry, start a new batch of charts belonging to this heading and skip the rest bo the loop
189       # header charts are not real charts. start a sub aggregation with them, but don't calculate anything with them
190       if ($row->{charttype} eq "H") {
191         if ($account{$category}{subtotal} && $form->{l_subtotal}) {
192           $row->{subdescription} = $account{$category}{subdescription};
193           $row->{this}           = $account{$category}{subthis} * $ml;                   # format: $dec, $dash
194           $row->{last}           = $account{$category}{sublast} * $ml if $last_period;   # format: $dec, $dash
195         }
196
197         $row->{subheader} = 1;
198         $account{$category}{subthis}        = $row->{this};
199         $account{$category}{sublast}        = $row->{last};
200         $account{$category}{subdescription} = $row->{description};
201         $account{$category}{subtotal} = 1;
202
203         $row->{this} = 0;
204         $row->{last} = 0;
205
206         next unless $form->{l_heading};
207       }
208
209       for my $period (qw(this last)) {
210         next if ($period eq 'last' && !$last_period);
211         # only add assets
212         $row->{$period}                    *= $ml;
213       }
214
215       push @{ $TMPL_DATA->{$category} }, $row;
216     } # foreach
217
218     # resolve heading/subtotal
219     if ($account{$category}{subtotal} && $form->{l_subtotal}) {
220       $TMPL_DATA->{$category}[-1]{subdescription} = $account{$category}{subdescription};
221       $TMPL_DATA->{$category}[-1]{this}           = $account{$category}{subthis} * $ml;                   # format: $dec, $dash
222       $TMPL_DATA->{$category}[-1]{last}           = $account{$category}{sublast} * $ml if $last_period;   # format: $dec, $dash
223     }
224
225     $TMPL_DATA->{total}{$category}{this} = sum map { $_->{this} } @{ $TMPL_DATA->{$category} };
226     $TMPL_DATA->{total}{$category}{last} = sum map { $_->{last} } @{ $TMPL_DATA->{$category} };
227   }
228
229   for my $period (qw(this last)) {
230     next if ($period eq 'last' && !$last_period);
231
232     $form->{E}{$period}             = $TMPL_DATA->{total}{A}{$period} - $TMPL_DATA->{total}{L}{$period} - $TMPL_DATA->{total}{Q}{$period};
233     $TMPL_DATA->{total}{Q}{$period}     += $form->{E}{$period};
234     $TMPL_DATA->{total}{$period}    = $TMPL_DATA->{total}{L}{$period} + $TMPL_DATA->{total}{Q}{$period};
235   }
236     $form->{E}{description}='nicht verbuchter Gewinn/Verlust';
237   push @{ $TMPL_DATA->{Q} }, $form->{E};
238
239   $main::lxdebug->leave_sub();
240
241   return $TMPL_DATA;
242 }
243
244 sub get_accounts {
245   $main::lxdebug->enter_sub();
246
247   my ($dbh, $last_period, $fromdate, $todate, $form, $categories) = @_;
248
249   my ($null, $department_id) = split /--/, $form->{department};
250
251   my $query;
252   my $dpt_where = '';
253   my $dpt_where_without_arapgl = '';
254   my $project   = '';
255   my $where     = "1 = 1";
256   my $glwhere   = "";
257   my $subwhere  = "";
258   my $item;
259   my $sth;
260   my $dec = $form->{decimalplaces};
261
262   my $category = qq| AND (| . join(" OR ", map({ "(c.category = " . $dbh->quote($_) . ")" } @{$categories})) . qq|) |;
263
264   # get headings
265   $query =
266     qq|SELECT c.accno, c.description, c.category
267        FROM chart c
268        WHERE (c.charttype = 'H')
269          $category
270        ORDER by c.accno|;
271
272   $sth = prepare_execute_query($form, $dbh, $query);
273
274   my @headingaccounts = ();
275   while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
276     $form->{ $ref->{category} }{ $ref->{accno} }{description} =
277       "$ref->{description}";
278     $form->{ $ref->{category} }{ $ref->{accno} }{charttype} = "H";
279     $form->{ $ref->{category} }{ $ref->{accno} }{accno}     = $ref->{accno};
280
281     push @headingaccounts, $ref->{accno};
282   }
283
284   $sth->finish;
285
286   # filter for opening and closing bookings
287   # if l_ob is selected l_cb is always ignored
288   if ( $last_period ) {
289     # ob/cb-settings for "compared to" balance
290     if ( $form->{l_ob_compared} ) {
291       $where .= ' AND ac.ob_transaction is true  '
292     } elsif ( not $form->{l_cb_compared} ) {
293       $where .= ' AND ac.cb_transaction is false ';
294     };
295   } else {
296     # ob/cb-settings for "as of" balance
297     if ( $form->{l_ob} ) {
298       $where .= ' AND ac.ob_transaction is true  '
299     } elsif ( not $form->{l_cb} ) {
300       $where .= ' AND ac.cb_transaction is false ';
301     };
302   };
303
304
305   if ($fromdate) {
306     $fromdate = conv_dateq($fromdate);
307     if ($form->{method} eq 'cash') {
308       $subwhere .= " AND (transdate >= $fromdate)";
309       $glwhere = " AND (ac.transdate >= $fromdate)";
310     } else {
311       $where .= " AND (ac.transdate >= $fromdate)";
312     }
313   }
314
315   if ($todate) {
316     $todate = conv_dateq($todate);
317     $where    .= " AND (ac.transdate <= $todate)";
318     $subwhere .= " AND (transdate <= $todate)";
319   }
320
321   if ($department_id) {
322     $dpt_where = qq| AND (a.department_id = | . conv_i($department_id, 'NULL') . qq|)|;
323   }
324
325   if ($form->{project_id}) {
326     # Diese Bedingung wird derzeit niemals wahr sein, da man in Bericht->Bilanz keine
327     # Projekte auswählen kann
328     $project = qq| AND (ac.project_id = | . conv_i($form->{project_id}, 'NULL') . qq|) |;
329   }
330
331   if ($form->{method} eq 'cash') {
332     $query =
333       qq|SELECT c.accno, sum(ac.amount) AS amount, c.description, c.category
334          FROM acc_trans ac
335          JOIN chart c ON (c.id = ac.chart_id)
336          JOIN ar a ON (a.id = ac.trans_id)
337          WHERE $where
338            $dpt_where
339            $category
340            AND ac.trans_id IN
341              (
342                SELECT trans_id
343                FROM acc_trans a
344                WHERE (a.chart_link LIKE '%AR_paid%')
345                $subwhere
346              )
347            $project
348          GROUP BY c.accno, c.description, c.category
349
350          UNION ALL
351
352          SELECT c.accno, sum(ac.amount) AS amount, c.description, c.category
353          FROM acc_trans ac
354          JOIN chart c ON (c.id = ac.chart_id)
355          JOIN ap a ON (a.id = ac.trans_id)
356          WHERE $where
357            $dpt_where
358            $category
359            AND ac.trans_id IN
360              (
361                SELECT trans_id
362                FROM acc_trans a
363                WHERE (a.chart_link LIKE '%AP_paid%')
364                $subwhere
365              )
366            $project
367          GROUP BY c.accno, c.description, c.category
368
369          UNION ALL
370
371          SELECT c.accno, sum(ac.amount) AS amount, c.description, c.category
372          FROM acc_trans ac
373          JOIN chart c ON (c.id = ac.chart_id)
374          JOIN gl a ON (a.id = ac.trans_id)
375          WHERE $where
376            $glwhere
377            $dpt_where
378            $category
379              AND NOT ((ac.chart_link = 'AR') OR (ac.chart_link = 'AP'))
380            $project
381          GROUP BY c.accno, c.description, c.category |;
382
383     if ($form->{project_id}) {
384       # s.o. keine Projektauswahl in Bilanz
385       $query .=
386         qq|
387          UNION ALL
388
389          SELECT c.accno AS accno, SUM(ac.sellprice * ac.qty) AS amount, c.description AS description, c.category
390          FROM invoice ac
391          JOIN ar a ON (a.id = ac.trans_id)
392          JOIN parts p ON (ac.parts_id = p.id)
393          JOIN chart c on (p.income_accno_id = c.id)
394          -- use transdate from subwhere
395          WHERE (c.category = 'I')
396            $subwhere
397            $dpt_where
398            AND ac.trans_id IN
399              (
400                SELECT trans_id
401                FROM acc_trans a
402                WHERE (a.chart_link LIKE '%AR_paid%')
403                $subwhere
404              )
405            $project
406          GROUP BY c.accno, c.description, c.category
407
408          UNION ALL
409
410          SELECT c.accno AS accno, SUM(ac.sellprice) AS amount, c.description AS description, c.category
411          FROM invoice ac
412          JOIN ap a ON (a.id = ac.trans_id)
413          JOIN parts p ON (ac.parts_id = p.id)
414          JOIN chart c on (p.expense_accno_id = c.id)
415          WHERE (c.category = 'E')
416            $subwhere
417            $dpt_where
418            AND ac.trans_id IN
419              (
420                SELECT trans_id
421                FROM acc_trans a
422                WHERE a.chart_link LIKE '%AP_paid%'
423                $subwhere
424              )
425            $project
426          GROUP BY c.accno, c.description, c.category |;
427     }
428
429   } else {                      # if ($form->{method} eq 'cash')
430     if ($department_id) {
431       $dpt_where = qq| AND a.department_id = | . conv_i($department_id);
432       $dpt_where_without_arapgl = qq| AND COALESCE((SELECT department_id FROM ar WHERE ar.id=ac.trans_id),
433                                                    (SELECT department_id FROM gl WHERE gl.id=ac.trans_id),
434                                                    (SELECT department_id FROM ap WHERE ap.id=ac.trans_id)) = | . conv_i($department_id);
435     }
436
437     $query = qq|
438       SELECT c.accno, sum(ac.amount) AS amount, c.description, c.category
439       FROM acc_trans ac
440       JOIN chart c ON (c.id = ac.chart_id)
441       WHERE $where
442         $dpt_where_without_arapgl
443         $category
444         $project
445       GROUP BY c.accno, c.description, c.category |;
446
447     if ($form->{project_id}) {
448       # s.o. keine Projektauswahl in Bilanz
449       $query .= qq|
450       UNION ALL
451
452       SELECT c.accno AS accno, SUM(ac.sellprice * ac.qty) AS amount, c.description AS description, c.category
453       FROM invoice ac
454       JOIN ar a ON (a.id = ac.trans_id)
455       JOIN parts p ON (ac.parts_id = p.id)
456       JOIN chart c on (p.income_accno_id = c.id)
457       -- use transdate from subwhere
458       WHERE (c.category = 'I')
459         $subwhere
460         $dpt_where
461         $project
462       GROUP BY c.accno, c.description, c.category
463
464       UNION ALL
465
466       SELECT c.accno AS accno, SUM(ac.sellprice * ac.qty) * -1 AS amount, c.description AS description, c.category
467       FROM invoice ac
468       JOIN ap a ON (a.id = ac.trans_id)
469       JOIN parts p ON (ac.parts_id = p.id)
470       JOIN chart c on (p.expense_accno_id = c.id)
471       WHERE (c.category = 'E')
472         $subwhere
473         $dpt_where
474         $project
475       GROUP BY c.accno, c.description, c.category |;
476     }
477   }
478
479   my @accno;
480   my $accno;
481   my $ref;
482
483   $sth = prepare_execute_query($form, $dbh, $query);
484
485   while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
486
487     if ($ref->{category} eq 'C') {
488       $ref->{category} = 'A';
489     }
490
491     # get last heading account
492     @accno = grep { $_ le "$ref->{accno}" } @headingaccounts;
493     $accno = pop @accno;
494     if ($accno) {
495       if ($last_period) {
496         $form->{ $ref->{category} }{$accno}{last} += $ref->{amount};
497       } else {
498         $form->{ $ref->{category} }{$accno}{this} += $ref->{amount};
499       }
500     }
501
502     $form->{ $ref->{category} }{ $ref->{accno} }{accno}       = $ref->{accno};
503     $form->{ $ref->{category} }{ $ref->{accno} }{description} = $ref->{description};
504     $form->{ $ref->{category} }{ $ref->{accno} }{charttype} = "A";
505
506     if ($last_period) {
507       $form->{ $ref->{category} }{ $ref->{accno} }{last} += $ref->{amount};
508     } else {
509       $form->{ $ref->{category} }{ $ref->{accno} }{this} += $ref->{amount};
510     }
511   }
512   $sth->finish;
513
514   # remove accounts with zero balance
515   foreach $category (@{$categories}) {
516     foreach $accno (keys %{ $form->{$category} }) {
517       $form->{$category}{$accno}{last} = $form->round_amount($form->{$category}{$accno}{last}, $dec);
518       $form->{$category}{$accno}{this} = $form->round_amount($form->{$category}{$accno}{this}, $dec);
519
520       delete $form->{$category}{$accno}
521         if (   $form->{$category}{$accno}{this} == 0
522             && $form->{$category}{$accno}{last} == 0);
523     }
524   }
525
526   $main::lxdebug->leave_sub();
527 }
528
529 sub get_accounts_g {
530   $main::lxdebug->enter_sub();
531
532   my ($dbh, $last_period, $fromdate, $todate, $form, $category) = @_;
533
534   my ($null, $department_id) = split /--/, $form->{department};
535
536   my $query;
537   my $dpt_where;
538   my $dpt_where_without_arapgl;
539   my $project;
540   my $where    = "1 = 1";
541   my $glwhere  = "";
542   my $prwhere  = "";
543   my $subwhere = "";
544   my $inwhere = "";
545   my $item;
546
547   $where .= ' AND ac.cb_transaction is false ' unless $form->{l_cb};
548
549   if ($fromdate) {
550     $fromdate = conv_dateq($fromdate);
551     if ($form->{method} eq 'cash') {
552       $subwhere .= " AND (transdate    >= $fromdate)";
553       $glwhere   = " AND (ac.transdate >= $fromdate)";
554       $prwhere   = " AND (a.transdate  >= $fromdate)";
555       $inwhere   = " AND (acc.transdate >= $fromdate)";
556     } else {
557       $where    .= " AND (ac.transdate >= $fromdate)";
558     }
559   }
560
561   if ($todate) {
562     $todate = conv_dateq($todate);
563     $subwhere   .= " AND (transdate    <= $todate)";
564     $where      .= " AND (ac.transdate <= $todate)";
565     $prwhere    .= " AND (a.transdate  <= $todate)";
566     $inwhere    .= " AND (acc.transdate <= $todate)";
567   }
568
569   if ($department_id) {
570     $dpt_where = qq| AND (a.department_id = | . conv_i($department_id, 'NULL') . qq|) |;
571   }
572
573   if ($form->{project_id}) {
574     $project = qq| AND (ac.project_id = | . conv_i($form->{project_id}) . qq|) |;
575   }
576
577 #
578 # GUV patch by Ronny Rentner (Bug 1190)
579 #
580 # GUV IST-Versteuerung
581 #
582 # Alle tatsaechlichen _Zahlungseingaenge_
583 # im Zeitraum erfassen
584 # (Teilzahlungen werden prozentual auf verschiedene Steuern aufgeteilt)
585 #
586 #
587
588   if ($form->{method} eq 'cash') {
589     $query =
590       qq|
591        SELECT SUM( ac.amount * CASE WHEN COALESCE((SELECT amount FROM ar a WHERE id = ac.trans_id $dpt_where), 0) != 0 THEN
592             /* ar amount is not zero, so we can divide by amount   */
593                     (SELECT SUM(acc.amount) * -1
594                      FROM acc_trans acc
595                      WHERE 1=1 $inwhere
596                      AND acc.trans_id = ac.trans_id
597                      AND acc.chart_link LIKE '%AR_paid%')
598                   / (SELECT amount FROM ar WHERE id = ac.trans_id)
599             ELSE 0
600             /* ar amount is zero, or we are checking with a non-ar-transaction, so we return 0 in both cases as multiplicator of ac.amount */
601             END
602                 ) AS amount, c.$category
603        FROM acc_trans ac
604        LEFT JOIN chart c ON (c.id  = ac.chart_id)
605        LEFT JOIN ar      ON (ar.id = ac.trans_id)
606       WHERE ac.trans_id IN (SELECT DISTINCT trans_id FROM acc_trans WHERE 1=1 $subwhere)
607
608       GROUP BY c.$category
609
610 /*
611        SELECT SUM(ac.amount * chart_category_to_sgn(c.category)) AS amount, c.$category
612          FROM acc_trans ac
613          JOIN chart c ON (c.id = ac.chart_id)
614          JOIN ar a ON (a.id = ac.trans_id)
615          WHERE $where $dpt_where
616            AND ac.trans_id IN ( SELECT trans_id FROM acc_trans a WHERE (a.chart_link LIKE '%AR_paid%') $subwhere)
617            $project
618          GROUP BY c.$category
619 */
620          UNION
621
622          SELECT SUM(ac.amount * chart_category_to_sgn(c.category)) AS amount, c.$category
623          FROM acc_trans ac
624          JOIN chart c ON (c.id = ac.chart_id)
625          JOIN ap a ON (a.id = ac.trans_id)
626          WHERE $where $dpt_where
627            AND ac.trans_id IN ( SELECT trans_id FROM acc_trans a WHERE (a.chart_link LIKE '%AP_paid%') $subwhere)
628            $project
629          GROUP BY c.$category
630
631          UNION
632
633          SELECT SUM(ac.amount * chart_category_to_sgn(c.category)) AS amount, c.$category
634          FROM acc_trans ac
635          JOIN chart c ON (c.id = ac.chart_id)
636          JOIN gl a ON (a.id = ac.trans_id)
637          WHERE $where $dpt_where $glwhere
638            AND NOT ((ac.chart_link = 'AR') OR (ac.chart_link = 'AP'))
639            $project
640          GROUP BY c.$category
641         |;
642
643     if ($form->{project_id}) {
644       $query .= qq|
645          UNION
646
647          SELECT SUM(ac.sellprice * ac.qty * chart_category_to_sgn(c.category)) AS amount, c.$category
648          FROM invoice ac
649          JOIN ar a ON (a.id = ac.trans_id)
650          JOIN parts p ON (ac.parts_id = p.id)
651          JOIN chart c on (p.income_accno_id = c.id)
652          WHERE (c.category = 'I') $prwhere $dpt_where
653            AND ac.trans_id IN ( SELECT trans_id FROM acc_trans a WHERE (a.chart_link LIKE '%AR_paid%') $subwhere)
654            $project
655          GROUP BY c.$category
656
657          UNION
658
659          SELECT SUM(ac.sellprice * chart_category_to_sgn(c.category)) AS amount, c.$category
660          FROM invoice ac
661          JOIN ap a ON (a.id = ac.trans_id)
662          JOIN parts p ON (ac.parts_id = p.id)
663          JOIN chart c on (p.expense_accno_id = c.id)
664          WHERE (c.category = 'E') $prwhere $dpt_where
665            AND ac.trans_id IN ( SELECT trans_id FROM acc_trans a WHERE (a.chart_link LIKE '%AP_paid%') $subwhere)
666          $project
667          GROUP BY c.$category
668          |;
669     }
670
671   } else {                      # if ($form->{method} eq 'cash')
672     if ($department_id) {
673       $dpt_where = qq| AND (a.department_id = | . conv_i($department_id, 'NULL') . qq|) |;
674       $dpt_where_without_arapgl = qq| AND COALESCE((SELECT department_id FROM ar WHERE ar.id=ac.trans_id),
675                                                    (SELECT department_id FROM gl WHERE gl.id=ac.trans_id),
676                                                    (SELECT department_id FROM ap WHERE ap.id=ac.trans_id)) = | . conv_i($department_id);
677     }
678
679     $query = qq|
680         SELECT sum(ac.amount * chart_category_to_sgn(c.category)) AS amount, c.$category
681         FROM acc_trans ac
682         JOIN chart c ON (c.id = ac.chart_id)
683         WHERE $where
684           $dpt_where_without_arapgl
685           $project
686         GROUP BY c.$category |;
687
688     if ($form->{project_id}) {
689       $query .= qq|
690         UNION
691
692         SELECT SUM(ac.sellprice * ac.qty * chart_category_to_sgn(c.category)) AS amount, c.$category
693         FROM invoice ac
694         JOIN ar a ON (a.id = ac.trans_id)
695         JOIN parts p ON (ac.parts_id = p.id)
696         JOIN chart c on (p.income_accno_id = c.id)
697         WHERE (c.category = 'I')
698           $prwhere
699           $dpt_where
700           $project
701         GROUP BY c.$category
702
703         UNION
704
705         SELECT SUM(ac.sellprice * ac.qty * chart_category_to_sgn(c.category)) AS amount, c.$category
706         FROM invoice ac
707         JOIN ap a ON (a.id = ac.trans_id)
708         JOIN parts p ON (ac.parts_id = p.id)
709         JOIN chart c on (p.expense_accno_id = c.id)
710         WHERE (c.category = 'E')
711           $prwhere
712           $dpt_where
713           $project
714         GROUP BY c.$category |;
715     }
716   }
717
718   my @accno;
719   my $accno;
720   my $ref;
721
722   foreach my $ref (selectall_hashref_query($form, $dbh, $query)) {
723     if ($category eq "pos_bwa") {
724       if ($last_period) {
725         $form->{ $ref->{$category} }{kumm} += $ref->{amount};
726       } else {
727         $form->{ $ref->{$category} }{jetzt} += $ref->{amount};
728       }
729     } else {
730       $form->{ $ref->{$category} } += $ref->{amount};
731     }
732   }
733
734   $main::lxdebug->leave_sub();
735 }
736
737 sub trial_balance {
738   $main::lxdebug->enter_sub();
739
740   my ($self, $myconfig, $form, %options) = @_;
741
742   my $dbh = $form->dbconnect($myconfig);
743
744   my ($query, $sth, $ref);
745   my %balance = ();
746   my %trb     = ();
747   my ($null, $department_id) = split /--/, $form->{department};
748   my @headingaccounts = ();
749   my $dpt_where;
750   my $dpt_where_without_arapgl;
751   my ($customer_where, $customer_join, $customer_no_union);
752   my $project;
753
754   my $where    = "1 = 1";
755   my $invwhere = $where;
756
757   if ($department_id) {
758     $dpt_where = qq| AND (a.department_id = | . conv_i($department_id, 'NULL') . qq|) |;
759     $dpt_where_without_arapgl = qq| AND COALESCE((SELECT department_id FROM ar WHERE ar.id=ac.trans_id),
760                                                  (SELECT department_id FROM gl WHERE gl.id=ac.trans_id),
761                                                  (SELECT department_id FROM ap WHERE ap.id=ac.trans_id)) = | . conv_i($department_id);
762   }
763   if ($form->{customer_id}) {
764     $customer_join     = qq| JOIN ar a ON (ac.trans_id = a.id) |;
765     $customer_where    = qq| AND (a.customer_id = | . conv_i($form->{customer_id}, 'NULL') . qq|) |;
766     $customer_no_union = qq| AND 1=0 |;
767   }
768
769   # project_id only applies to getting transactions
770   # it has nothing to do with a trial balance
771   # but we use the same function to collect information
772
773   if ($form->{project_id}) {
774     $project = qq| AND (ac.project_id = | . conv_i($form->{project_id}, 'NULL') . qq|) |;
775   }
776
777   my $acc_cash_where = "";
778 #  my $ar_cash_where = "";
779 #  my $ap_cash_where = "";
780
781
782   if ($form->{method} eq "cash") {
783     $acc_cash_where =
784       qq| AND (ac.trans_id IN (
785             SELECT id
786             FROM ar
787             WHERE datepaid >= '$form->{fromdate}'
788               AND datepaid <= '$form->{todate}'
789
790             UNION
791
792             SELECT id
793             FROM ap
794             WHERE datepaid >= '$form->{fromdate}'
795               AND datepaid <= '$form->{todate}'
796
797             UNION
798
799             SELECT id
800             FROM gl
801             WHERE transdate >= '$form->{fromdate}'
802               AND transdate <= '$form->{todate}'
803           )) |;
804 #    $ar_ap_cash_where = qq| AND (a.datepaid>='$form->{fromdate}' AND a.datepaid<='$form->{todate}') |;
805   }
806
807   if ($options{beginning_balances}) {
808     foreach my $prefix (qw(from to)) {
809       next if ($form->{"${prefix}date"});
810
811       my $min_max = $prefix eq 'from' ? 'min' : 'max';
812       $query      = qq|SELECT ${min_max}(transdate)
813                        FROM acc_trans ac
814                        $customer_join
815                        WHERE (1 = 1)
816                          $dpt_where_without_arapgl
817                          $dpt_where
818                          $customer_where
819                          $project|;
820       ($form->{"${prefix}date"}) = selectfirst_array_query($form, $dbh, $query);
821     }
822
823     # get beginning balances
824     $query =
825       qq|SELECT c.accno, c.category, SUM(ac.amount) AS amount, c.description
826           FROM acc_trans ac
827           LEFT JOIN chart c ON (ac.chart_id = c.id)
828           $customer_join
829           WHERE ((select date_trunc('year', ac.transdate::date)) = (select date_trunc('year', ?::date))) AND ac.ob_transaction
830             $dpt_where_without_arapgl
831             $dpt_where
832             $customer_where
833             $project
834           GROUP BY c.accno, c.category, c.description |;
835
836     $sth = prepare_execute_query($form, $dbh, $query, $form->{fromdate});
837
838     while (my $ref = $sth->fetchrow_hashref("NAME_lc")) {
839
840       if ($ref->{amount} != 0 || $form->{all_accounts}) {
841         $trb{ $ref->{accno} }{description} = $ref->{description};
842         $trb{ $ref->{accno} }{charttype}   = 'A';
843         $trb{ $ref->{accno} }{beginning_balance} = $ref->{amount};
844
845         if ($ref->{amount} > 0) {
846           $trb{ $ref->{accno} }{haben_eb}   = $ref->{amount};
847         } else {
848           $trb{ $ref->{accno} }{soll_eb}   = $ref->{amount} * -1;
849         }
850         $trb{ $ref->{accno} }{category}    = $ref->{category};
851       }
852
853     }
854     $sth->finish;
855   }
856
857   # get headings
858   $query =
859     qq|SELECT c.accno, c.description, c.category
860        FROM chart c
861        WHERE c.charttype = 'H'
862        ORDER by c.accno|;
863
864   $sth = prepare_execute_query($form, $dbh, $query);
865
866   while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
867     $trb{ $ref->{accno} }{description} = $ref->{description};
868     $trb{ $ref->{accno} }{charttype}   = 'H';
869     $trb{ $ref->{accno} }{category}    = $ref->{category};
870
871     push @headingaccounts, $ref->{accno};
872   }
873
874   $sth->finish;
875
876   $where = " 1 = 1 ";
877   my $saldowhere    = " 1 = 1 ";
878   my $sumwhere      = " 1 = 1 ";
879   my $subwhere      = '';
880   my $sumsubwhere   = '';
881   my $saldosubwhere = '';
882   my $glsaldowhere  = '';
883   my $glsubwhere    = '';
884   my $glwhere       = '';
885   my $glsumwhere    = '';
886   my $tofrom;
887   my ($fromdate, $todate);
888
889   if ($form->{fromdate} || $form->{todate}) {
890     if ($form->{fromdate}) {
891       $fromdate = conv_dateq($form->{fromdate});
892       $tofrom        .= " AND (ac.transdate >= $fromdate)";
893       $subwhere      .= " AND (ac.transdate >= $fromdate)";
894       $sumsubwhere   .= " AND (ac.transdate >= (select date_trunc('year', date $fromdate))) ";
895       $saldosubwhere .= " AND (ac,transdate>=(select date_trunc('year', date $fromdate)))  ";
896       $invwhere      .= " AND (a.transdate >= $fromdate)";
897       $glsaldowhere  .= " AND ac.transdate>=(select date_trunc('year', date $fromdate)) ";
898       $glwhere        = " AND (ac.transdate >= $fromdate)";
899       $glsumwhere     = " AND (ac.transdate >= (select date_trunc('year', date $fromdate))) ";
900     }
901     if ($form->{todate}) {
902       $todate = conv_dateq($form->{todate});
903       $tofrom        .= " AND (ac.transdate <= $todate)";
904       $invwhere      .= " AND (a.transdate <= $todate)";
905       $saldosubwhere .= " AND (ac.transdate <= $todate)";
906       $sumsubwhere   .= " AND (ac.transdate <= $todate)";
907       $subwhere      .= " AND (ac.transdate <= $todate)";
908       $glwhere       .= " AND (ac.transdate <= $todate)";
909       $glsumwhere    .= " AND (ac.transdate <= $todate) ";
910       $glsaldowhere  .= " AND (ac.transdate <= $todate) ";
911    }
912   }
913
914   if ($form->{method} eq "cash") {
915     $where .=
916       qq| AND(ac.trans_id IN (SELECT id FROM ar WHERE datepaid>= $fromdate AND datepaid<= $todate UNION SELECT id FROM ap WHERE datepaid>= $fromdate AND datepaid<= $todate UNION SELECT id FROM gl WHERE transdate>= $fromdate AND transdate<= $todate)) AND (NOT ac.ob_transaction OR ac.ob_transaction IS NULL) AND (NOT ac.cb_transaction OR ac.cb_transaction IS NULL) |;
917     $saldowhere .= qq| AND(ac.trans_id IN (SELECT id FROM ar WHERE datepaid>= $fromdate AND datepaid<= $todate UNION SELECT id FROM ap WHERE datepaid>= $fromdate AND datepaid<= $todate UNION SELECT id FROM gl WHERE transdate>= $fromdate AND transdate<= $todate))  AND (NOT ac.cb_transaction OR ac.cb_transaction IS NULL) |;
918
919     $sumwhere .= qq| AND(ac.trans_id IN (SELECT id FROM ar WHERE datepaid>= $fromdate AND datepaid<= $todate UNION SELECT id FROM ap WHERE datepaid>= $fromdate AND datepaid<= $todate UNION SELECT id FROM gl WHERE transdate>= $fromdate AND transdate<= $todate)) AND (NOT ac.ob_transaction OR ac.ob_transaction IS NULL) AND (NOT ac.cb_transaction OR ac.cb_transaction IS NULL) |;
920   } else {
921     $where .= $tofrom . " AND (NOT ac.ob_transaction OR ac.ob_transaction IS NULL) AND (NOT ac.cb_transaction OR ac.cb_transaction IS NULL)";
922     $saldowhere .= $glsaldowhere . " AND (NOT ac.cb_transaction OR ac.cb_transaction IS NULL)";
923     $sumwhere .= $glsumwhere . " AND (NOT ac.ob_transaction OR ac.ob_transaction IS NULL) AND (NOT ac.cb_transaction OR ac.cb_transaction IS NULL)";
924   }
925
926   $query = qq|
927        SELECT c.accno, c.description, c.category, SUM(ac.amount) AS amount
928        FROM acc_trans ac
929        JOIN chart c ON (c.id = ac.chart_id)
930        $customer_join
931        WHERE $where
932          $dpt_where_without_arapgl
933          $project
934        GROUP BY c.accno, c.description, c.category |;
935
936   if ($form->{project_id}) {
937     $query .= qq|
938       -- add project transactions from invoice
939
940       UNION ALL
941
942       SELECT c.accno, c.description, c.category, SUM(ac.sellprice * ac.qty) AS amount
943       FROM invoice ac
944       JOIN ar a ON (ac.trans_id = a.id)
945       JOIN parts p ON (ac.parts_id = p.id)
946       JOIN chart c ON (p.income_accno_id = c.id)
947       WHERE $invwhere
948         $dpt_where
949         $customer_where
950         $project
951       GROUP BY c.accno, c.description, c.category
952
953       UNION ALL
954
955       SELECT c.accno, c.description, c.category, SUM(ac.sellprice * ac.qty) * -1 AS amount
956       FROM invoice ac
957       JOIN ap a ON (ac.trans_id = a.id)
958       JOIN parts p ON (ac.parts_id = p.id)
959       JOIN chart c ON (p.expense_accno_id = c.id)
960       WHERE $invwhere
961         $dpt_where
962         $customer_no_union
963         $project
964       GROUP BY c.accno, c.description, c.category
965       |;
966     }
967
968   $query .= qq| ORDER BY accno|;
969
970   $sth = prepare_execute_query($form, $dbh, $query);
971
972   # calculate the debit and credit in the period
973   while ($ref = $sth->fetchrow_hashref("NAME_lc")) {
974     $trb{ $ref->{accno} }{description} = $ref->{description};
975     $trb{ $ref->{accno} }{charttype}   = 'A';
976     $trb{ $ref->{accno} }{category}    = $ref->{category};
977     $trb{ $ref->{accno} }{amount} += $ref->{amount};
978   }
979   $sth->finish;
980
981   # prepare query for each account
982   my ($q_drcr, $drcr, $q_project_drcr, $project_drcr);
983
984   $q_drcr =
985     qq|SELECT
986          (SELECT SUM(ac.amount) * -1
987           FROM acc_trans ac
988           JOIN chart c ON (c.id = ac.chart_id)
989           $customer_join
990           WHERE $where
991             $dpt_where_without_arapgl
992             $dpt_where
993             $customer_where
994             $project
995           AND (ac.amount < 0)
996           AND (c.accno = ?)) AS debit,
997
998          (SELECT SUM(ac.amount)
999           FROM acc_trans ac
1000           JOIN chart c ON (c.id = ac.chart_id)
1001           $customer_join
1002           WHERE $where
1003             $dpt_where_without_arapgl
1004             $dpt_where
1005             $customer_where
1006             $project
1007           AND ac.amount > 0
1008           AND c.accno = ?) AS credit,
1009         (SELECT SUM(ac.amount)
1010          FROM acc_trans ac
1011          JOIN chart c ON (ac.chart_id = c.id)
1012          $customer_join
1013          WHERE $saldowhere
1014            $dpt_where_without_arapgl
1015            $dpt_where
1016            $customer_where
1017            $project
1018          AND c.accno = ? AND (NOT ac.ob_transaction OR ac.ob_transaction IS NULL)) AS saldo,
1019
1020         (SELECT SUM(ac.amount)
1021          FROM acc_trans ac
1022          JOIN chart c ON (ac.chart_id = c.id)
1023          $customer_join
1024          WHERE $sumwhere
1025            $dpt_where_without_arapgl
1026            $dpt_where
1027            $customer_where
1028            $project
1029          AND ac.amount > 0
1030          AND c.accno = ?) AS sum_credit,
1031
1032         (SELECT SUM(ac.amount)
1033          FROM acc_trans ac
1034          JOIN chart c ON (ac.chart_id = c.id)
1035          $customer_join
1036          WHERE $sumwhere
1037            $dpt_where_without_arapgl
1038            $dpt_where
1039            $customer_where
1040            $project
1041          AND ac.amount < 0
1042          AND c.accno = ?) AS sum_debit,
1043
1044         (SELECT max(ac.transdate) FROM acc_trans ac
1045         JOIN chart c ON (ac.chart_id = c.id)
1046         $customer_join
1047         WHERE $where
1048           $dpt_where_without_arapgl
1049           $dpt_where
1050           $customer_where
1051           $project
1052         AND c.accno = ?) AS last_transaction
1053
1054
1055  |;
1056
1057   $drcr = prepare_query($form, $dbh, $q_drcr);
1058
1059   if ($form->{project_id}) {
1060     # prepare query for each account
1061     $q_project_drcr =
1062       qq|SELECT
1063           (SELECT SUM(ac.sellprice * ac.qty) * -1
1064            FROM invoice ac
1065            JOIN parts p ON (ac.parts_id = p.id)
1066            JOIN ap a ON (ac.trans_id = a.id)
1067            JOIN chart c ON (p.expense_accno_id = c.id)
1068            WHERE $invwhere
1069              $dpt_where
1070              $customer_no_union
1071              $project
1072            AND c.accno = ?) AS debit,
1073
1074           (SELECT SUM(ac.sellprice * ac.qty)
1075            FROM invoice ac
1076            JOIN parts p ON (ac.parts_id = p.id)
1077            JOIN ar a ON (ac.trans_id = a.id)
1078            JOIN chart c ON (p.income_accno_id = c.id)
1079            WHERE $invwhere
1080              $dpt_where
1081              $customer_where
1082              $project
1083            AND c.accno = ?) AS credit,
1084
1085         (SELECT SUM(ac.amount)
1086          FROM acc_trans ac
1087          JOIN chart c ON (ac.chart_id = c.id)
1088          $customer_join
1089          WHERE $saldowhere
1090            $dpt_where_without_arapgl
1091            $dpt_where
1092            $customer_where
1093            $project
1094          AND c.accno = ? AND (NOT ac.ob_transaction OR ac.ob_transaction IS NULL)) AS saldo,
1095
1096         (SELECT SUM(ac.amount)
1097          FROM acc_trans ac
1098          JOIN chart c ON (ac.chart_id = c.id)
1099          $customer_join
1100          WHERE $sumwhere
1101            $dpt_where_without_arapgl
1102            $dpt_where
1103            $customer_where
1104            $project
1105          AND ac.amount > 0
1106          AND c.accno = ?) AS sum_credit,
1107
1108         (SELECT SUM(ac.amount)
1109          FROM acc_trans ac
1110          JOIN chart c ON (ac.chart_id = c.id)
1111          $customer_join
1112          WHERE $sumwhere
1113            $dpt_where
1114            $dpt_where_without_arapgl
1115            $customer_where
1116            $project
1117          AND ac.amount < 0
1118          AND c.accno = ?) AS sum_debit,
1119
1120
1121         (SELECT max(ac.transdate) FROM acc_trans ac
1122         JOIN chart c ON (ac.chart_id = c.id)
1123         $customer_join
1124         WHERE $where
1125           $dpt_where_without_arapgl
1126           $dpt_where
1127           $customer_where
1128           $project
1129         AND c.accno = ?) AS last_transaction
1130  |;
1131
1132     $project_drcr = prepare_query($form, $dbh, $q_project_drcr);
1133   }
1134
1135
1136   my ($debit, $credit, $saldo, $soll_saldo, $haben_saldo,$soll_kummuliert, $haben_kummuliert, $last_transaction);
1137
1138   foreach my $accno (sort keys %trb) {
1139     $ref = {};
1140
1141     $ref->{accno} = $accno;
1142     map { $ref->{$_} = $trb{$accno}{$_} }
1143       qw(description category charttype amount soll_eb haben_eb beginning_balance);
1144
1145     $ref->{balance} = $form->round_amount($balance{ $ref->{accno} }, 2);
1146
1147     if ($trb{$accno}{charttype} eq 'A') {
1148
1149       # get DR/CR
1150       do_statement($form, $drcr, $q_drcr, $ref->{accno}, $ref->{accno}, $ref->{accno}, $ref->{accno}, $ref->{accno}, $ref->{accno});
1151
1152       ($debit, $credit, $saldo, $haben_saldo, $soll_saldo) = (0, 0, 0, 0, 0);
1153       my ($soll_kumuliert, $haben_kumuliert) = (0, 0);
1154       $last_transaction = "";
1155       while (($debit, $credit, $saldo, $haben_kumuliert, $soll_kumuliert, $last_transaction) = $drcr->fetchrow_array) {
1156         $ref->{debit}  += $debit;
1157         $ref->{credit} += $credit;
1158         if ($saldo >= 0) {
1159           $ref->{haben_saldo} += $saldo;
1160         } else {
1161           $ref->{soll_saldo} += $saldo * -1;
1162         }
1163         $ref->{last_transaction} = $last_transaction;
1164         $ref->{soll_kumuliert} = $soll_kumuliert * -1;
1165         $ref->{haben_kumuliert} = $haben_kumuliert;
1166       }
1167       $drcr->finish;
1168
1169       if ($form->{project_id}) {
1170
1171         # get DR/CR
1172         do_statement($form, $project_drcr, $q_project_drcr, $ref->{accno}, $ref->{accno}, $ref->{accno}, $ref->{accno}, $ref->{accno}, $ref->{accno});
1173
1174         ($debit, $credit) = (0, 0);
1175         while (($debit, $credit, $saldo, $haben_kumuliert, $soll_kumuliert, $last_transaction) = $project_drcr->fetchrow_array) {
1176           $ref->{debit}  += $debit;
1177           $ref->{credit} += $credit;
1178           if ($saldo >= 0) {
1179             $ref->{haben_saldo} += $saldo;
1180           } else {
1181             $ref->{soll_saldo} += $saldo * -1;
1182           }
1183           $ref->{soll_kumuliert} += $soll_kumuliert * -1;
1184           $ref->{haben_kumuliert} += $haben_kumuliert;
1185         }
1186         $project_drcr->finish;
1187       }
1188
1189       $ref->{debit}  = $form->round_amount($ref->{debit},  2);
1190       $ref->{credit} = $form->round_amount($ref->{credit}, 2);
1191
1192       if ($ref->{haben_saldo} != 0) {
1193         $ref->{haben_saldo}  = $ref->{haben_saldo} + $ref->{beginning_balance};
1194         if ($ref->{haben_saldo} < 0) {
1195           $ref->{soll_saldo} = $form->round_amount(($ref->{haben_saldo} *- 1), 2);
1196           $ref->{haben_saldo} = 0;
1197         }
1198       } else {
1199         $ref->{soll_saldo} = $ref->{soll_saldo} - $ref->{beginning_balance};
1200         if ($ref->{soll_saldo} < 0) {
1201           $ref->{haben_saldo} = $form->round_amount(($ref->{soll_saldo} * -1), 2);
1202           $ref->{soll_saldo} = 0;
1203         }
1204      }
1205       $ref->{haben_saldo} = $form->round_amount($ref->{haben_saldo}, 2);
1206       $ref->{soll_saldo} = $form->round_amount($ref->{soll_saldo}, 2);
1207       $ref->{haben_kumuliert}  = $form->round_amount($ref->{haben_kumuliert},  2);
1208       $ref->{soll_kumuliert} = $form->round_amount($ref->{soll_kumuliert}, 2);
1209     }
1210
1211     # add subtotal
1212     my @accno;
1213     @accno = grep { $_ le "$ref->{accno}" } @headingaccounts;
1214     $accno = pop @accno;
1215     if ($accno) {
1216       $trb{$accno}{debit}  += $ref->{debit};
1217       $trb{$accno}{credit} += $ref->{credit};
1218       $trb{$accno}{soll_saldo}  += $ref->{soll_saldo};
1219       $trb{$accno}{haben_saldo} += $ref->{haben_saldo};
1220       $trb{$accno}{soll_kumuliert}  += $ref->{soll_kumuliert};
1221       $trb{$accno}{haben_kumuliert} += $ref->{haben_kumuliert};
1222     }
1223
1224     push @{ $form->{TB} }, $ref;
1225
1226   }
1227
1228   $dbh->disconnect;
1229
1230   # debits and credits for headings
1231   foreach my $accno (@headingaccounts) {
1232     foreach $ref (@{ $form->{TB} }) {
1233       if ($accno eq $ref->{accno}) {
1234         $ref->{debit}           = $trb{$accno}{debit};
1235         $ref->{credit}          = $trb{$accno}{credit};
1236         $ref->{soll_saldo}      = $trb{$accno}{soll_saldo};
1237         $ref->{haben_saldo}     = $trb{$accno}{haben_saldo};
1238         $ref->{soll_kumuliert}  = $trb{$accno}{soll_kumuliert};
1239         $ref->{haben_kumuliert} = $trb{$accno}{haben_kumuliert};
1240       }
1241     }
1242   }
1243
1244   $main::lxdebug->leave_sub();
1245 }
1246
1247 sub get_storno {
1248   $main::lxdebug->enter_sub();
1249   my ($self, $dbh, $form) = @_;
1250   my $arap = $form->{arap} eq "ar" ? "ar" : "ap";
1251   my $query = qq|SELECT invnumber FROM $arap WHERE invnumber LIKE "Storno zu "|;
1252   my $sth =  $dbh->prepare($query);
1253   while(my $ref = $sth->fetchrow_hashref()) {
1254     $ref->{invnumer} =~ s/Storno zu //g;
1255     $form->{storno}{$ref->{invnumber}} = 1;
1256   }
1257   $main::lxdebug->leave_sub();
1258 }
1259
1260 sub aging {
1261   $main::lxdebug->enter_sub();
1262
1263   my ($self, $myconfig, $form) = @_;
1264
1265   # connect to database
1266   my $dbh     = $form->dbconnect($myconfig);
1267
1268   my ($invoice, $arap, $buysell, $ct, $ct_id, $ml);
1269
1270   # falls customer ziehen wir die offene forderungsliste
1271   # anderfalls für die lieferanten die offenen verbindlichkeitne
1272   if ($form->{ct} eq "customer") {
1273     $invoice = "is";
1274     $arap = "ar";
1275     $buysell = "buy";
1276     $ct = "customer";
1277     $ml = -1;
1278   } else {
1279     $invoice = "ir";
1280     $arap = "ap";
1281     $buysell = "sell";
1282     $ct = "vendor";
1283     $ml = 1;
1284   }
1285   $ct_id = "${ct}_id";
1286
1287   # erweiterung um einen freien zeitraum oder einen stichtag
1288   # mit entsprechender altersstrukturliste (s.a. Bug 1842)
1289   # eine neue variable an der oberfläche eingeführt, somit ist
1290   # todate == freier zeitrau und fordate == stichtag
1291   # duedate_where == nur fällige rechnungen anzeigen
1292
1293   my ($review_of_aging_list, $todate, $fromdate, $fromwhere, $fordate,
1294       $duedate_where);
1295
1296   if ($form->{reporttype} eq 'custom') {  # altersstrukturliste, nur fällige
1297
1298     # explizit rausschmeissen was man für diesen bericht nicht braucht
1299     delete $form->{fromdate};
1300     delete $form->{todate};
1301
1302     # an der oberfläche ist das tagesaktuelle datum vorausgewählt
1303     # falls es dennoch per Benutzereingabe gelöscht wird, lieber wieder vorbelegen
1304     # ferner muss für die spätere DB-Abfrage muss todate gesetzt sein.
1305     $form->{fordate}  = $form->current_date($myconfig) unless ($form->{fordate});
1306     $fordate          = conv_dateq($form->{fordate});
1307     $todate           = $fordate;
1308
1309     if ($form->{review_of_aging_list}) { # falls die liste leer ist, alles anzeigen
1310       if ($form->{review_of_aging_list} =~ m "-") {             # ..  periode von bis
1311         my @period = split(/-/, $form->{review_of_aging_list}); # ... von periode bis periode
1312         $review_of_aging_list = " AND $period[0] <  (date $fordate) - duedate
1313                                   AND (date $fordate) - duedate  < $period[1]";
1314       } else {
1315         $form->{review_of_aging_list} =~ s/[^0-9]//g;   # größer 120 das substitute ist nur für das '>' zeichen
1316         $review_of_aging_list = " AND $form->{review_of_aging_list} < (date $fordate) - duedate";
1317       }
1318     }
1319     $duedate_where = " AND (date $fordate) - duedate >= 0 ";
1320   } else {  # freier zeitraum, nur rechnungsdatum und OHNE review_of_aging_list
1321     $form->{todate}  = $form->current_date($myconfig) unless ($form->{todate});
1322     $todate = conv_dateq($form->{todate});
1323     $fromdate = conv_dateq($form->{fromdate});
1324     $fromwhere = ($form->{fromdate} ne "") ? " AND (transdate >= (date $fromdate)) " : "";
1325   }
1326   my $where = " 1 = 1 ";
1327   my ($name, $null);
1328
1329   if ($form->{$ct_id}) {
1330     $where .= qq| AND (ct.id = | . conv_i($form->{$ct_id}) . qq|)|;
1331   } elsif ($form->{ $form->{ct} }) {
1332     $where .= qq| AND (ct.name ILIKE | . $dbh->quote('%' . $form->{$ct} . '%') . qq|)|;
1333   }
1334
1335   my $dpt_join;
1336   my $where_dpt;
1337   if ($form->{department}) {
1338     my ($null, $department_id) = split /--/, $form->{department};
1339     $dpt_join = qq| JOIN department d ON (a.department_id = d.id) |;
1340     $where .= qq| AND (a.department_id = | . conv_i($department_id, 'NULL') . qq|)|;
1341     $where_dpt = qq| AND (${arap}.department_id = | . conv_i($department_id, 'NULL') . qq|)|;
1342   }
1343  my $q_details = qq|
1344
1345     SELECT ${ct}.id AS ctid, ${ct}.name,
1346       street, zipcode, city, country, contact, email,
1347       phone as customerphone, fax as customerfax, ${ct}number,
1348       "invnumber", "transdate",
1349       (amount - COALESCE((SELECT sum(amount)*$ml FROM acc_trans WHERE chart_link ilike '%paid%' AND acc_trans.trans_id=${arap}.id AND acc_trans.transdate <= (date $todate)),0)) as "open", "amount",
1350       "duedate", invoice, ${arap}.id, date_part('days', now() - duedate) as overduedays,
1351       (SELECT $buysell
1352        FROM exchangerate
1353        WHERE (${arap}.currency_id = exchangerate.currency_id)
1354          AND (exchangerate.transdate = ${arap}.transdate)) AS exchangerate
1355     FROM ${arap}, ${ct}
1356     WHERE ((paid != amount) OR (datepaid > (date $todate) AND datepaid is not null))
1357       AND NOT COALESCE (${arap}.storno, 'f')
1358       AND (${arap}.${ct}_id = ${ct}.id)
1359       $where_dpt
1360       AND (${ct}.id = ?)
1361       AND (transdate <= (date $todate) $fromwhere )
1362       $review_of_aging_list
1363       $duedate_where
1364     ORDER BY ctid, transdate, invnumber |;
1365
1366   my $sth_details = prepare_query($form, $dbh, $q_details);
1367
1368   # select outstanding vendors or customers, depends on $ct
1369   my $query =
1370     qq|SELECT DISTINCT ct.id, ct.name
1371        FROM $ct ct, $arap a
1372        $dpt_join
1373        WHERE $where
1374          AND (a.${ct_id} = ct.id)
1375          AND ((a.paid != a.amount) OR ((a.datepaid > $todate) AND (datepaid is NOT NULL)))
1376          AND (a.transdate <= $todate $fromwhere)
1377        ORDER BY ct.name|;
1378
1379   my $sth = prepare_execute_query($form, $dbh, $query);
1380
1381   $form->{AG} = [];
1382   # for each company that has some stuff outstanding
1383   while (my ($id) = $sth->fetchrow_array) {
1384     do_statement($form, $sth_details, $q_details, $id);
1385
1386     while (my $ref = $sth_details->fetchrow_hashref("NAME_lc")) {
1387       $ref->{module} = ($ref->{invoice}) ? $invoice : $arap;
1388       $ref->{exchangerate} = 1 unless $ref->{exchangerate};
1389       push @{ $form->{AG} }, $ref;
1390     }
1391
1392     $sth_details->finish;
1393
1394   }
1395
1396   $sth->finish;
1397
1398   # disconnect
1399   $dbh->disconnect;
1400
1401   $main::lxdebug->leave_sub();
1402 }
1403
1404 sub get_customer {
1405   $main::lxdebug->enter_sub();
1406
1407   my ($self, $myconfig, $form) = @_;
1408
1409   # connect to database
1410   my $dbh = $form->dbconnect($myconfig);
1411
1412   my $ct = $form->{ct} eq "customer" ? "customer" : "vendor";
1413
1414   my $query =
1415     qq|SELECT ct.name, ct.email, ct.cc, ct.bcc
1416        FROM $ct ct
1417        WHERE ct.id = ?|;
1418   ($form->{ $form->{ct} }, $form->{email}, $form->{cc}, $form->{bcc}) =
1419     selectrow_query($form, $dbh, $query, $form->{"${ct}_id"});
1420   $dbh->disconnect;
1421
1422   $main::lxdebug->leave_sub();
1423 }
1424
1425 sub tax_report {
1426   $main::lxdebug->enter_sub();
1427
1428   my ($self, $myconfig, $form) = @_;
1429
1430   # connect to database
1431   my $dbh = $form->dbconnect($myconfig);
1432
1433   my ($null, $department_id) = split /--/, $form->{department};
1434
1435   # build WHERE
1436   my $where = "1 = 1";
1437
1438   if ($department_id) {
1439     $where .= qq| AND (a.department_id = | . conv_i($department_id, 'NULL') . qq|) |;
1440   }
1441
1442   my ($accno, $rate);
1443
1444   if ($form->{accno}) {
1445     $accno = $form->{accno};
1446     $rate  = $form->{"$form->{accno}_rate"};
1447     $accno = qq| AND (ch.accno = | . $dbh->quote($accno) . qq|)|;
1448   }
1449   $rate *= 1;
1450
1451   my ($table, $ARAP);
1452
1453   if ($form->{db} eq 'ar') {
1454     $table = "customer";
1455     $ARAP  = "AR";
1456   } else {
1457     $table = "vendor";
1458     $ARAP  = "AP";
1459   }
1460
1461   my $arap = lc($ARAP);
1462
1463   my $transdate = "a.transdate";
1464
1465   if ($form->{method} eq 'cash') {
1466     $transdate = "a.datepaid";
1467
1468     my $todate = conv_dateq($form->{todate} ? $form->{todate} : $form->current_date($myconfig));
1469
1470     $where .= qq|
1471       AND ac.trans_id IN
1472         (
1473           SELECT trans_id
1474           FROM acc_trans a
1475           WHERE (a.chart_link LIKE '%${ARAP}_paid%')
1476           AND (transdate <= $todate)
1477         )
1478       |;
1479   }
1480
1481   # if there are any dates construct a where
1482   $where .= " AND ($transdate >= " . conv_dateq($form->{fromdate}) . ") " if ($form->{fromdate});
1483   $where .= " AND ($transdate <= " . conv_dateq($form->{todate}) . ") " if ($form->{todate});
1484
1485   my $ml = ($form->{db} eq 'ar') ? 1 : -1;
1486
1487   my $sortorder = join ', ', $form->sort_columns(qw(transdate invnumber name));
1488   $sortorder = $form->{sort} if ($form->{sort} && grep({ $_ eq $form->{sort} } qw(id transdate invnumber name netamount tax)));
1489
1490   my $query =
1491       qq|SELECT a.id, '0' AS invoice, $transdate AS transdate, a.invnumber, n.name, a.netamount,
1492           ac.amount * $ml AS tax
1493          FROM acc_trans ac
1494          JOIN ${arap} a ON (a.id = ac.trans_id)
1495          JOIN chart ch ON (ch.id = ac.chart_id)
1496          JOIN $table n ON (n.id = a.${table}_id)
1497          WHERE
1498            $where
1499            $accno
1500            AND (a.invoice = '0')
1501
1502          UNION
1503
1504          SELECT a.id, '1' AS invoice, $transdate AS transdate, a.invnumber, n.name, i.sellprice * i.qty AS netamount,
1505            i.sellprice * i.qty * $rate * $ml AS tax
1506          FROM acc_trans ac
1507          JOIN ${arap} a ON (a.id = ac.trans_id)
1508          JOIN chart ch ON (ch.id = ac.chart_id)
1509          JOIN $table n ON (n.id = a.${table}_id)
1510          JOIN ${table}tax t ON (t.${table}_id = n.id)
1511          JOIN invoice i ON (i.trans_id = a.id)
1512          WHERE
1513            $where
1514            $accno
1515            AND (a.invoice = '1')
1516          ORDER BY $sortorder|;
1517
1518   $form->{TR} = selectall_hashref_query($form, $dbh, $query);
1519
1520   $dbh->disconnect;
1521
1522   $main::lxdebug->leave_sub();
1523 }
1524
1525 sub paymentaccounts {
1526   $main::lxdebug->enter_sub();
1527
1528   my ($self, $myconfig, $form) = @_;
1529
1530   # connect to database, turn AutoCommit off
1531   my $dbh = $form->dbconnect_noauto($myconfig);
1532
1533   my $ARAP = $form->{db} eq "ar" ? "AR" : "AP";
1534
1535   # get A(R|P)_paid accounts
1536   my $query =
1537     qq|SELECT accno, description
1538        FROM chart
1539        WHERE link LIKE '%${ARAP}_paid%'|;
1540   $form->{PR} = selectall_hashref_query($form, $dbh, $query);
1541
1542   $dbh->disconnect;
1543
1544   $main::lxdebug->leave_sub();
1545 }
1546
1547 sub payments {
1548   $main::lxdebug->enter_sub();
1549
1550   my ($self, $myconfig, $form) = @_;
1551
1552   # connect to database, turn AutoCommit off
1553   my $dbh = $form->dbconnect_noauto($myconfig);
1554
1555   my $ml = 1;
1556   my $arap;
1557   my $table;
1558   if ($form->{db} eq 'ar') {
1559     $table = 'customer';
1560     $ml = -1;
1561     $arap = 'ar';
1562   } else {
1563     $table = 'vendor';
1564     $arap = 'ap';
1565   }
1566
1567   my ($query, $sth);
1568   my $where;
1569
1570   if ($form->{department_id}) {
1571     $where = qq| AND (a.department_id = | . conv_i($form->{department_id}, 'NULL') . qq|) |;
1572   }
1573
1574   if ($form->{fromdate}) {
1575     $where .= " AND (ac.transdate >= " . $dbh->quote($form->{fromdate}) . ") ";
1576   }
1577   if ($form->{todate}) {
1578     $where .= " AND (ac.transdate <= " . $dbh->quote($form->{todate}) . ") ";
1579   }
1580   if (!$form->{fx_transaction}) {
1581     $where .= " AND ac.fx_transaction = '0'";
1582   }
1583
1584   my $invnumber;
1585   my $reference;
1586   if ($form->{reference}) {
1587     $reference = $dbh->quote('%' . $form->{reference} . '%');
1588     $invnumber = " AND (a.invnumber LIKE $reference)";
1589     $reference = " AND (a.reference LIKE $reference)";
1590   }
1591   if ($form->{source}) {
1592     $where .= " AND (ac.source ILIKE " . $dbh->quote('%' . $form->{source} . '%') . ") ";
1593   }
1594   if ($form->{memo}) {
1595     $where .= " AND (ac.memo ILIKE " . $dbh->quote('%' . $form->{memo} . '%') . ") ";
1596   }
1597
1598   my %sort_columns =  (
1599     'transdate'    => [ qw(transdate lower_invnumber lower_name) ],
1600     'invnumber'    => [ qw(lower_invnumber lower_name transdate) ],
1601     'name'         => [ qw(lower_name transdate)                 ],
1602     'source'       => [ qw(lower_source)                         ],
1603     'memo'         => [ qw(lower_memo)                           ],
1604     );
1605   my %lowered_columns =  (
1606     'invnumber'       => { 'gl' => 'a.reference',   'arap' => 'a.invnumber', },
1607     'memo'            => { 'gl' => 'ac.memo',       'arap' => 'ac.memo',     },
1608     'source'          => { 'gl' => 'ac.source',     'arap' => 'ac.source',   },
1609     'name'            => { 'gl' => 'a.description', 'arap' => 'c.name',      },
1610     );
1611
1612   my $sortdir   = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
1613   my $sortkey   = $sort_columns{$form->{sort}} ? $form->{sort} : 'transdate';
1614   my $sortorder = join ', ', map { "$_ $sortdir" } @{ $sort_columns{$sortkey} };
1615
1616
1617   my %columns_for_sorting = ( 'gl' => '', 'arap' => '', );
1618   foreach my $spec (@{ $sort_columns{$sortkey} }) {
1619     next if ($spec !~ m/^lower_(.*)$/);
1620
1621     my $column = $1;
1622     map { $columns_for_sorting{$_} .= sprintf(', lower(%s) AS lower_%s', $lowered_columns{$column}->{$_}, $column) } qw(gl arap);
1623   }
1624
1625   $query = qq|SELECT id, accno, description FROM chart WHERE accno = ?|;
1626   $sth = prepare_query($form, $dbh, $query);
1627
1628   my $q_details =
1629       qq|SELECT c.name, a.invnumber, a.ordnumber,
1630            ac.transdate, ac.amount * $ml AS paid, ac.source,
1631            a.invoice, a.id, ac.memo, '${arap}' AS module
1632            $columns_for_sorting{arap}
1633          FROM acc_trans ac
1634          JOIN $arap a ON (ac.trans_id = a.id)
1635          JOIN $table c ON (c.id = a.${table}_id)
1636          WHERE (ac.chart_id = ?)
1637            $where
1638            $invnumber
1639
1640          UNION
1641
1642          SELECT a.description, a.reference, NULL AS ordnumber,
1643            ac.transdate, ac.amount * $ml AS paid, ac.source,
1644            '0' as invoice, a.id, ac.memo, 'gl' AS module
1645            $columns_for_sorting{gl}
1646          FROM acc_trans ac
1647          JOIN gl a ON (a.id = ac.trans_id)
1648          WHERE (ac.chart_id = ?)
1649            $where
1650            $reference
1651            AND (ac.amount * $ml) > 0
1652
1653          ORDER BY $sortorder|;
1654   my $sth_details = prepare_query($form, $dbh, $q_details);
1655
1656   $form->{PR} = [];
1657
1658   # cycle through each id
1659   foreach my $accno (split(/ /, $form->{paymentaccounts})) {
1660     do_statement($form, $sth, $query, $accno);
1661     my $ref = $sth->fetchrow_hashref();
1662     push(@{ $form->{PR} }, $ref);
1663     $sth->finish();
1664
1665     $form->{ $ref->{id} } = [] unless ($form->{ $ref->{id} });
1666
1667     do_statement($form, $sth_details, $q_details, $ref->{id}, $ref->{id});
1668     while (my $pr = $sth_details->fetchrow_hashref()) {
1669       push(@{ $form->{ $ref->{id} } }, $pr);
1670     }
1671     $sth_details->finish();
1672   }
1673
1674   $dbh->disconnect;
1675
1676   $main::lxdebug->leave_sub();
1677 }
1678
1679 sub bwa {
1680   $main::lxdebug->enter_sub();
1681
1682   my ($self, $myconfig, $form) = @_;
1683
1684   # connect to database
1685   my $dbh = $form->dbconnect($myconfig);
1686
1687   my $last_period = 0;
1688   my $category;
1689   my @categories  =
1690     qw(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40);
1691
1692   $form->{decimalplaces} *= 1;
1693
1694   &get_accounts_g($dbh, $last_period, $form->{fromdate}, $form->{todate}, $form, "pos_bwa");
1695
1696   # if there are any compare dates
1697   my $year;
1698   if ($form->{fromdate} || $form->{todate}) {
1699     $last_period = 1;
1700     if ($form->{fromdate}) {
1701       $form->{fromdate} =~ /[0-9]*\.[0-9]*\.([0-9]*)/;
1702       $year = $1;
1703     } else {
1704       $form->{todate} =~ /[0-9]*\.[0-9]*\.([0-9]*)/;
1705       $year = $1;
1706     }
1707     my $kummfromdate = $form->{comparefromdate};
1708     my $kummtodate   = $form->{comparetodate};
1709     &get_accounts_g($dbh, $last_period, $kummfromdate, $kummtodate, $form, "pos_bwa");
1710   }
1711
1712   my @periods        = qw(jetzt kumm);
1713   my @gesamtleistung = qw(1 3);
1714   my @gesamtkosten   = qw (10 11 12 13 14 15 16 17 18 20);
1715   my @ergebnisse     =
1716     qw (rohertrag betriebrohertrag betriebsergebnis neutraleraufwand neutralerertrag ergebnisvorsteuern ergebnis gesamtleistung gesamtkosten);
1717
1718   foreach my $key (@periods) {
1719     $form->{ "$key" . "gesamtleistung" } = 0;
1720     $form->{ "$key" . "gesamtkosten" }   = 0;
1721
1722     foreach $category (@categories) {
1723
1724       if (defined($form->{$category}{$key})) {
1725         $form->{"$key$category"} =
1726           $form->format_amount($myconfig,
1727                                $form->round_amount($form->{$category}{$key}, 2
1728                                ),
1729                                $form->{decimalplaces},
1730                                '0');
1731       }
1732     }
1733     foreach my $item (@gesamtleistung) {
1734       $form->{ "$key" . "gesamtleistung" } += $form->{$item}{$key};
1735     }
1736     $form->{ "$key" . "gesamtleistung" } -= $form->{2}{$key};
1737
1738     foreach my $item (@gesamtkosten) {
1739       $form->{ "$key" . "gesamtkosten" } += $form->{$item}{$key};
1740     }
1741     $form->{ "$key" . "rohertrag" } =
1742       $form->{ "$key" . "gesamtleistung" } - $form->{4}{$key};
1743     $form->{ "$key" . "betriebrohertrag" } =
1744       $form->{ "$key" . "rohertrag" } + $form->{5}{$key};
1745     $form->{ "$key" . "betriebsergebnis" } =
1746       $form->{ "$key" . "betriebrohertrag" } -
1747       $form->{ "$key" . "gesamtkosten" };
1748     $form->{ "$key" . "neutraleraufwand" } =
1749       $form->{19}{$key} + $form->{30}{$key} + $form->{31}{$key};
1750     $form->{ "$key" . "neutralerertrag" } =
1751       $form->{32}{$key} + $form->{33}{$key} + $form->{34}{$key};
1752     $form->{ "$key" . "ergebnisvorsteuern" } =
1753       $form->{ "$key" . "betriebsergebnis" } -
1754       $form->{ "$key" . "neutraleraufwand" } +
1755       $form->{ "$key" . "neutralerertrag" };
1756     $form->{ "$key" . "ergebnis" } =
1757       $form->{ "$key" . "ergebnisvorsteuern" } - $form->{35}{$key};
1758
1759     if ($form->{ "$key" . "gesamtleistung" } > 0) {
1760       foreach $category (@categories) {
1761         if (defined($form->{$category}{$key})) {
1762           $form->{ "$key" . "gl" . "$category" } =
1763             $form->format_amount(
1764                                $myconfig,
1765                                $form->round_amount(
1766                                  ($form->{$category}{$key} /
1767                                     $form->{ "$key" . "gesamtleistung" } * 100
1768                                  ),
1769                                  $form->{decimalplaces}
1770                                ),
1771                                $form->{decimalplaces},
1772                                '0');
1773         }
1774       }
1775       foreach my $item (@ergebnisse) {
1776         $form->{ "$key" . "gl" . "$item" } =
1777           $form->format_amount($myconfig,
1778                                $form->round_amount(
1779                                  ( $form->{ "$key" . "$item" } /
1780                                      $form->{ "$key" . "gesamtleistung" } * 100
1781                                  ),
1782                                  $form->{decimalplaces}
1783                                ),
1784                                $form->{decimalplaces},
1785                                '0');
1786       }
1787     }
1788
1789     if ($form->{ "$key" . "gesamtkosten" } > 0) {
1790       foreach $category (@categories) {
1791         if (defined($form->{$category}{$key})) {
1792           $form->{ "$key" . "gk" . "$category" } =
1793             $form->format_amount($myconfig,
1794                                  $form->round_amount(
1795                                    ($form->{$category}{$key} /
1796                                       $form->{ "$key" . "gesamtkosten" } * 100
1797                                    ),
1798                                    $form->{decimalplaces}
1799                                  ),
1800                                  $form->{decimalplaces},
1801                                  '0');
1802         }
1803       }
1804       foreach my $item (@ergebnisse) {
1805         $form->{ "$key" . "gk" . "$item" } =
1806           $form->format_amount($myconfig,
1807                                $form->round_amount(
1808                                    ($form->{ "$key" . "$item" } /
1809                                       $form->{ "$key" . "gesamtkosten" } * 100
1810                                    ),
1811                                    $form->{decimalplaces}
1812                                ),
1813                                $form->{decimalplaces},
1814                                '0');
1815       }
1816     }
1817
1818     if ($form->{10}{$key} > 0) {
1819       foreach $category (@categories) {
1820         if (defined($form->{$category}{$key})) {
1821           $form->{ "$key" . "pk" . "$category" } =
1822             $form->format_amount(
1823                         $myconfig,
1824                         $form->round_amount(
1825                           ($form->{$category}{$key} / $form->{10}{$key} * 100),
1826                           $form->{decimalplaces}
1827                         ),
1828                         $form->{decimalplaces},
1829                         '0');
1830         }
1831       }
1832       foreach my $item (@ergebnisse) {
1833         $form->{ "$key" . "pk" . "$item" } =
1834           $form->format_amount($myconfig,
1835                                $form->round_amount(
1836                                                 ($form->{ "$key" . "$item" } /
1837                                                    $form->{10}{$key} * 100
1838                                                 ),
1839                                                 $form->{decimalplaces}
1840                                ),
1841                                $form->{decimalplaces},
1842                                '0');
1843       }
1844     }
1845
1846     if ($form->{4}{$key} > 0) {
1847       foreach $category (@categories) {
1848         if (defined($form->{$category}{$key})) {
1849           $form->{ "$key" . "auf" . "$category" } =
1850             $form->format_amount(
1851                          $myconfig,
1852                          $form->round_amount(
1853                            ($form->{$category}{$key} / $form->{4}{$key} * 100),
1854                            $form->{decimalplaces}
1855                          ),
1856                          $form->{decimalplaces},
1857                          '0');
1858         }
1859       }
1860       foreach my $item (@ergebnisse) {
1861         $form->{ "$key" . "auf" . "$item" } =
1862           $form->format_amount($myconfig,
1863                                $form->round_amount(
1864                                                 ($form->{ "$key" . "$item" } /
1865                                                    $form->{4}{$key} * 100
1866                                                 ),
1867                                                 $form->{decimalplaces}
1868                                ),
1869                                $form->{decimalplaces},
1870                                '0');
1871       }
1872     }
1873
1874     foreach my $item (@ergebnisse) {
1875       $form->{ "$key" . "$item" } =
1876         $form->format_amount($myconfig,
1877                              $form->round_amount($form->{ "$key" . "$item" },
1878                                                  $form->{decimalplaces}
1879                              ),
1880                              $form->{decimalplaces},
1881                              '0');
1882     }
1883
1884   }
1885   $dbh->disconnect;
1886
1887   $main::lxdebug->leave_sub();
1888 }
1889
1890 sub income_statement {
1891   $main::lxdebug->enter_sub();
1892
1893   my ($self, $myconfig, $form) = @_;
1894
1895   # connect to database
1896   my $dbh = $form->dbconnect($myconfig);
1897
1898   my $last_period          = 0;
1899   my @categories_einnahmen = qw(1 2 3 4 5 6 7);
1900   my @categories_ausgaben  =
1901     qw(8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31);
1902
1903   my @ergebnisse = qw(sumeura sumeurb guvsumme);
1904
1905   $form->{decimalplaces} *= 1;
1906
1907
1908
1909   &get_accounts_g($dbh, $last_period, $form->{fromdate}, $form->{todate},
1910                   $form, "pos_eur");
1911
1912
1913   foreach my $item (@categories_einnahmen) {
1914     $form->{"eur${item}"} =
1915       $form->format_amount($myconfig, $form->round_amount($form->{$item}, 2),2);
1916     $form->{"sumeura"} += $form->{$item};
1917   }
1918   foreach my $item (@categories_ausgaben) {
1919     $form->{"eur${item}"} =
1920       $form->format_amount($myconfig, $form->round_amount($form->{$item}, 2),2);
1921     $form->{"sumeurb"} += $form->{$item};
1922   }
1923
1924   $form->{"guvsumme"} = $form->{"sumeura"} - $form->{"sumeurb"};
1925
1926   foreach my $item (@ergebnisse) {
1927     $form->{$item} =
1928       $form->format_amount($myconfig, $form->round_amount($form->{$item}, 2),2);
1929   }
1930   $main::lxdebug->leave_sub();
1931 }
1932 1;