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