can't set $p without $cgi
[freeside.git] / sql-ledger / old / sql-ledger / SL / RP.pm
1 #=====================================================================
2 # SQL-Ledger Accounting
3 # Copyright (C) 1998-2002
4 #
5 #  Author: Dieter Simader
6 #   Email: dsimader@sql-ledger.org
7 #     Web: http://www.sql-ledger.org
8 #
9 #  Contributors: Benjamin Lee <benjaminlee@consultant.com>
10 #
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #======================================================================
24 #
25 # backend code for reports
26 #
27 #======================================================================
28
29 package RP;
30
31
32 sub income_statement {
33   my ($self, $myconfig, $form) = @_;
34
35   # connect to database
36   my $dbh = $form->dbconnect($myconfig);
37
38   my $last_period = 0;
39   my @categories = qw(I E);
40   my $category;
41
42   $form->{decimalplaces} *= 1;
43
44   &get_accounts($dbh, $last_period, $form->{fromdate}, $form->{todate}, $form, \@categories);
45   
46   # if there are any compare dates
47   if ($form->{comparefromdate} || $form->{comparetodate}) {
48     $last_period = 1;
49
50     &get_accounts($dbh, $last_period, $form->{comparefromdate}, $form->{comparetodate}, $form, \@categories);
51   }  
52
53   
54   # disconnect
55   $dbh->disconnect;
56
57
58   # now we got $form->{I}{accno}{ }
59   # and $form->{E}{accno}{  }
60   
61   my %account = ( 'I' => { 'label' => 'income',
62                            'labels' => 'income',
63                            'ml' => 1 },
64                   'E' => { 'label' => 'expense',
65                            'labels' => 'expenses',
66                            'ml' => -1 }
67                 );
68   
69   my $str;
70   
71   foreach $category (@categories) {
72     
73     foreach $key (sort keys %{ $form->{$category} }) {
74       # push description onto array
75       
76       $str = ($form->{l_heading}) ? $form->{padding} : "";
77       
78       if ($form->{$category}{$key}{charttype} eq "A") {
79         $str .= ($form->{l_accno}) ? "$form->{$category}{$key}{accno} - $form->{$category}{$key}{description}" : "$form->{$category}{$key}{description}";
80       }
81       if ($form->{$category}{$key}{charttype} eq "H") {
82         if ($account{$category}{subtotal} && $form->{l_subtotal}) {
83           $dash = "- ";
84           push(@{$form->{"$account{$category}{label}_account"}}, "$str$form->{bold}$account{$category}{subdescription}$form->{endbold}");
85           push(@{$form->{"$account{$category}{labels}_this_period"}}, $form->format_amount($myconfig, $account{$category}{subthis} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
86           
87           if ($last_period) {
88             push(@{$form->{"$account{$category}{labels}_last_period"}}, $form->format_amount($myconfig, $account{$category}{sublast} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
89           }
90           
91         }
92         
93         $str = "$form->{br}$form->{bold}$form->{$category}{$key}{description}$form->{endbold}";
94
95         $account{$category}{subthis} = $form->{$category}{$key}{this};
96         $account{$category}{sublast} = $form->{$category}{$key}{last};
97         $account{$category}{subdescription} = $form->{$category}{$key}{description};
98         $account{$category}{subtotal} = 1;
99
100         $form->{$category}{$key}{this} = 0;
101         $form->{$category}{$key}{last} = 0;
102
103         next unless $form->{l_heading};
104
105         $dash = " ";
106       }
107       
108       push(@{$form->{"$account{$category}{label}_account"}}, $str);
109       
110       if ($form->{$category}{$key}{charttype} eq 'A') {
111         $form->{"total_$account{$category}{labels}_this_period"} += $form->{$category}{$key}{this} * $account{$category}{ml};
112         $dash = "- ";
113       }
114       
115       push(@{$form->{"$account{$category}{labels}_this_period"}}, $form->format_amount($myconfig, $form->{$category}{$key}{this} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
116       
117       # add amount or - for last period
118       if ($last_period) {
119         $form->{"total_$account{$category}{labels}_last_period"} += $form->{$category}{$key}{last} * $account{$category}{ml};
120
121         push(@{$form->{"$account{$category}{labels}_last_period"}}, $form->format_amount($myconfig,$form->{$category}{$key}{last} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
122       }
123     }
124
125     $str = ($form->{l_heading}) ? $form->{padding} : "";
126     if ($account{$category}{subtotal} && $form->{l_subtotal}) {
127       push(@{$form->{"$account{$category}{label}_account"}}, "$str$form->{bold}$account{$category}{subdescription}$form->{endbold}");
128       push(@{$form->{"$account{$category}{labels}_this_period"}}, $form->format_amount($myconfig, $account{$category}{subthis} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
129
130       if ($last_period) {
131         push(@{$form->{"$account{$category}{labels}_last_period"}}, $form->format_amount($myconfig, $account{$category}{sublast} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
132       }
133     }
134       
135   }
136
137   
138   # totals for income and expenses
139   $form->{total_income_this_period} = $form->round_amount($form->{total_income_this_period}, $form->{decimalplaces});
140   $form->{total_expenses_this_period} = $form->round_amount($form->{total_expenses_this_period}, $form->{decimalplaces});
141
142   # total for income/loss
143   $form->{total_this_period} = $form->{total_income_this_period} - $form->{total_expenses_this_period};
144   
145   if ($last_period) {
146     # total for income/loss
147     $form->{total_last_period} = $form->format_amount($myconfig, $form->{total_income_last_period} - $form->{total_expenses_last_period}, $form->{decimalplaces}, "- ");
148     
149     # totals for income and expenses for last_period
150     $form->{total_income_last_period} = $form->format_amount($myconfig, $form->{total_income_last_period}, $form->{decimalplaces}, "- ");
151     $form->{total_expenses_last_period} = $form->format_amount($myconfig, $form->{total_expenses_last_period}, $form->{decimalplaces}, "- ");
152
153   }
154
155
156   $form->{total_income_this_period} = $form->format_amount($myconfig,$form->{total_income_this_period}, $form->{decimalplaces}, "- ");
157   $form->{total_expenses_this_period} = $form->format_amount($myconfig,$form->{total_expenses_this_period}, $form->{decimalplaces}, "- ");
158   $form->{total_this_period} = $form->format_amount($myconfig,$form->{total_this_period}, $form->{decimalplaces}, "- ");
159
160 }
161
162
163
164 sub balance_sheet {
165   my ($self, $myconfig, $form) = @_;
166   
167   # connect to database
168   my $dbh = $form->dbconnect($myconfig);
169
170   my $last_period = 0;
171   my @categories = qw(A L Q);
172
173   # if there are any dates construct a where
174   if ($form->{asofdate}) {
175     
176     $form->{this_period} = "$form->{asofdate}";
177     $form->{period} = "$form->{asofdate}";
178     
179   }
180
181   $form->{decimalplaces} *= 1;
182
183   &get_accounts($dbh, $last_period, "", $form->{asofdate}, $form, \@categories);
184   
185   # if there are any compare dates
186   if ($form->{compareasofdate}) {
187
188     $last_period = 1;
189     &get_accounts($dbh, $last_period, "", $form->{compareasofdate}, $form, \@categories);
190   
191     $form->{last_period} = "$form->{compareasofdate}";
192
193   }  
194
195   
196   # disconnect
197   $dbh->disconnect;
198
199
200   # now we got $form->{A}{accno}{ }    assets
201   # and $form->{L}{accno}{ }           liabilities
202   # and $form->{Q}{accno}{ }           equity
203   # build asset accounts
204   
205   my $str;
206   my $key;
207   
208   my %account  = ( 'A' => { 'label' => 'asset',
209                             'labels' => 'assets',
210                             'ml' => -1 },
211                    'L' => { 'label' => 'liability',
212                             'labels' => 'liabilities',
213                             'ml' => 1 },
214                    'Q' => { 'label' => 'equity',
215                             'labels' => 'equities',
216                             'ml' => 1 }
217                 );          
218                             
219   foreach $category (@categories) {
220
221     foreach $key (sort keys %{ $form->{$category} }) {
222
223       $str = ($form->{l_heading}) ? $form->{padding} : "";
224
225       if ($form->{$category}{$key}{charttype} eq "A") {
226         $str .= ($form->{l_accno}) ? "$form->{$category}{$key}{accno} - $form->{$category}{$key}{description}" : "$form->{$category}{$key}{description}";
227       }
228       if ($form->{$category}{$key}{charttype} eq "H") {
229         if ($account{$category}{subtotal} && $form->{l_subtotal}) {
230           $dash = "- ";
231           push(@{$form->{"$account{$category}{label}_account"}}, "$str$form->{bold}$account{$category}{subdescription}$form->{endbold}");
232           push(@{$form->{"$account{$category}{label}_this_period"}}, $form->format_amount($myconfig, $account{$category}{subthis} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
233           
234           if ($last_period) {
235             push(@{$form->{"$account{$category}{label}_last_period"}}, $form->format_amount($myconfig, $account{$category}{sublast} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
236           }
237         }
238
239         $str = "$form->{bold}$form->{$category}{$key}{description}$form->{endbold}";
240         
241         $account{$category}{subthis} = $form->{$category}{$key}{this};
242         $account{$category}{sublast} = $form->{$category}{$key}{last};
243         $account{$category}{subdescription} = $form->{$category}{$key}{description};
244         $account{$category}{subtotal} = 1;
245         
246         $form->{$category}{$key}{this} = 0;
247         $form->{$category}{$key}{last} = 0;
248
249         next unless $form->{l_heading};
250
251         $dash = " ";
252       }
253       
254       # push description onto array
255       push(@{$form->{"$account{$category}{label}_account"}}, $str);
256       
257       if ($form->{$category}{$key}{charttype} eq 'A') {
258         $form->{"total_$account{$category}{labels}_this_period"} += $form->{$category}{$key}{this} * $account{$category}{ml};
259         $dash = "- ";
260       }
261
262       push(@{$form->{"$account{$category}{label}_this_period"}}, $form->format_amount($myconfig, $form->{$category}{$key}{this} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
263       
264       if ($last_period) {
265         $form->{"total_$account{$category}{labels}_last_period"} += $form->{$category}{$key}{last} * $account{$category}{ml};
266
267         push(@{$form->{"$account{$category}{label}_last_period"}}, $form->format_amount($myconfig, $form->{$category}{$key}{last} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
268       }
269     }
270
271     $str = ($form->{l_heading}) ? $form->{padding} : "";
272     if ($account{$category}{subtotal} && $form->{l_subtotal}) {
273       push(@{$form->{"$account{$category}{label}_account"}}, "$str$form->{bold}$account{$category}{subdescription}$form->{endbold}");
274       push(@{$form->{"$account{$category}{label}_this_period"}}, $form->format_amount($myconfig, $account{$category}{subthis} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
275       
276       if ($last_period) {
277         push(@{$form->{"$account{$category}{label}_last_period"}}, $form->format_amount($myconfig, $account{$category}{sublast} * $account{$category}{ml}, $form->{decimalplaces}, $dash));
278       }
279     }
280
281   }
282
283   
284   # totals for assets, liabilities
285   $form->{total_assets_this_period} = $form->round_amount($form->{total_assets_this_period}, $form->{decimalplaces});
286   $form->{total_liabilities_this_period} = $form->round_amount($form->{total_liabilities_this_period}, $form->{decimalplaces});
287   
288
289   # calculate retained earnings
290   $form->{earnings_this_period} = $form->{total_assets_this_period} - $form->{total_liabilities_this_period} - $form->{total_equity_this_period};
291
292   push(@{$form->{equity_this_period}}, $form->format_amount($myconfig, $form->{earnings_this_period}, $form->{decimalplaces}, "- "));
293   
294   $form->{total_equity_this_period} = $form->round_amount($form->{total_equity_this_period} + $form->{earnings_this_period}, $form->{decimalplaces});
295   
296   # add liability + equity
297   $form->{total_this_period} = $form->format_amount($myconfig, $form->{total_liabilities_this_period} + $form->{total_equity_this_period}, $form->{decimalplaces}, "- ");
298
299
300   if ($last_period) {
301     # totals for assets, liabilities
302     $form->{total_assets_last_period} = $form->round_amount($form->{total_assets_last_period}, $form->{decimalplaces});
303     $form->{total_liabilities_last_period} = $form->round_amount($form->{total_liabilities_last_period}, $form->{decimalplaces});
304     
305
306     # calculate retained earnings
307     $form->{earnings_last_period} = $form->{total_assets_last_period} - $form->{total_liabilities_last_period} - $form->{total_equity_last_period};
308
309     push(@{$form->{equity_last_period}}, $form->format_amount($myconfig,$form->{earnings_last_period}, $form->{decimalplaces}, "- "));
310     
311     $form->{total_equity_last_period} = $form->round_amount($form->{total_equity_last_period} + $form->{earnings_last_period}, $form->{decimalplaces});
312
313     # add liability + equity
314     $form->{total_last_period} = $form->format_amount($myconfig, $form->{total_liabilities_last_period} + $form->{total_equity_last_period}, $form->{decimalplaces}, "- ");
315
316   }
317
318   
319   $form->{total_liabilities_last_period} = $form->format_amount($myconfig, $form->{total_liabilities_last_period}, $form->{decimalplaces}, "- ") if ($form->{total_liabilities_last_period} != 0);
320   
321   $form->{total_equity_last_period} = $form->format_amount($myconfig, $form->{total_equity_last_period}, $form->{decimalplaces}, "- ") if ($form->{total_equity_last_period} != 0);
322   
323   $form->{total_assets_last_period} = $form->format_amount($myconfig, $form->{total_assets_last_period}, $form->{decimalplaces}, "- ") if ($form->{total_assets_last_period} != 0);
324   
325   $form->{total_assets_this_period} = $form->format_amount($myconfig, $form->{total_assets_this_period}, $form->{decimalplaces}, "- ");
326   
327   $form->{total_liabilities_this_period} = $form->format_amount($myconfig, $form->{total_liabilities_this_period}, $form->{decimalplaces}, "- ");
328   
329   $form->{total_equity_this_period} = $form->format_amount($myconfig, $form->{total_equity_this_period}, $form->{decimalplaces}, "- ");
330   
331 }
332
333
334
335 sub get_accounts {
336   my ($dbh, $last_period, $fromdate, $todate, $form, $categories) = @_;
337
338   my $query;
339   my $where = "WHERE 1 = 1";
340   my $subwhere;
341   my $item;
342  
343   my $category = "AND (";
344   foreach $item (@{ $categories }) {
345     $category .= qq|c.category = '$item' OR |;
346   }
347   $category =~ s/OR $/\)/;
348
349
350   # get headings
351   $query = qq|SELECT accno, description, category
352               FROM chart c
353               WHERE c.charttype = 'H'
354               $category
355               ORDER by c.accno|;
356
357   if ($form->{accounttype} eq 'gifi')
358   {
359     $query = qq|SELECT g.accno, g.description, c.category
360                 FROM gifi g
361                 JOIN chart c ON (c.gifi_accno = g.accno)
362                 WHERE c.charttype = 'H'
363                 $category
364                 ORDER BY g.accno|;
365   }
366
367   $sth = $dbh->prepare($query);
368   $sth->execute || $form->dberror($query);
369   
370   my @headingaccounts = ();
371   while ($ref = $sth->fetchrow_hashref(NAME_lc))
372   {
373     $form->{$ref->{category}}{$ref->{accno}}{description} = "$ref->{description}";
374     $form->{$ref->{category}}{$ref->{accno}}{charttype} = "H";
375     $form->{$ref->{category}}{$ref->{accno}}{accno} = $ref->{accno};
376     
377     push @headingaccounts, $ref->{accno};
378   }
379
380   $sth->finish;
381
382
383   $where .= " AND ac.transdate >= '$fromdate'" if $fromdate;
384
385   if ($todate) {
386     $where .= " AND ac.transdate <= '$todate'";
387     $subwhere = " AND transdate <= '$todate'";
388   }
389     
390
391   if ($form->{project_id})
392   {
393     $project = qq|
394                  AND ac.project_id = $form->{project_id}
395                  |;
396   }
397
398
399   if ($form->{accounttype} eq 'gifi')
400   {
401     
402     if ($form->{method} eq 'cash')
403     {
404
405         $query = qq|
406         
407                  SELECT g.accno, sum(ac.amount) AS amount,
408                  g.description, c.category
409                  FROM acc_trans ac
410                  JOIN chart c ON (c.id = ac.chart_id)
411                  JOIN ar a ON (a.id = ac.trans_id)
412                  JOIN gifi g ON (g.accno = c.gifi_accno)
413                  $where
414                  $category
415                  AND ac.trans_id IN
416                    (
417                      SELECT trans_id
418                      FROM acc_trans
419                      JOIN chart ON (chart_id = id)
420                      WHERE link LIKE '%AR_paid%'
421                      $subwhere
422                    )
423                  $project
424                  GROUP BY g.accno, g.description, c.category
425                  
426        UNION
427        
428                  SELECT '' AS accno, SUM(ac.amount) AS amount,
429                  '' AS description, c.category
430                  FROM acc_trans ac
431                  JOIN chart c ON (c.id = ac.chart_id)
432                  JOIN ar a ON (a.id = ac.trans_id)
433                  $where
434                  $category
435                  AND c.gifi_accno = ''
436                  AND ac.trans_id IN
437                    (
438                      SELECT trans_id
439                      FROM acc_trans
440                      JOIN chart ON (chart_id = id)
441                      WHERE link LIKE '%AR_paid%'
442                      $subwhere
443                    )
444                  $project
445                  GROUP BY c.category
446
447        UNION
448
449                  SELECT g.accno, sum(ac.amount) AS amount,
450                  g.description, c.category
451                  FROM acc_trans ac
452                  JOIN chart c ON (c.id = ac.chart_id)
453                  JOIN ap a ON (a.id = ac.trans_id)
454                  JOIN gifi g ON (g.accno = c.gifi_accno)
455                  $where
456                  $category
457                  AND ac.trans_id IN
458                    (
459                      SELECT trans_id
460                      FROM acc_trans
461                      JOIN chart ON (chart_id = id)
462                      WHERE link LIKE '%AP_paid%'
463                      $subwhere
464                    )
465                  $project
466                  GROUP BY g.accno, g.description, c.category
467                  
468        UNION
469        
470                  SELECT '' AS accno, SUM(ac.amount) AS amount,
471                  '' AS description, c.category
472                  FROM acc_trans ac
473                  JOIN chart c ON (c.id = ac.chart_id)
474                  JOIN ap a ON (a.id = ac.trans_id)
475                  $where
476                  $category
477                  AND c.gifi_accno = ''
478                  AND ac.trans_id IN
479                    (
480                      SELECT trans_id
481                      FROM acc_trans
482                      JOIN chart ON (chart_id = id)
483                      WHERE link LIKE '%AP_paid%'
484                      $subwhere
485                    )
486                  $project
487                  GROUP BY c.category
488
489        UNION
490
491 -- add gl
492         
493                  SELECT g.accno, sum(ac.amount) AS amount,
494                  g.description, c.category
495                  FROM acc_trans ac
496                  JOIN chart c ON (c.id = ac.chart_id)
497                  JOIN gifi g ON (g.accno = c.gifi_accno)
498                  JOIN gl a ON (a.id = ac.trans_id)
499                  $where
500                  $category
501                  AND NOT (c.link = 'AR' OR c.link = 'AP')
502                  $project
503                  GROUP BY g.accno, g.description, c.category
504                  
505        UNION
506        
507                  SELECT '' AS accno, SUM(ac.amount) AS amount,
508                  '' AS description, c.category
509                  FROM acc_trans ac
510                  JOIN chart c ON (c.id = ac.chart_id)
511                  JOIN gl a ON (a.id = ac.trans_id)
512                  $where
513                  $category
514                  AND c.gifi_accno = ''
515                  AND NOT (c.link = 'AR' OR c.link = 'AP')
516                  $project
517                  GROUP BY c.category
518                  |;
519
520     } else {
521
522       $query = qq|
523       
524               SELECT g.accno, SUM(ac.amount) AS amount,
525               g.description, c.category
526               FROM acc_trans ac
527               JOIN chart c ON (c.id = ac.chart_id)
528               JOIN gifi g ON (c.gifi_accno = g.accno)
529               $where
530               $category
531               $project
532               GROUP BY g.accno, g.description, c.category
533               
534            UNION
535            
536               SELECT '' AS accno, SUM(ac.amount) AS amount,
537               '' AS description, c.category
538               FROM acc_trans ac
539               JOIN chart c ON (c.id = ac.chart_id)
540               $where
541               $category
542               AND c.gifi_accno = ''
543               $project
544               GROUP by c.category
545               |;
546               
547     }
548     
549   } else {
550
551     if ($form->{method} eq 'cash')
552     {
553
554
555       $query = qq|
556         
557                  SELECT c.accno, sum(ac.amount) AS amount,
558                  c.description, c.category
559                  FROM acc_trans ac
560                  JOIN chart c ON (c.id = ac.chart_id)
561                  JOIN ar a ON (a.id = ac.trans_id)
562                  $where
563                  $category
564                  AND ac.trans_id IN
565                    (
566                      SELECT trans_id
567                      FROM acc_trans
568                      JOIN chart ON (chart_id = id)
569                      WHERE link LIKE '%AR_paid%'
570                      $subwhere
571                    )
572                      
573                  $project
574                  GROUP BY c.accno, c.description, c.category
575                  
576         UNION
577         
578                  SELECT c.accno, sum(ac.amount) AS amount,
579                  c.description, c.category
580                  FROM acc_trans ac
581                  JOIN chart c ON (c.id = ac.chart_id)
582                  JOIN ap a ON (a.id = ac.trans_id)
583                  $where
584                  $category
585                  AND ac.trans_id IN
586                    (
587                      SELECT trans_id
588                      FROM acc_trans
589                      JOIN chart ON (chart_id = id)
590                      WHERE link LIKE '%AP_paid%'
591                      $subwhere
592                    )
593                      
594                  $project
595                  GROUP BY c.accno, c.description, c.category
596                  
597         UNION
598
599                  SELECT c.accno, sum(ac.amount) AS amount,
600                  c.description, c.category
601                  FROM acc_trans ac
602                  JOIN chart c ON (c.id = ac.chart_id)
603                  JOIN gl a ON (a.id = ac.trans_id)
604                  $where
605                  $category
606                  AND NOT (c.link = 'AR' OR c.link = 'AP')
607                  $project
608                  GROUP BY c.accno, c.description, c.category
609                  |;
610                  
611     } else {
612      
613       $query = qq|
614       
615                  SELECT c.accno, sum(ac.amount) AS amount,
616                  c.description, c.category
617                  FROM acc_trans ac
618                  JOIN chart c ON (c.id = ac.chart_id)
619                  $where
620                  $category
621                  $project
622                  GROUP BY c.accno, c.description, c.category
623                  |;
624
625     }
626     
627   }
628
629
630   my @accno;
631   my $accno;
632   my $ref;
633   
634   my $sth = $dbh->prepare($query);
635   $sth->execute || $form->dberror($query);
636
637   while ($ref = $sth->fetchrow_hashref(NAME_lc))
638   {
639
640     if ($ref->{category} eq 'C') {
641       $ref->{category} = 'A';
642     }
643       
644     # get last heading account
645     @accno = grep { $_ le "$ref->{accno}" } @headingaccounts;
646     $accno = pop @accno;
647     if ($accno) {
648       if ($last_period)
649       {
650         $form->{$ref->{category}}{$accno}{last} += $ref->{amount};
651       } else {
652         $form->{$ref->{category}}{$accno}{this} += $ref->{amount};
653       }
654     }
655     
656     $form->{$ref->{category}}{$ref->{accno}}{accno} = $ref->{accno};
657     $form->{$ref->{category}}{$ref->{accno}}{description} = $ref->{description};
658     $form->{$ref->{category}}{$ref->{accno}}{charttype} = "A";
659     
660     if ($last_period)
661     {
662       $form->{$ref->{category}}{$ref->{accno}}{last} += $ref->{amount};
663     } else {
664       $form->{$ref->{category}}{$ref->{accno}}{this} += $ref->{amount};
665     }
666   }
667   $sth->finish;
668
669   
670   # remove accounts with zero balance
671   foreach $category (@{ $categories }) {
672     foreach $accno (keys %{ $form->{$category} }) {
673       $form->{$category}{$accno}{last} = $form->round_amount($form->{$category}{$accno}{last}, $form->{decimalplaces});
674       $form->{$category}{$accno}{this} = $form->round_amount($form->{$category}{$accno}{this}, $form->{decimalplaces});
675
676       delete $form->{$category}{$accno} if ($form->{$category}{$accno}{this} == 0 && $form->{$category}{$accno}{last} == 0);
677     }
678   }
679
680 }
681
682
683
684 sub trial_balance_details {
685   my ($self, $myconfig, $form) = @_;
686
687   my $dbh = $form->dbconnect($myconfig);
688
689   my ($query, $sth, $ref);
690   my %balance = ();
691   my %trb = ();
692
693   my $where = "WHERE 1 = 1";
694
695   if ($form->{project_id}) {
696     $where .= qq|
697                 AND a.project_id = $form->{project_id}
698                 |;
699   }
700   
701   # get beginning balances
702   if ($form->{fromdate}) {
703
704     if ($form->{accounttype} eq 'gifi') {
705       
706       $query = qq|SELECT g.accno, c.category, SUM(a.amount) AS amount,
707                   g.description
708                   FROM acc_trans a
709                   JOIN chart c ON (a.chart_id = c.id)
710                   JOIN gifi g ON (c.gifi_accno = g.accno)
711                   $where
712                   AND a.transdate < '$form->{fromdate}'
713                   GROUP BY g.accno, c.category, g.description
714                   |;
715    
716     } else {
717       
718       $query = qq|SELECT c.accno, c.category, SUM(a.amount) AS amount,
719                   c.description
720                   FROM acc_trans a
721                   JOIN chart c ON (a.chart_id = c.id)
722                   $where
723                   AND a.transdate < '$form->{fromdate}'
724                   GROUP BY c.accno, c.category, c.description
725                   |;
726     }
727
728     $sth = $dbh->prepare($query);
729     $sth->execute || $form->dberror($query);
730
731     while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
732       $balance{$ref->{accno}} = $ref->{amount};
733
734       if ($ref->{amount} != 0 && $form->{all_accounts}) {
735         $trb{$ref->{accno}}{description} = $ref->{description};
736         $trb{$ref->{accno}}{charttype} = 'A';
737         $trb{$ref->{accno}}{category} = $ref->{category};
738       }
739
740     }
741     $sth->finish;
742
743   }
744
745
746   # get headings
747   $query = qq|SELECT c.accno, c.description, c.category
748               FROM chart c
749               WHERE c.charttype = 'H'
750               ORDER by c.accno|;
751
752   if ($form->{accounttype} eq 'gifi')
753   {
754     $query = qq|SELECT g.accno, g.description, c.category
755                 FROM gifi g
756                 JOIN chart c ON (c.gifi_accno = g.accno)
757                 WHERE c.charttype = 'H'
758                 ORDER BY g.accno|;
759   }
760
761   $sth = $dbh->prepare($query);
762   $sth->execute || $form->dberror($query);
763   
764   my @headingaccounts = ();
765   while ($ref = $sth->fetchrow_hashref(NAME_lc))
766   {
767     $trb{$ref->{accno}}{description} = $ref->{description};
768     $trb{$ref->{accno}}{charttype} = 'H';
769     $trb{$ref->{accno}}{category} = $ref->{category};
770    
771     push @headingaccounts, $ref->{accno};
772   }
773
774   $sth->finish;
775
776
777   if ($form->{fromdate} || $form->{todate}) {
778     if ($form->{fromdate}) {
779       $where .= " AND a.transdate >= '$form->{fromdate}'";
780     }
781     if ($form->{todate}) {
782       $where .= " AND a.transdate <= '$form->{todate}'";
783     }
784   }
785
786
787   if ($form->{accounttype} eq 'gifi') {
788
789     $query = qq|SELECT g.accno, g.description, c.category,
790                 SUM(a.amount) AS amount
791                 FROM acc_trans a
792                 JOIN chart c ON (c.id = a.chart_id)
793                 JOIN gifi g ON (c.gifi_accno = g.accno)
794                 $where
795                 GROUP BY g.accno, g.description, c.category
796                 
797               UNION
798
799                 SELECT '' AS accno, '' AS description, c.category,
800                 SUM(a.amount) AS amount
801                 FROM acc_trans a
802                 JOIN chart c ON (c.id = a.chart_id)
803                 $where
804                 AND c.gifi_accno = ''
805                 GROUP BY c.category
806                 ORDER BY accno|;
807     
808   } else {
809
810     $query = qq|SELECT c.accno, c.description, c.category,
811                 SUM(a.amount) AS amount
812                 FROM acc_trans a
813                 JOIN chart c ON (c.id = a.chart_id)
814                 $where
815                 GROUP BY c.accno, c.description, c.category
816                 ORDER BY accno|;
817
818   }
819   
820   $sth = $dbh->prepare($query);
821   $sth->execute || $form->dberror($query);
822
823
824   # prepare query for each account
825     
826   $query = qq|SELECT (SELECT SUM(a.amount) * -1
827               FROM acc_trans a
828               JOIN chart c ON (c.id = a.chart_id)
829               $where
830               AND a.amount < 0
831               AND c.accno = ?) AS debit,
832              (SELECT SUM(a.amount)
833               FROM acc_trans a
834               JOIN chart c ON (c.id = a.chart_id)
835               $where
836               AND a.amount > 0
837               AND c.accno = ?) AS credit
838               |;
839
840   if ($form->{accounttype} eq 'gifi') {
841
842     $query = qq|SELECT (SELECT SUM(a.amount) * -1
843                 FROM acc_trans a
844                 JOIN chart c ON (c.id = a.chart_id)
845                 $where
846                 AND a.amount < 0
847                 AND c.gifi_accno = ?) AS debit,
848                (SELECT SUM(a.amount)
849                 FROM acc_trans a
850                 JOIN chart c ON (c.id = a.chart_id)
851                 $where
852                 AND a.amount > 0
853                 AND c.gifi_accno = ?) AS credit|;
854   
855   }
856    
857   $drcr = $dbh->prepare($query);
858   
859   # calculate the debit and credit in the period
860   while ($ref = $sth->fetchrow_hashref(NAME_lc)) {
861     $trb{$ref->{accno}}{description} = $ref->{description};
862     $trb{$ref->{accno}}{charttype} = 'A';
863     $trb{$ref->{accno}}{category} = $ref->{category};
864     $trb{$ref->{accno}}{amount} += $ref->{amount};
865
866   }
867   $sth->finish;
868
869   my ($debit, $credit);
870   
871   foreach my $accno (sort keys %trb) {
872     $ref = ();
873
874     $ref->{accno} = $accno;
875     map { $ref->{$_} = $trb{$accno}{$_} } qw(description category charttype amount);
876     
877     $ref->{balance} = $form->round_amount($balance{$ref->{accno}}, 2);
878
879     if ($trb{$accno}{charttype} eq 'A') {
880       # get DR/CR
881       $drcr->execute($ref->{accno}, $ref->{accno}) || $form->dberror($query);
882       
883       ($debit, $credit) = (0,0);
884       while (($debit, $credit) = $drcr->fetchrow_array) {
885         $ref->{debit} += $debit;
886         $ref->{credit} += $credit;
887       }
888       $drcr->finish;
889
890       $ref->{debit} = $form->round_amount($ref->{debit}, 2);
891       $ref->{credit} = $form->round_amount($ref->{credit}, 2);
892     
893     }
894
895
896     # add subtotal
897     @accno = grep { $_ le "$ref->{accno}" } @headingaccounts;
898     $accno = pop @accno;
899     if ($accno) {
900       $trb{$accno}{debit} += $ref->{debit};
901       $trb{$accno}{credit} += $ref->{credit};
902     }
903    
904     push @{ $form->{TB} }, $ref;
905     
906   }
907
908   $dbh->disconnect;
909
910   # debits and credits for headings
911   foreach $accno (@headingaccounts) {
912     foreach $ref (@{ $form->{TB} }) {
913       if ($accno eq $ref->{accno}) {
914         $ref->{debit} = $trb{$accno}{debit};
915         $ref->{credit} = $trb{$accno}{credit};
916       }
917     }
918   }
919
920 }
921
922
923
924 sub aging {
925   my ($self, $myconfig, $form) = @_;
926
927   # connect to database
928   my $dbh = $form->dbconnect($myconfig);
929   my $invoice = ($form->{arap} eq 'ar') ? 'is' : 'ir';
930   
931   $form->{todate} = $form->current_date($myconfig) unless ($form->{todate});
932
933   my $where = "1 = 1";
934   my $name;
935
936   if ($form->{"$form->{ct}_id"}) {
937     $where .= qq| AND ct.id = $form->{"$form->{ct}_id"}|;
938   } else {
939     if ($form->{$form->{ct}}) {
940       $name = $form->like(lc $form->{$form->{ct}});
941       $where .= qq| AND lower(ct.name) LIKE '$name'| if $form->{$form->{ct}};
942     }
943   }
944
945   # select outstanding vendors or customers, depends on $ct
946   my $query = qq|SELECT DISTINCT ct.id, ct.name
947                  FROM $form->{ct} ct, $form->{arap} a
948                  WHERE $where
949                  AND a.$form->{ct}_id = ct.id
950                  AND a.paid != a.amount
951                  AND (a.transdate <= '$form->{todate}')
952                  ORDER BY ct.name|;
953
954   my $sth = $dbh->prepare($query);
955   $sth->execute || $form->dberror;
956
957   my $buysell = ($form->{arap} eq 'ar') ? 'buy' : 'sell';
958   
959   # for each company that has some stuff outstanding
960   while ( my ($id) = $sth->fetchrow_array ) {
961   
962     $query = qq|
963
964 -- between 0-30 days
965
966         SELECT $form->{ct}.id AS ctid, $form->{ct}.name,
967         addr1, addr2, addr3, addr4, contact,
968         phone as customerphone, fax as customerfax, $form->{ct}number,
969         "invnumber", "transdate",
970         (amount - paid) as "c0", 0.00 as "c30", 0.00 as "c60", 0.00 as "c90",
971         "duedate", invoice, $form->{arap}.id,
972           (SELECT $buysell FROM exchangerate
973            WHERE $form->{arap}.curr = exchangerate.curr
974            AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate
975   FROM $form->{arap}, $form->{ct} 
976         WHERE paid != amount
977         AND $form->{arap}.$form->{ct}_id = $form->{ct}.id
978         AND $form->{ct}.id = $id
979         AND (
980                 transdate <= (date '$form->{todate}' - interval '0 days') 
981                 AND transdate >= (date '$form->{todate}' - interval '30 days')
982             )
983         
984         UNION
985
986 -- between 31-60 days
987
988         SELECT $form->{ct}.id AS ctid, $form->{ct}.name,
989         addr1, addr2, addr3, addr4, contact,
990         phone as customerphone, fax as customerfax, $form->{ct}number,
991         "invnumber", "transdate", 
992         0.00 as "c0", (amount - paid) as "c30", 0.00 as "c60", 0.00 as "c90",
993         "duedate", invoice, $form->{arap}.id,
994           (SELECT $buysell FROM exchangerate
995            WHERE $form->{arap}.curr = exchangerate.curr
996            AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate
997   FROM $form->{arap}, $form->{ct}
998         WHERE paid != amount 
999         AND $form->{arap}.$form->{ct}_id = $form->{ct}.id 
1000         AND $form->{ct}.id = $id
1001         AND (
1002                 transdate < (date '$form->{todate}' - interval '30 days') 
1003                 AND transdate >= (date '$form->{todate}' - interval '60 days')
1004                 )
1005
1006         UNION
1007   
1008 -- between 61-90 days
1009
1010         SELECT $form->{ct}.id AS ctid, $form->{ct}.name,
1011         addr1, addr2, addr3, addr4, contact,
1012         phone as customerphone, fax as customerfax, $form->{ct}number,
1013         "invnumber", "transdate", 
1014         0.00 as "c0", 0.00 as "c30", (amount - paid) as "c60", 0.00 as "c90",
1015         "duedate", invoice, $form->{arap}.id,
1016           (SELECT $buysell FROM exchangerate
1017            WHERE $form->{arap}.curr = exchangerate.curr
1018            AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate
1019         FROM $form->{arap}, $form->{ct} 
1020         WHERE paid != amount
1021         AND $form->{arap}.$form->{ct}_id = $form->{ct}.id 
1022         AND $form->{ct}.id = $id
1023         AND (
1024                 transdate < (date '$form->{todate}' - interval '60 days') 
1025                 AND transdate >= (date '$form->{todate}' - interval '90 days')
1026                 )
1027
1028         UNION
1029   
1030 -- over 90 days
1031
1032         SELECT $form->{ct}.id AS ctid, $form->{ct}.name,
1033         addr1, addr2, addr3, addr4, contact,
1034         phone as customerphone, fax as customerfax, $form->{ct}number,
1035         "invnumber", "transdate", 
1036         0.00 as "c0", 0.00 as "c30", 0.00 as "c60", (amount - paid) as "c90",
1037         "duedate", invoice, $form->{arap}.id,
1038           (SELECT $buysell FROM exchangerate
1039            WHERE $form->{arap}.curr = exchangerate.curr
1040            AND exchangerate.transdate = $form->{arap}.transdate) AS exchangerate
1041         FROM $form->{arap}, $form->{ct} 
1042         WHERE paid != amount
1043         AND $form->{arap}.$form->{ct}_id = $form->{ct}.id 
1044         AND $form->{ct}.id = $id
1045         AND transdate < (date '$form->{todate}' - interval '90 days') 
1046
1047         ORDER BY
1048   
1049   ctid, invnumber, transdate
1050   
1051                 |;
1052
1053     my $sth = $dbh->prepare($query);
1054     $sth->execute || $form->dberror;
1055
1056     while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1057       $ref->{module} = ($ref->{invoice}) ? $invoice : $form->{arap};
1058       $ref->{exchangerate} = 1 unless $ref->{exchangerate};
1059       push @{ $form->{AG} }, $ref;
1060     }
1061     
1062     $sth->finish;
1063
1064   }
1065
1066   $sth->finish;
1067   # disconnect
1068   $dbh->disconnect;
1069
1070 }
1071
1072
1073 sub get_customer {
1074   my ($self, $myconfig, $form) = @_;
1075
1076   # connect to database
1077   my $dbh = $form->dbconnect($myconfig);
1078
1079   my $query = qq|SELECT name, email, cc, bcc
1080                  FROM $form->{ct} ct
1081                  WHERE ct.id = $form->{"$form->{ct}_id"}|;
1082   my $sth = $dbh->prepare($query);
1083   $sth->execute || $form->dberror;
1084
1085   ($form->{$form->{ct}}, $form->{email}, $form->{cc}, $form->{bcc}) = $sth->fetchrow_array;
1086   $sth->finish;
1087   $dbh->disconnect;
1088
1089 }
1090
1091
1092 sub get_taxaccounts {
1093   my ($self, $myconfig, $form) = @_;
1094
1095   # connect to database
1096   my $dbh = $form->dbconnect($myconfig);
1097
1098   # get tax accounts
1099   my $query = qq|SELECT accno, description
1100                  FROM chart
1101                  WHERE link LIKE '%CT_tax%'
1102                  ORDER BY accno|;
1103   my $sth = $dbh->prepare($query);
1104   $sth->execute || $form->dberror;
1105
1106   while ( my ($accno, $description) = $sth->fetchrow_array ) {
1107     push @{ $form->{taxaccounts} }, "$accno--$description";
1108   }
1109   $sth->finish;
1110
1111   # get gifi tax accounts
1112   my $query = qq|SELECT DISTINCT ON (g.accno) g.accno, g.description
1113                  FROM gifi g, chart c
1114                  WHERE g.accno = c.gifi_accno
1115                  AND c.link LIKE '%CT_tax%'
1116                  ORDER BY accno|;
1117   my $sth = $dbh->prepare($query);
1118   $sth->execute || $form->dberror;
1119
1120   while ( my ($accno, $description) = $sth->fetchrow_array ) {
1121     push @{ $form->{gifi_taxaccounts} }, "$accno--$description";
1122   }
1123   $sth->finish;
1124
1125   $dbh->disconnect;
1126
1127 }
1128
1129
1130
1131 sub tax_report {
1132   my ($self, $myconfig, $form) = @_;
1133
1134   # connect to database
1135   my $dbh = $form->dbconnect($myconfig);
1136
1137   # build WHERE
1138   my $where = qq|WHERE ac.trans_id = a.id
1139                  AND ac.chart_id = ch.id|;
1140                  
1141
1142   if ($form->{accno} =~ /^gifi_/) {
1143     my ($null, $accno) = split /_/, $form->{accno};
1144     $where .= qq| AND ch.gifi_accno = '$accno'|;
1145   } else {
1146     $where .= qq| AND ch.accno = '$form->{accno}'|;
1147   }
1148
1149   my $table;
1150   
1151   if ($form->{db} eq 'ar') {
1152     $where .= " AND n.id = a.customer_id";
1153     $table = "customer";
1154   }
1155   if ($form->{db} eq 'ap') {
1156     $where .= " AND n.id = a.vendor_id";
1157     $table = "vendor";
1158   }
1159
1160   my $transdate = ($form->{cashbased}) ? "a.datepaid" : "ac.transdate";
1161   if ($form->{cashbased}) {
1162     $where .= " AND a.amount = a.paid";
1163   }
1164
1165   # if there are any dates construct a where
1166   if ($form->{fromdate} || $form->{todate}) {
1167     if ($form->{fromdate}) {
1168       $where .= " AND $transdate >= '$form->{fromdate}'";
1169     }
1170     if ($form->{todate}) {
1171       $where .= " AND $transdate <= '$form->{todate}'";
1172     }
1173   }
1174   
1175   my $query = qq|SELECT a.id, a.invoice, $transdate AS transdate, a.invnumber,
1176                         n.name, a.netamount,|;
1177   my $sortorder = join ', ', $form->sort_columns(qw(transdate invnumber name));
1178   $sortorder = $form->{sort} unless $sortorder;
1179   
1180   if ($form->{db} eq 'ar') {
1181     $query .= " ac.amount AS tax";
1182   }
1183   if ($form->{db} eq 'ap') {
1184     $query .= " ac.amount * -1 AS tax";
1185   }
1186
1187   $query .= qq|
1188                FROM acc_trans ac, "$form->{db}" a, "$table" n, chart ch
1189                $where
1190                ORDER by $sortorder|;
1191
1192   my $sth = $dbh->prepare($query);
1193   $sth->execute || $form->dberror($query);
1194
1195   while ( my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1196     push @{ $form->{TR} }, $ref;
1197   }
1198
1199   $sth->finish;
1200   $dbh->disconnect;
1201
1202 }
1203
1204
1205 sub paymentaccounts {
1206   my ($self, $myconfig, $form) = @_;
1207  
1208   # connect to database, turn AutoCommit off
1209   my $dbh = $form->dbconnect_noauto($myconfig);
1210
1211   my $arap = uc $form->{db};
1212   $arap .= "_paid";
1213   
1214   # get A(R|P)_paid accounts
1215   my $query = qq|SELECT accno, description
1216                  FROM chart
1217                  WHERE link LIKE '%$arap%'|;
1218   my $sth = $dbh->prepare($query);
1219   $sth->execute || $form->dberror($query);
1220  
1221   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1222     push @{ $form->{PR} }, $ref;
1223   }
1224
1225   $sth->finish;
1226   $dbh->disconnect;
1227
1228 }
1229
1230  
1231 sub payments {
1232   my ($self, $myconfig, $form) = @_;
1233
1234   # connect to database, turn AutoCommit off
1235   my $dbh = $form->dbconnect_noauto($myconfig);
1236
1237   my $ml = 1;
1238   if ($form->{db} eq 'ar') {
1239     $table = 'customer';
1240     $ml = -1;
1241   }
1242   if ($form->{db} eq 'ap') {
1243     $table = 'vendor';
1244   }
1245   
1246   my ($query, $sth);
1247   
1248   # cycle through each id
1249   foreach my $accno (split(/ /, $form->{paymentaccounts})) {
1250
1251     $query = qq|SELECT id, accno, description
1252                 FROM chart
1253                 WHERE accno = '$accno'|;
1254     $sth = $dbh->prepare($query);
1255     $sth->execute || $form->dberror($query);
1256
1257     my $ref = $sth->fetchrow_hashref(NAME_lc);
1258     push @{ $form->{PR} }, $ref;
1259     $sth->finish;
1260
1261     $query = qq|SELECT c.name, a.invnumber, a.ordnumber,
1262                 ac.transdate,
1263                 ac.amount * $ml AS paid, ac.source, a.invoice, a.id,
1264                 '$form->{db}' AS module
1265                 FROM $table c, acc_trans ac, $form->{db} a
1266                 WHERE c.id = a.${table}_id
1267                 AND ac.trans_id = a.id
1268                 AND ac.chart_id = $ref->{id}|;
1269                 
1270     $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
1271     $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
1272
1273     $query .= qq|
1274         UNION
1275                 SELECT g.description, g.reference, NULL AS ordnumber,
1276                  ac.transdate,
1277                  ac.amount * $ml AS paid, ac.source, '0' as invoice, g.id,
1278                  'gl' AS module
1279                  FROM gl g, acc_trans ac
1280                  WHERE g.id = ac.trans_id
1281                  AND ac.chart_id = $ref->{id}
1282                  AND (ac.amount * $ml) > 0
1283                 |;
1284
1285     $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
1286     $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
1287
1288
1289     my $sortorder = join ', ', $form->sort_columns(qw(name invnumber ordnumber transdate source));
1290     
1291     $query .= " ORDER BY $sortorder";
1292
1293     $sth = $dbh->prepare($query);
1294     $sth->execute || $form->dberror($query);
1295
1296     while (my $pr = $sth->fetchrow_hashref(NAME_lc)) {
1297       push @{ $form->{$ref->{id}} }, $pr;
1298     }
1299     $sth->finish;
1300
1301   }
1302   
1303   $dbh->disconnect;
1304   
1305 }
1306
1307
1308 1;
1309
1310