d691b3ce63bb95417d6aa48e2cf6cde3444aadcb
[freeside.git] / sql-ledger / SL / AM.pm
1 #=====================================================================
2 # SQL-Ledger Accounting
3 # Copyright (C) 2001
4 #
5 #  Author: Dieter Simader
6 #   Email: dsimader@sql-ledger.org
7 #     Web: http://www.sql-ledger.org
8 #
9 #  Contributors:
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 # Administration module
26 #    Chart of Accounts
27 #    template routines
28 #    preferences
29 #
30 #======================================================================
31
32 package AM;
33
34
35 sub get_account {
36   my ($self, $myconfig, $form) = @_;
37
38   # connect to database
39   my $dbh = $form->dbconnect($myconfig);
40
41   my $query = qq|SELECT accno, description, charttype, gifi_accno,
42                  category, link
43                  FROM chart
44                  WHERE id = $form->{id}|;
45   my $sth = $dbh->prepare($query);
46   $sth->execute || $form->dberror($query);
47
48   my $ref = $sth->fetchrow_hashref(NAME_lc);
49   
50   foreach my $key (keys %$ref) {
51     $form->{"$key"} = $ref->{"$key"};
52   }
53
54   $sth->finish;
55
56
57   # get default accounts
58   $query = qq|SELECT inventory_accno_id, income_accno_id, expense_accno_id
59               FROM defaults|;
60   $sth = $dbh->prepare($query);
61   $sth->execute || $form->dberror($query);
62
63   $ref = $sth->fetchrow_hashref(NAME_lc);
64
65   map { $form->{$_} = $ref->{$_} } keys %ref;
66
67   $sth->finish;
68   $dbh->disconnect;
69
70 }
71
72
73 sub save_account {
74   my ($self, $myconfig, $form) = @_;
75
76   # connect to database, turn off AutoCommit
77   my $dbh = $form->dbconnect_noauto($myconfig);
78
79   # sanity check, can't have AR with AR_...
80   if ($form->{AR} || $form->{AP} || $form->{IC}) {
81     map { delete $form->{$_} } qw(AR_amount AR_tax AR_paid AP_amount AP_tax AP_paid IC_sale IC_cogs IC_taxpart IC_income IC_expense IC_taxservice);
82   }
83   
84   $form->{link} = "";
85   foreach my $item ($form->{AR},
86                     $form->{AR_amount},
87                     $form->{AR_tax},
88                     $form->{AR_paid},
89                     $form->{AP},
90                     $form->{AP_amount},
91                     $form->{AP_tax},
92                     $form->{AP_paid},
93                     $form->{IC},
94                     $form->{IC_sale},
95                     $form->{IC_cogs},
96                     $form->{IC_taxpart},
97                     $form->{IC_income},
98                     $form->{IC_expense},
99                     $form->{IC_taxservice},
100                     $form->{CT_tax}
101                     ) {
102      $form->{link} .= "${item}:" if ($item);
103   }
104   chop $form->{link};
105
106   # if we have an id then replace the old record
107   $form->{description} =~ s/'/''/g;
108
109   # strip blanks from accno
110   map { $form->{$_} =~ s/ //g; } qw(accno gifi_accno);
111   
112   my ($query, $sth);
113   
114   if ($form->{id}) {
115     $query = qq|UPDATE chart SET
116                 accno = '$form->{accno}',
117                 description = '$form->{description}',
118                 charttype = '$form->{charttype}',
119                 gifi_accno = '$form->{gifi_accno}',
120                 category = '$form->{category}',
121                 link = '$form->{link}'
122                 WHERE id = $form->{id}|;
123   } else {
124     $query = qq|INSERT INTO chart 
125                 (accno, description, charttype, gifi_accno, category, link)
126                 VALUES ('$form->{accno}', '$form->{description}',
127                 '$form->{charttype}', '$form->{gifi_accno}',
128                 '$form->{category}', '$form->{link}')|;
129   }
130   $dbh->do($query) || $form->dberror($query);
131   
132
133   if ($form->{IC_taxpart} || $form->{IC_taxservice} || $form->{CT_tax}) {
134
135     my $chart_id = $form->{id};
136     
137     unless ($form->{id}) {
138       # get id from chart
139       $query = qq|SELECT id
140                   FROM chart
141                   WHERE accno = '$form->{accno}'|;
142       $sth = $dbh->prepare($query);
143       $sth->execute || $form->dberror($query);
144
145       ($chart_id) = $sth->fetchrow_array;
146       $sth->finish;
147     }
148     
149     # add account if it doesn't exist in tax
150     $query = qq|SELECT chart_id
151                 FROM tax
152                 WHERE chart_id = $chart_id|;
153     $sth = $dbh->prepare($query);
154     $sth->execute || $form->dberror($query);
155
156     my ($tax_id) = $sth->fetchrow_array;
157     $sth->finish;
158     
159     # add tax if it doesn't exist
160     unless ($tax_id) {
161       $query = qq|INSERT INTO tax (chart_id, rate)
162                   VALUES ($chart_id, 0)|;
163       $dbh->do($query) || $form->dberror($query);
164     }
165   } else {
166     # remove tax
167     if ($form->{id}) {
168       $query = qq|DELETE FROM tax
169                   WHERE chart_id = $form->{id}|;
170       $dbh->do($query) || $form->dberror($query);
171     }
172   }
173
174
175   # commit
176   my $rc = $dbh->commit;
177   $dbh->disconnect;
178
179   $rc;
180   
181 }
182
183
184
185 sub delete_account {
186   my ($self, $myconfig, $form) = @_;
187
188   # connect to database, turn off AutoCommit
189   my $dbh = $form->dbconnect_noauto($myconfig);
190
191   # delete chart of account record
192   $query = qq|DELETE FROM chart
193               WHERE id = $form->{id}|;
194   $dbh->do($query) || $form->dberror($query);
195
196   # set inventory_accno_id, income_accno_id, expense_accno_id to defaults
197   $query = qq|UPDATE parts
198               SET inventory_accno_id = 
199                          (SELECT inventory_accno_id FROM defaults)
200               WHERE inventory_accno_id = $form->{id}|;
201   $dbh->do($query) || $form->dberror($query);
202   
203   $query = qq|UPDATE parts
204               SET income_accno_id =
205                          (SELECT income_accno_id FROM defaults)
206               WHERE income_accno_id = $form->{id}|;
207   $dbh->do($query) || $form->dberror($query);
208   
209   $query = qq|UPDATE parts
210               SET expense_accno_id =
211                          (SELECT expense_accno_id FROM defaults)
212               WHERE expense_accno_id = $form->{id}|;
213   $dbh->do($query) || $form->dberror($query);
214   
215   foreach my $table (qw(partstax customertax vendortax tax)) {
216     $query = qq|DELETE FROM $table
217                 WHERE chart_id = $form->{id}|;
218     $dbh->do($query) || $form->dberror($query);
219   }
220
221   # commit and redirect
222   my $rc = $dbh->commit;
223   $dbh->disconnect;
224   
225   $rc;
226
227 }
228
229
230 sub gifi_accounts {
231   my ($self, $myconfig, $form) = @_;
232   
233   # connect to database
234   my $dbh = $form->dbconnect($myconfig);
235
236   my $query = qq|SELECT accno, description
237                  FROM gifi
238                  ORDER BY accno|;
239
240   $sth = $dbh->prepare($query);
241   $sth->execute || $form->dberror($query);
242
243   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
244     push @{ $form->{ALL} }, $ref;
245   }
246
247   $sth->finish;
248   $dbh->disconnect;
249   
250 }
251
252
253
254 sub get_gifi {
255   my ($self, $myconfig, $form) = @_;
256
257   # connect to database
258   my $dbh = $form->dbconnect($myconfig);
259   
260   my $query = qq|SELECT accno, description
261                  FROM gifi
262                  WHERE accno = '$form->{accno}'|;
263   my $sth = $dbh->prepare($query);
264   $sth->execute || $form->dberror($query);
265
266   my $ref = $sth->fetchrow_hashref(NAME_lc);
267   
268   map { $form->{$_} = $ref->{$_} } keys %$ref;
269
270   $sth->finish;
271   $dbh->disconnect;
272
273 }
274
275
276 sub save_gifi {
277   my ($self, $myconfig, $form) = @_;
278   
279   # connect to database
280   my $dbh = $form->dbconnect($myconfig);
281   
282   $form->{description} =~ s/'/''/g;
283   $form->{accno} =~ s/ //g;
284
285   # id is the old account number!
286   if ($form->{id}) {
287     $query = qq|UPDATE gifi SET
288                 accno = '$form->{accno}',
289                 description = '$form->{description}'
290                 WHERE accno = '$form->{id}'|;
291   } else {
292     $query = qq|INSERT INTO gifi 
293                 (accno, description)
294                 VALUES ('$form->{accno}', '$form->{description}')|;
295   }
296   $dbh->do($query) || $form->dberror($query);
297   
298   $dbh->disconnect;
299
300 }
301
302
303 sub delete_gifi {
304   my ($self, $myconfig, $form) = @_;
305   
306   # connect to database
307   my $dbh = $form->dbconnect($myconfig);
308   
309   # id is the old account number!
310   $query = qq|DELETE FROM gifi
311               WHERE accno = '$form->{id}'|;
312   $dbh->do($query) || $form->dberror($query);
313   
314   $dbh->disconnect;
315
316 }
317
318
319 sub load_template {
320   my ($self, $form) = @_;
321   
322   open(TEMPLATE, "$form->{file}") or $form->error("$form->{file} : $!");
323
324   while (<TEMPLATE>) {
325     $form->{body} .= $_;
326   }
327
328   close(TEMPLATE);
329
330 }
331
332
333 sub save_template {
334   my ($self, $form) = @_;
335   
336   open(TEMPLATE, ">$form->{file}") or $form->error("$form->{file} : $!");
337   
338   # strip \r
339   $form->{body} =~ s/\r\n/\n/g;
340   print TEMPLATE $form->{body};
341
342   close(TEMPLATE);
343
344 }
345
346
347
348 sub save_preferences {
349   my ($self, $myconfig, $form, $memberfile, $userspath) = @_;
350
351   map { ($form->{$_}) = split /--/, $form->{$_} } qw(inventory_accno income_accno expense_accno fxgain_accno fxloss_accno);
352   
353   my @a;
354   $form->{curr} =~ s/ //g;
355   map { push(@a, uc pack "A3", $_) if $_ } split /:/, $form->{curr};
356   $form->{curr} = join ':', @a;
357     
358   # connect to database
359   my $dbh = $form->dbconnect_noauto($myconfig);
360   
361   # these defaults are database wide
362   # user specific variables are in myconfig
363   # save defaults
364   my $query = qq|UPDATE defaults SET
365                  inventory_accno_id = 
366                      (SELECT id FROM chart
367                                 WHERE accno = '$form->{inventory_accno}'),
368                  income_accno_id =
369                      (SELECT id FROM chart
370                                 WHERE accno = '$form->{income_accno}'),
371                  expense_accno_id =
372                      (SELECT id FROM chart
373                                 WHERE accno = '$form->{expense_accno}'),
374                  fxgain_accno_id =
375                      (SELECT id FROM chart
376                                 WHERE accno = '$form->{fxgain_accno}'),
377                  fxloss_accno_id =
378                      (SELECT id FROM chart
379                                 WHERE accno = '$form->{fxloss_accno}'),
380                  invnumber = '$form->{invnumber}',
381                  sonumber = '$form->{sonumber}',
382                  ponumber = '$form->{ponumber}',
383                  yearend = '$form->{yearend}',
384                  curr = '$form->{curr}',
385                  weightunit = '$form->{weightunit}',
386                  businessnumber = '$form->{businessnumber}'
387                 |;
388   $dbh->do($query) || $form->dberror($query);
389
390   # update name
391   my $name = $form->{name};
392   $name =~ s/'/''/g;
393   $query = qq|UPDATE employee
394               SET name = '$name'
395               WHERE login = '$form->{login}'|;
396   $dbh->do($query) || $form->dberror($query);
397   
398   foreach my $item (split / /, $form->{taxaccounts}) {
399     $query = qq|UPDATE tax
400                 SET rate = |.($form->{$item} / 100).qq|,
401                 taxnumber = '$form->{"taxnumber_$item"}'
402                 WHERE chart_id = $item|;
403     $dbh->do($query) || $form->dberror($query);
404   }
405
406   my $rc = $dbh->commit;
407   $dbh->disconnect;
408
409   # save first currency in myconfig
410   $form->{currency} = substr($form->{curr},0,3);
411   
412   my $myconfig = new User "$memberfile", "$form->{login}";
413   
414   foreach my $item (keys %$form) {
415     $myconfig->{$item} = $form->{$item};
416   }
417
418   $myconfig->save_member($memberfile, $userspath);
419
420   $rc;
421   
422 }
423
424
425 sub defaultaccounts {
426   my ($self, $myconfig, $form) = @_;
427   
428   # connect to database
429   my $dbh = $form->dbconnect($myconfig);
430   
431   # get defaults from defaults table
432   my $query = qq|SELECT * FROM defaults|;
433   my $sth = $dbh->prepare($query);
434   $sth->execute || $form->dberror($query);
435   
436   $form->{defaults} = $sth->fetchrow_hashref(NAME_lc);
437   $form->{defaults}{IC} = $form->{defaults}{inventory_accno_id};
438   $form->{defaults}{IC_income} = $form->{defaults}{income_accno_id};
439   $form->{defaults}{IC_expense} = $form->{defaults}{expense_accno_id};
440   $form->{defaults}{FX_gain} = $form->{defaults}{fxgain_accno_id};
441   $form->{defaults}{FX_loss} = $form->{defaults}{fxloss_accno_id};
442   
443   
444   $sth->finish;
445
446
447   $query = qq|SELECT id, accno, description, link
448               FROM chart
449               WHERE link LIKE '%IC%'
450               ORDER BY accno|;
451   $sth = $dbh->prepare($query);
452   $sth->execute || $self->dberror($query);
453
454   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
455     foreach my $key (split(/:/, $ref->{link})) {
456       if ($key =~ /IC/) {
457         $nkey = $key;
458         if ($key =~ /cogs/) {
459           $nkey = "IC_expense";
460         }
461         if ($key =~ /sale/) {
462           $nkey = "IC_income";
463         }
464         %{ $form->{IC}{$nkey}{$ref->{accno}} } = ( id => $ref->{id},
465                                         description => $ref->{description} );
466       }
467     }
468   }
469   $sth->finish;
470
471
472   $query = qq|SELECT id, accno, description
473               FROM chart
474               WHERE category = 'I'
475               AND charttype = 'A'
476               ORDER BY accno|;
477   $sth = $dbh->prepare($query);
478   $sth->execute || $self->dberror($query);
479
480   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
481     %{ $form->{IC}{FX_gain}{$ref->{accno}} } = ( id => $ref->{id},
482                                       description => $ref->{description} );
483   }
484   $sth->finish;
485
486   $query = qq|SELECT id, accno, description
487               FROM chart
488               WHERE category = 'E'
489               AND charttype = 'A'
490               ORDER BY accno|;
491   $sth = $dbh->prepare($query);
492   $sth->execute || $self->dberror($query);
493
494   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
495     %{ $form->{IC}{FX_loss}{$ref->{accno}} } = ( id => $ref->{id},
496                                       description => $ref->{description} );
497   }
498   $sth->finish;
499
500
501   # now get the tax rates and numbers
502   $query = qq|SELECT chart.id, chart.accno, chart.description,
503               tax.rate * 100 AS rate, tax.taxnumber
504               FROM chart, tax
505               WHERE chart.id = tax.chart_id|;
506
507   $sth = $dbh->prepare($query);
508   $sth->execute || $form->dberror($query);
509
510   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
511     $form->{taxrates}{$ref->{accno}}{id} = $ref->{id};
512     $form->{taxrates}{$ref->{accno}}{description} = $ref->{description};
513     $form->{taxrates}{$ref->{accno}}{taxnumber} = $ref->{taxnumber} if $ref->{taxnumber};
514     $form->{taxrates}{$ref->{accno}}{rate} = $ref->{rate} if $ref->{rate};
515   }
516
517   $sth->finish;
518   $dbh->disconnect;
519   
520 }
521
522
523 sub backup {
524   my ($self, $myconfig, $form, $userspath) = @_;
525   
526   my ($tmpfile, $out, $mail);
527   
528   if ($form->{media} eq 'email') {
529
530     my $boundary = time;
531     $tmpfile = "$userspath/$boundary.$myconfig->{dbname}-$form->{dbversion}.sql";
532     $out = $form->{OUT};
533     $form->{OUT} = ">$tmpfile";
534     
535     use SL::Mailer;
536     $mail = new Mailer;
537
538     $mail->{to} = qq|"$myconfig->{name}" <$myconfig->{email}>|;
539     $mail->{from} = qq|"$myconfig->{name}" <$myconfig->{email}>|;
540     $mail->{subject} = "SQL-Ledger Backup / $myconfig->{dbname}-$form->{dbversion}.sql";
541     @{ $mail->{attachments} } = ($tmpfile);
542     $mail->{version} = $form->{version};
543     $mail->{fileid} = "$boundary.";
544
545     $myconfig->{signature} =~ s/\\n/\r\n/g;
546     $mail->{message} = "--\n$myconfig->{signature}";
547     
548   }
549     
550   if ($form->{OUT}) {
551     open(OUT, "$form->{OUT}") or $form->error("$form->{OUT} : $!");
552   } else {
553     open(OUT, ">-") or $form->error("STDOUT : $!");
554   }
555
556   if ($form->{media} eq 'file') {
557     print OUT qq|Content-Type: Application/File;
558 Content-Disposition: filename="$myconfig->{dbname}-$form->{dbversion}.sql"\n\n|;
559   }
560
561   # connect to database
562   my $dbh = $form->dbconnect($myconfig);
563
564   # get all the tables
565   my @tables = $dbh->tables;
566   
567   my $today = scalar localtime;
568   
569
570   $myconfig->{dbhost} = 'localhost' unless $myconfig->{dbhost};
571   
572   print OUT qq|-- SQL-Ledger Backup
573 -- Dataset: $myconfig->{dbname}
574 -- Version: $form->{dbversion}
575 -- Host: $myconfig->{dbhost}
576 -- Login: $form->{login}
577 -- User: $myconfig->{name}
578 -- Date: $today
579 --
580 -- set options
581 $myconfig->{dboptions};
582 --
583 |;
584
585   foreach $table (@tables) {
586     my $query = qq|SELECT * FROM $table|;
587     
588     my $sth = $dbh->prepare($query);
589     $sth->execute || $form->dberror($query);
590
591     $query = qq|INSERT INTO $table (|;
592     map { $query .= qq|$sth->{NAME}->[$_],| } (0 .. $sth->{NUM_OF_FIELDS} - 1);
593     chop $query;
594
595     $query .= qq|) VALUES|;
596     
597     print OUT qq|--
598 DELETE FROM $table;
599 |;
600     while (my @arr = $sth->fetchrow_array) {
601
602       $fields = "(";
603       foreach my $item (@arr) {
604         if (defined $item) {
605           $item =~ s/'/''/g;
606           $fields .= qq|'$item',|;
607         } else {
608           $fields .= 'NULL,';
609         }
610       }
611         
612       chop $fields;
613       $fields .= ")";
614         
615       print OUT qq|$query $fields;\n|;
616     }
617     
618     $sth->finish;
619   }
620
621   $query = qq|SELECT last_value FROM id|;
622   $sth = $dbh->prepare($query);
623   $sth->execute || $form->dberror($query);
624
625   my ($id) = $sth->fetchrow_array;
626   $sth->finish;
627   
628   print OUT qq|--
629 DROP SEQUENCE id;
630 CREATE SEQUENCE id START $id;
631 |;
632   
633   close(OUT);
634   
635   $dbh->disconnect;
636
637   if ($form->{media} eq 'email') {
638     my $err = $mail->send($out);
639     $_ = $tmpfile;
640     unlink;
641   }
642     
643 }
644
645
646 sub closedto {
647   my ($self, $myconfig, $form) = @_;
648
649   my $dbh = $form->dbconnect($myconfig);
650
651   my $query = qq|SELECT closedto, revtrans FROM defaults|;
652   my $sth = $dbh->prepare($query);
653   $sth->execute || $form->dberror($query);
654
655   ($form->{closedto}, $form->{revtrans}) = $sth->fetchrow_array;
656   
657   $sth->finish;
658   
659   $dbh->disconnect;
660
661 }
662
663  
664 sub closebooks {
665   my ($self, $myconfig, $form) = @_;
666
667   my $dbh = $form->dbconnect($myconfig);
668
669   if ($form->{revtrans}) {
670    
671     $query = qq|UPDATE defaults SET closedto = NULL,
672                                     revtrans = '1'|;
673   } else {
674     if ($form->{closedto}) {
675     
676       $query = qq|UPDATE defaults SET closedto = '$form->{closedto}',
677                                       revtrans = '0'|;
678     } else {
679       
680       $query = qq|UPDATE defaults SET closedto = NULL,
681                                       revtrans = '0'|;
682     }
683   }
684
685   # set close in defaults
686   $dbh->do($query) || $form->dberror($query);
687   
688   $dbh->disconnect;
689   
690 }
691
692
693 1;
694