import sql-ledger 2.4.4
[freeside.git] / sql-ledger / SL / AM.pm
1 #=====================================================================
2 # SQL-Ledger Accounting
3 # Copyright (C) 2000
4 #
5 #  Author: Dieter Simader
6 #   Email: dsimader@sql-ledger.org
7 #     Web: http://www.sql-ledger.org
8 #
9 #  Contributors: Jim Rawlings <jim@your-dba.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 # 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   # get default accounts
55   $query = qq|SELECT inventory_accno_id, income_accno_id, expense_accno_id
56               FROM defaults|;
57   $sth = $dbh->prepare($query);
58   $sth->execute || $form->dberror($query);
59
60   $ref = $sth->fetchrow_hashref(NAME_lc);
61   map { $form->{$_} = $ref->{$_} } keys %ref;
62   $sth->finish;
63
64   # check if we have any transactions
65   $query = qq|SELECT trans_id FROM acc_trans
66               WHERE chart_id = $form->{id}|;
67   ($form->{orphaned}) = $dbh->selectrow_array($query);
68   $form->{orphaned} = !$form->{orphaned};
69
70   $dbh->disconnect;
71
72 }
73
74
75 sub save_account {
76   my ($self, $myconfig, $form) = @_;
77
78   # connect to database, turn off AutoCommit
79   my $dbh = $form->dbconnect_noauto($myconfig);
80
81   $form->{link} = "";
82   foreach my $item ($form->{AR},
83                     $form->{AR_amount},
84                     $form->{AR_tax},
85                     $form->{AR_paid},
86                     $form->{AP},
87                     $form->{AP_amount},
88                     $form->{AP_tax},
89                     $form->{AP_paid},
90                     $form->{IC},
91                     $form->{IC_sale},
92                     $form->{IC_cogs},
93                     $form->{IC_taxpart},
94                     $form->{IC_income},
95                     $form->{IC_expense},
96                     $form->{IC_taxservice},
97                     $form->{CT_tax}
98                     ) {
99      $form->{link} .= "${item}:" if ($item);
100   }
101   chop $form->{link};
102
103   # strip blanks from accno
104   map { $form->{$_} =~ s/( |')//g } qw(accno gifi_accno);
105   
106   foreach my $item (qw(accno gifi_accno description)) {
107     $form->{$item} =~ s/-(-+)/-/g;
108     $form->{$item} =~ s/ ( )+/ /g;
109   }
110   
111   my $query;
112   my $sth;
113   
114   # if we have an id then replace the old record
115   if ($form->{id}) {
116     $query = qq|UPDATE chart SET
117                 accno = '$form->{accno}',
118                 description = |.$dbh->quote($form->{description}).qq|,
119                 charttype = '$form->{charttype}',
120                 gifi_accno = '$form->{gifi_accno}',
121                 category = '$form->{category}',
122                 link = '$form->{link}'
123                 WHERE id = $form->{id}|;
124   } else {
125     $query = qq|INSERT INTO chart 
126                 (accno, description, charttype, gifi_accno, category, link)
127                 VALUES ('$form->{accno}',|
128                 .$dbh->quote($form->{description}).qq|,
129                 '$form->{charttype}', '$form->{gifi_accno}',
130                 '$form->{category}', '$form->{link}')|;
131   }
132   $dbh->do($query) || $form->dberror($query);
133
134
135   $chart_id = $form->{id};
136
137   if (! $form->{id}) {
138     # get id from chart
139     $query = qq|SELECT id
140                 FROM chart
141                 WHERE accno = '$form->{accno}'|;
142     ($chart_id) = $dbh->selectrow_array($query);
143   }
144
145   if ($form->{IC_taxpart} || $form->{IC_taxservice} || $form->{CT_tax}) {
146    
147     # add account if it doesn't exist in tax
148     $query = qq|SELECT chart_id
149                 FROM tax
150                 WHERE chart_id = $chart_id|;
151     my ($tax_id) = $dbh->selectrow_array($query);
152     
153     # add tax if it doesn't exist
154     unless ($tax_id) {
155       $query = qq|INSERT INTO tax (chart_id, rate)
156                   VALUES ($chart_id, 0)|;
157       $dbh->do($query) || $form->dberror($query);
158     }
159   } else {
160     # remove tax
161     if ($form->{id}) {
162       $query = qq|DELETE FROM tax
163                   WHERE chart_id = $form->{id}|;
164       $dbh->do($query) || $form->dberror($query);
165     }
166   }
167
168   # commit
169   my $rc = $dbh->commit;
170   $dbh->disconnect;
171
172   $rc;
173   
174 }
175
176
177
178 sub delete_account {
179   my ($self, $myconfig, $form) = @_;
180
181   # connect to database, turn off AutoCommit
182   my $dbh = $form->dbconnect_noauto($myconfig);
183   
184   my $query = qq|SELECT * FROM acc_trans
185                  WHERE chart_id = $form->{id}|;
186   if ($dbh->selectrow_array($query)) {
187     $dbh->disconnect;
188     return;
189   }
190
191
192   # delete chart of account record
193   $query = qq|DELETE FROM chart
194               WHERE id = $form->{id}|;
195   $dbh->do($query) || $form->dberror($query);
196
197   # set inventory_accno_id, income_accno_id, expense_accno_id to defaults
198   $query = qq|UPDATE parts
199               SET inventory_accno_id = 
200                          (SELECT inventory_accno_id FROM defaults)
201               WHERE inventory_accno_id = $form->{id}|;
202   $dbh->do($query) || $form->dberror($query);
203   
204   $query = qq|UPDATE parts
205               SET income_accno_id =
206                          (SELECT income_accno_id FROM defaults)
207               WHERE income_accno_id = $form->{id}|;
208   $dbh->do($query) || $form->dberror($query);
209   
210   $query = qq|UPDATE parts
211               SET expense_accno_id =
212                          (SELECT expense_accno_id FROM defaults)
213               WHERE expense_accno_id = $form->{id}|;
214   $dbh->do($query) || $form->dberror($query);
215   
216   foreach my $table (qw(partstax customertax vendortax tax)) {
217     $query = qq|DELETE FROM $table
218                 WHERE chart_id = $form->{id}|;
219     $dbh->do($query) || $form->dberror($query);
220   }
221
222   # commit and redirect
223   my $rc = $dbh->commit;
224   $dbh->disconnect;
225   
226   $rc;
227
228 }
229
230
231 sub gifi_accounts {
232   my ($self, $myconfig, $form) = @_;
233   
234   # connect to database
235   my $dbh = $form->dbconnect($myconfig);
236
237   my $query = qq|SELECT accno, description
238                  FROM gifi
239                  ORDER BY accno|;
240
241   $sth = $dbh->prepare($query);
242   $sth->execute || $form->dberror($query);
243
244   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
245     push @{ $form->{ALL} }, $ref;
246   }
247
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
264   ($form->{accno}, $form->{description}) = $dbh->selectrow_array($query);
265
266   # check for transactions
267   $query = qq|SELECT * FROM acc_trans a
268               JOIN chart c ON (a.chart_id = c.id)
269               JOIN gifi g ON (c.gifi_accno = g.accno)
270               WHERE g.accno = '$form->{accno}'|;
271   ($form->{orphaned}) = $dbh->selectrow_array($query);
272   $form->{orphaned} = !$form->{orphaned};
273
274   $dbh->disconnect;
275
276 }
277
278
279 sub save_gifi {
280   my ($self, $myconfig, $form) = @_;
281   
282   # connect to database
283   my $dbh = $form->dbconnect($myconfig);
284   
285   $form->{accno} =~ s/( |')//g;
286   
287   foreach my $item (qw(accno description)) {
288     $form->{$item} =~ s/-(-+)/-/g;
289     $form->{$item} =~ s/ ( )+/ /g;
290   }
291
292   # id is the old account number!
293   if ($form->{id}) {
294     $query = qq|UPDATE gifi SET
295                 accno = '$form->{accno}',
296                 description = |.$dbh->quote($form->{description}).qq|
297                 WHERE accno = '$form->{id}'|;
298   } else {
299     $query = qq|INSERT INTO gifi 
300                 (accno, description)
301                 VALUES ('$form->{accno}',|
302                 .$dbh->quote($form->{description}).qq|)|;
303   }
304   $dbh->do($query) || $form->dberror; 
305   
306   $dbh->disconnect;
307
308 }
309
310
311 sub delete_gifi {
312   my ($self, $myconfig, $form) = @_;
313   
314   # connect to database
315   my $dbh = $form->dbconnect($myconfig);
316   
317   # id is the old account number!
318   $query = qq|DELETE FROM gifi
319               WHERE accno = '$form->{id}'|;
320   $dbh->do($query) || $form->dberror($query);
321   
322   $dbh->disconnect;
323
324 }
325
326
327 sub warehouses {
328   my ($self, $myconfig, $form) = @_;
329   
330   # connect to database
331   my $dbh = $form->dbconnect($myconfig);
332
333   $form->sort_order();
334   my $query = qq|SELECT id, description
335                  FROM warehouse
336                  ORDER BY 2 $form->{direction}|;
337
338   $sth = $dbh->prepare($query);
339   $sth->execute || $form->dberror($query);
340
341   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
342     push @{ $form->{ALL} }, $ref;
343   }
344
345   $dbh->disconnect;
346   
347 }
348
349
350
351 sub get_warehouse {
352   my ($self, $myconfig, $form) = @_;
353
354   # connect to database
355   my $dbh = $form->dbconnect($myconfig);
356   
357   my $query = qq|SELECT description
358                  FROM warehouse
359                  WHERE id = $form->{id}|;
360   ($form->{description}) = $dbh->selectrow_array($query);
361
362   # see if it is in use
363   $query = qq|SELECT * FROM inventory
364               WHERE warehouse_id = $form->{id}|;
365   ($form->{orphaned}) = $dbh->selectrow_array($query);
366   $form->{orphaned} = !$form->{orphaned};
367
368   $dbh->disconnect;
369
370 }
371
372
373 sub save_warehouse {
374   my ($self, $myconfig, $form) = @_;
375   
376   # connect to database
377   my $dbh = $form->dbconnect($myconfig);
378   
379   $form->{description} =~ s/-(-)+/-/g;
380   $form->{description} =~ s/ ( )+/ /g;
381
382   if ($form->{id}) {
383     $query = qq|UPDATE warehouse SET
384                 description = |.$dbh->quote($form->{description}).qq|
385                 WHERE id = $form->{id}|;
386   } else {
387     $query = qq|INSERT INTO warehouse
388                 (description)
389                 VALUES (|.$dbh->quote($form->{description}).qq|)|;
390   }
391   $dbh->do($query) || $form->dberror($query);
392   
393   $dbh->disconnect;
394
395 }
396
397
398 sub delete_warehouse {
399   my ($self, $myconfig, $form) = @_;
400   
401   # connect to database
402   my $dbh = $form->dbconnect($myconfig);
403   
404   $query = qq|DELETE FROM warehouse
405               WHERE id = $form->{id}|;
406   $dbh->do($query) || $form->dberror($query);
407   
408   $dbh->disconnect;
409
410 }
411
412
413
414 sub departments {
415   my ($self, $myconfig, $form) = @_;
416   
417   # connect to database
418   my $dbh = $form->dbconnect($myconfig);
419
420   $form->sort_order();
421   my $query = qq|SELECT id, description, role
422                  FROM department
423                  ORDER BY 2 $form->{direction}|;
424
425   $sth = $dbh->prepare($query);
426   $sth->execute || $form->dberror($query);
427
428   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
429     push @{ $form->{ALL} }, $ref;
430   }
431
432   $dbh->disconnect;
433   
434 }
435
436
437
438 sub get_department {
439   my ($self, $myconfig, $form) = @_;
440
441   # connect to database
442   my $dbh = $form->dbconnect($myconfig);
443   
444   my $query = qq|SELECT description, role
445                  FROM department
446                  WHERE id = $form->{id}|;
447   ($form->{description}, $form->{role}) = $dbh->selectrow_array($query);
448   
449   map { $form->{$_} = $ref->{$_} } keys %$ref;
450
451   # see if it is in use
452   $query = qq|SELECT * FROM dpt_trans
453               WHERE department_id = $form->{id}|;
454   ($form->{orphaned}) = $dbh->selectrow_array($query);
455   $form->{orphaned} = !$form->{orphaned};
456
457   $dbh->disconnect;
458
459 }
460
461
462 sub save_department {
463   my ($self, $myconfig, $form) = @_;
464   
465   # connect to database
466   my $dbh = $form->dbconnect($myconfig);
467
468   $form->{description} =~ s/-(-)+/-/g;
469   $form->{description} =~ s/ ( )+/ /g;
470
471   if ($form->{id}) {
472     $query = qq|UPDATE department SET
473                 description = |.$dbh->quote($form->{description}).qq|,
474                 role = '$form->{role}'
475                 WHERE id = $form->{id}|;
476   } else {
477     $query = qq|INSERT INTO department 
478                 (description, role)
479                 VALUES (|
480                 .$dbh->quote($form->{description}).qq|, '$form->{role}')|;
481   }
482   $dbh->do($query) || $form->dberror($query);
483   
484   $dbh->disconnect;
485
486 }
487
488
489 sub delete_department {
490   my ($self, $myconfig, $form) = @_;
491   
492   # connect to database
493   my $dbh = $form->dbconnect($myconfig);
494   
495   $query = qq|DELETE FROM department
496               WHERE id = $form->{id}|;
497   $dbh->do($query);
498   
499   $dbh->disconnect;
500
501 }
502
503
504 sub business {
505   my ($self, $myconfig, $form) = @_;
506   
507   # connect to database
508   my $dbh = $form->dbconnect($myconfig);
509
510   $form->sort_order();
511   my $query = qq|SELECT id, description, discount
512                  FROM business
513                  ORDER BY 2 $form->{direction}|;
514
515   $sth = $dbh->prepare($query);
516   $sth->execute || $form->dberror($query);
517
518   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
519     push @{ $form->{ALL} }, $ref;
520   }
521
522   $dbh->disconnect;
523   
524 }
525
526
527
528 sub get_business {
529   my ($self, $myconfig, $form) = @_;
530
531   # connect to database
532   my $dbh = $form->dbconnect($myconfig);
533   
534   my $query = qq|SELECT description, discount
535                  FROM business
536                  WHERE id = $form->{id}|;
537   ($form->{description}, $form->{discount}) = $dbh->selectrow_array($query);
538
539   $dbh->disconnect;
540
541 }
542
543
544 sub save_business {
545   my ($self, $myconfig, $form) = @_;
546   
547   # connect to database
548   my $dbh = $form->dbconnect($myconfig);
549   
550   $form->{description} =~ s/-(-)+/-/g;
551   $form->{description} =~ s/ ( )+/ /g;
552   $form->{discount} /= 100;
553   
554   if ($form->{id}) {
555     $query = qq|UPDATE business SET
556                 description = |.$dbh->quote($form->{description}).qq|,
557                 discount = $form->{discount}
558                 WHERE id = $form->{id}|;
559   } else {
560     $query = qq|INSERT INTO business 
561                 (description, discount)
562                 VALUES (|
563                 .$dbh->quote($form->{description}).qq|, $form->{discount})|;
564   }
565   $dbh->do($query) || $form->dberror($query);
566   
567   $dbh->disconnect;
568
569 }
570
571
572 sub delete_business {
573   my ($self, $myconfig, $form) = @_;
574   
575   # connect to database
576   my $dbh = $form->dbconnect($myconfig);
577   
578   $query = qq|DELETE FROM business
579               WHERE id = $form->{id}|;
580   $dbh->do($query) || $form->dberror($query);
581   
582   $dbh->disconnect;
583
584 }
585
586
587 sub sic {
588   my ($self, $myconfig, $form) = @_;
589   
590   # connect to database
591   my $dbh = $form->dbconnect($myconfig);
592
593   $form->{sort} = "code" unless $form->{sort};
594   my @a = qw(code description);
595   my %ordinal = ( code          => 1,
596                   description   => 3 );
597   my $sortorder = $form->sort_order(\@a, \%ordinal);
598   my $query = qq|SELECT code, sictype, description
599                  FROM sic
600                  ORDER BY $sortorder|;
601
602   $sth = $dbh->prepare($query);
603   $sth->execute || $form->dberror($query);
604
605   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
606     push @{ $form->{ALL} }, $ref;
607   }
608
609   $dbh->disconnect;
610   
611 }
612
613
614
615 sub get_sic {
616   my ($self, $myconfig, $form) = @_;
617
618   # connect to database
619   my $dbh = $form->dbconnect($myconfig);
620   
621   my $query = qq|SELECT code, sictype, description
622                  FROM sic
623                  WHERE code = |.$dbh->quote($form->{code});
624   my $sth = $dbh->prepare($query);
625   $sth->execute || $form->dberror($query);
626
627   my $ref = $sth->fetchrow_hashref(NAME_lc);
628   
629   map { $form->{$_} = $ref->{$_} } keys %$ref;
630
631   $sth->finish;
632   $dbh->disconnect;
633
634 }
635
636
637 sub save_sic {
638   my ($self, $myconfig, $form) = @_;
639   
640   # connect to database
641   my $dbh = $form->dbconnect($myconfig);
642   
643   foreach my $item (qw(code description)) {
644     $form->{$item} =~ s/-(-)+/-/g;
645   }
646  
647   # if there is an id
648   if ($form->{id}) {
649     $query = qq|UPDATE sic SET
650                 code = |.$dbh->quote($form->{code}).qq|,
651                 sictype = '$form->{sictype}',
652                 description = |.$dbh->quote($form->{description}).qq|
653                 WHERE code = |.$dbh->quote($form->{id});
654   } else {
655     $query = qq|INSERT INTO sic 
656                 (code, sictype, description)
657                 VALUES (|
658                 .$dbh->quote($form->{code}).qq|,
659                 '$form->{sictype}',|
660                 .$dbh->quote($form->{description}).qq|)|;
661   }
662   $dbh->do($query) || $form->dberror($query);
663   
664   $dbh->disconnect;
665
666 }
667
668
669 sub delete_sic {
670   my ($self, $myconfig, $form) = @_;
671   
672   # connect to database
673   my $dbh = $form->dbconnect($myconfig);
674   
675   $query = qq|DELETE FROM sic
676               WHERE code = |.$dbh->quote($form->{code});
677   $dbh->do($query);
678   
679   $dbh->disconnect;
680
681 }
682
683
684 sub language {
685   my ($self, $myconfig, $form) = @_;
686   
687   # connect to database
688   my $dbh = $form->dbconnect($myconfig);
689
690   $form->{sort} = "code" unless $form->{sort};
691   my @a = qw(code description);
692   my %ordinal = ( code          => 1,
693                   description   => 2 );
694   my $sortorder = $form->sort_order(\@a, \%ordinal);
695   
696   my $query = qq|SELECT code, description
697                  FROM language
698                  ORDER BY $sortorder|;
699   $sth = $dbh->prepare($query);
700   $sth->execute || $form->dberror($query);
701
702   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
703     push @{ $form->{ALL} }, $ref;
704   }
705
706   $dbh->disconnect;
707   
708 }
709
710
711
712 sub get_language {
713   my ($self, $myconfig, $form) = @_;
714
715   # connect to database
716   my $dbh = $form->dbconnect($myconfig);
717   
718   my $query = qq|SELECT *
719                  FROM language
720                  WHERE code = |.$dbh->quote($form->{code});
721   my $sth = $dbh->prepare($query);
722   $sth->execute || $form->dberror($query);
723
724   my $ref = $sth->fetchrow_hashref(NAME_lc);
725   
726   map { $form->{$_} = $ref->{$_} } keys %$ref;
727
728   $sth->finish;
729
730   $dbh->disconnect;
731
732 }
733
734
735 sub save_language {
736   my ($self, $myconfig, $form) = @_;
737   
738   # connect to database
739   my $dbh = $form->dbconnect($myconfig);
740
741   $form->{code} =~ s/ //g;
742   foreach my $item (qw(code description)) {
743     $form->{$item} =~ s/-(-)+/-/g;
744     $form->{$item} =~ s/ ( )+/-/g;
745   }
746   
747   # if there is an id
748   if ($form->{id}) {
749     $query = qq|UPDATE language SET
750                 code = |.$dbh->quote($form->{code}).qq|,
751                 description = |.$dbh->quote($form->{description}).qq|
752                 WHERE code = |.$dbh->quote($form->{id});
753   } else {
754     $query = qq|INSERT INTO language
755                 (code, description)
756                 VALUES (|
757                 .$dbh->quote($form->{code}).qq|,|
758                 .$dbh->quote($form->{description}).qq|)|;
759   }
760   $dbh->do($query) || $form->dberror($query);
761   
762   $dbh->disconnect;
763
764 }
765
766
767 sub delete_language {
768   my ($self, $myconfig, $form) = @_;
769   
770   # connect to database
771   my $dbh = $form->dbconnect($myconfig);
772   
773   $query = qq|DELETE FROM language
774               WHERE code = |.$dbh->quote($form->{code});
775   $dbh->do($query) || $form->dberror($query);
776   
777   $dbh->disconnect;
778
779 }
780
781
782
783 sub load_template {
784   my ($self, $form) = @_;
785   
786   open(TEMPLATE, "$form->{file}") or $form->error("$form->{file} : $!");
787
788   while (<TEMPLATE>) {
789     $form->{body} .= $_;
790   }
791
792   close(TEMPLATE);
793
794 }
795
796
797 sub save_template {
798   my ($self, $form) = @_;
799   
800   open(TEMPLATE, ">$form->{file}") or $form->error("$form->{file} : $!");
801   
802   # strip \r
803   $form->{body} =~ s/\r\n/\n/g;
804   print TEMPLATE $form->{body};
805
806   close(TEMPLATE);
807
808 }
809
810
811
812 sub save_preferences {
813   my ($self, $myconfig, $form, $memberfile, $userspath) = @_;
814
815   # connect to database
816   my $dbh = $form->dbconnect($myconfig);
817   
818   # update name
819   my $query = qq|UPDATE employee
820                  SET name = |.$dbh->quote($form->{name}).qq|,
821                  role = '$form->{role}'
822                  WHERE login = '$form->{login}'|;
823   $dbh->do($query) || $form->dberror($query);
824   
825   # get default currency
826   $query = qq|SELECT curr, businessnumber
827               FROM defaults|;
828   ($form->{currency}, $form->{businessnumber}) = $dbh->selectrow_array($query);
829   $form->{currency} =~ s/:.*//;
830   
831   $dbh->disconnect;
832
833   my $myconfig = new User "$memberfile", "$form->{login}";
834   
835   foreach my $item (keys %$form) {
836     $myconfig->{$item} = $form->{$item};
837   }
838   
839   $myconfig->{password} = $form->{new_password} if ($form->{old_password} ne $form->{new_password});
840
841   $myconfig->save_member($memberfile, $userspath);
842
843   1;
844
845 }
846
847
848 sub save_defaults {
849   my ($self, $myconfig, $form) = @_;
850
851   map { ($form->{$_}) = split /--/, $form->{$_} } qw(inventory_accno income_accno expense_accno fxgain_accno fxloss_accno);
852   
853   my @a;
854   $form->{curr} =~ s/ //g;
855   map { push(@a, uc pack "A3", $_) if $_ } split /:/, $form->{curr};
856   $form->{curr} = join ':', @a;
857     
858   # connect to database
859   my $dbh = $form->dbconnect_noauto($myconfig);
860   
861   # save defaults
862   my $query = qq|UPDATE defaults SET
863                  inventory_accno_id = 
864                      (SELECT id FROM chart
865                                 WHERE accno = '$form->{inventory_accno}'),
866                  income_accno_id =
867                      (SELECT id FROM chart
868                                 WHERE accno = '$form->{income_accno}'),
869                  expense_accno_id =
870                      (SELECT id FROM chart
871                                 WHERE accno = '$form->{expense_accno}'),
872                  fxgain_accno_id =
873                      (SELECT id FROM chart
874                                 WHERE accno = '$form->{fxgain_accno}'),
875                  fxloss_accno_id =
876                      (SELECT id FROM chart
877                                 WHERE accno = '$form->{fxloss_accno}'),
878                  sinumber = '$form->{sinumber}',
879                  vinumber = '$form->{vinumber}',
880                  sonumber = '$form->{sonumber}',
881                  ponumber = '$form->{ponumber}',
882                  sqnumber = '$form->{sqnumber}',
883                  rfqnumber = '$form->{rfqnumber}',
884                  partnumber = '$form->{partnumber}',
885                  employeenumber = '$form->{employeenumber}',
886                  customernumber = '$form->{customernumber}',
887                  vendornumber = '$form->{vendornumber}',
888                  yearend = '$form->{yearend}',
889                  curr = '$form->{curr}',
890                  weightunit = |.$dbh->quote($form->{weightunit}).qq|,
891                  businessnumber = |.$dbh->quote($form->{businessnumber});
892   $dbh->do($query) || $form->dberror($query);
893
894   foreach my $item (split / /, $form->{taxaccounts}) {
895     $form->{$item} = $form->parse_amount($myconfig, $form->{$item}) / 100;
896     $query = qq|UPDATE tax
897                 SET rate = $form->{$item},
898                 taxnumber = |.$dbh->quote($form->{"taxnumber_$item"}).qq|
899                 WHERE chart_id = $item|;
900     $dbh->do($query) || $form->dberror($query);
901   }
902
903   my $rc = $dbh->commit;
904   $dbh->disconnect;
905
906   $rc;
907   
908 }
909
910
911 sub defaultaccounts {
912   my ($self, $myconfig, $form) = @_;
913   
914   # connect to database
915   my $dbh = $form->dbconnect($myconfig);
916   
917   # get defaults from defaults table
918   my $query = qq|SELECT * FROM defaults|;
919   my $sth = $dbh->prepare($query);
920   $sth->execute || $form->dberror($query);
921   
922   $form->{defaults} = $sth->fetchrow_hashref(NAME_lc);
923   $form->{defaults}{IC} = $form->{defaults}{inventory_accno_id};
924   $form->{defaults}{IC_income} = $form->{defaults}{income_accno_id};
925   $form->{defaults}{IC_expense} = $form->{defaults}{expense_accno_id};
926   $form->{defaults}{FX_gain} = $form->{defaults}{fxgain_accno_id};
927   $form->{defaults}{FX_loss} = $form->{defaults}{fxloss_accno_id};
928   
929   
930   $sth->finish;
931
932
933   $query = qq|SELECT id, accno, description, link
934               FROM chart
935               WHERE link LIKE '%IC%'
936               ORDER BY accno|;
937   $sth = $dbh->prepare($query);
938   $sth->execute || $form->dberror($query);
939
940   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
941     foreach my $key (split(/:/, $ref->{link})) {
942       if ($key =~ /IC/) {
943         $nkey = $key;
944         if ($key =~ /cogs/) {
945           $nkey = "IC_expense";
946         }
947         if ($key =~ /sale/) {
948           $nkey = "IC_income";
949         }
950         %{ $form->{IC}{$nkey}{$ref->{accno}} } = ( id => $ref->{id},
951                                         description => $ref->{description} );
952       }
953     }
954   }
955   $sth->finish;
956
957
958   $query = qq|SELECT id, accno, description
959               FROM chart
960               WHERE category = 'I'
961               AND charttype = 'A'
962               ORDER BY accno|;
963   $sth = $dbh->prepare($query);
964   $sth->execute || $form->dberror($query);
965
966   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
967     %{ $form->{IC}{FX_gain}{$ref->{accno}} } = ( id => $ref->{id},
968                                       description => $ref->{description} );
969   }
970   $sth->finish;
971
972   $query = qq|SELECT id, accno, description
973               FROM chart
974               WHERE category = 'E'
975               AND charttype = 'A'
976               ORDER BY accno|;
977   $sth = $dbh->prepare($query);
978   $sth->execute || $form->dberror($query);
979
980   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
981     %{ $form->{IC}{FX_loss}{$ref->{accno}} } = ( id => $ref->{id},
982                                       description => $ref->{description} );
983   }
984   $sth->finish;
985
986
987   # now get the tax rates and numbers
988   $query = qq|SELECT chart.id, chart.accno, chart.description,
989               tax.rate * 100 AS rate, tax.taxnumber
990               FROM chart, tax
991               WHERE chart.id = tax.chart_id|;
992
993   $sth = $dbh->prepare($query);
994   $sth->execute || $form->dberror($query);
995
996   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
997     $form->{taxrates}{$ref->{accno}}{id} = $ref->{id};
998     $form->{taxrates}{$ref->{accno}}{description} = $ref->{description};
999     $form->{taxrates}{$ref->{accno}}{taxnumber} = $ref->{taxnumber} if $ref->{taxnumber};
1000     $form->{taxrates}{$ref->{accno}}{rate} = $ref->{rate} if $ref->{rate};
1001   }
1002
1003   $sth->finish;
1004   $dbh->disconnect;
1005   
1006 }
1007
1008
1009 sub backup {
1010   my ($self, $myconfig, $form, $userspath, $gzip) = @_;
1011   
1012   my $mail;
1013   my $err;
1014   
1015   my @t = localtime(time);
1016   $t[4]++;
1017   $t[5] += 1900;
1018   $t[3] = substr("0$t[3]", -2);
1019   $t[4] = substr("0$t[4]", -2);
1020
1021   my $boundary = time;
1022   my $tmpfile = "$userspath/$boundary.$myconfig->{dbname}-$form->{dbversion}-$t[5]$t[4]$t[3].sql";
1023   my $out = $form->{OUT};
1024   $form->{OUT} = ">$tmpfile";
1025
1026   open(OUT, "$form->{OUT}") or $form->error("$form->{OUT} : $!");
1027
1028   # get sequences, functions and triggers
1029   my @tables = ();
1030   my @sequences = ();
1031   my @functions = ();
1032   my @triggers = ();
1033   my @schema = ();
1034   
1035   # get dbversion from -tables.sql
1036   my $file = "$myconfig->{dbdriver}-tables.sql";
1037
1038   open(FH, "sql/$file") or $form->error("sql/$file : $!");
1039
1040   my @a = <FH>;
1041   close(FH);
1042
1043   @dbversion = grep /defaults \(version\)/, @a;
1044   
1045   $dbversion = "@dbversion";
1046   $dbversion =~ /(\d+\.\d+\.\d+)/;
1047   $dbversion = User::calc_version($1);
1048   
1049   opendir SQLDIR, "sql/." or $form->error($!);
1050   @a = grep /$myconfig->{dbdriver}-upgrade-.*?\.sql$/, readdir SQLDIR;
1051   closedir SQLDIR;
1052
1053   my $mindb;
1054   my $maxdb;
1055   
1056   foreach my $line (@a) {
1057
1058     $upgradescript = $line;
1059     $line =~ s/(^$myconfig->{dbdriver}-upgrade-|\.sql$)//g;
1060     
1061     ($mindb, $maxdb) = split /-/, $line;
1062     $mindb = User::calc_version($mindb);
1063
1064     next if $mindb < $dbversion;
1065     
1066     $maxdb = User::calc_version($maxdb);
1067     
1068     $upgradescripts{$maxdb} = $upgradescript;
1069   }
1070
1071
1072   $upgradescripts{$dbversion} = "$myconfig->{dbdriver}-tables.sql";
1073   $upgradescripts{functions} = "$myconfig->{dbdriver}-functions.sql";
1074
1075   if (-f "sql/$myconfig->{dbdriver}-custom_tables.sql") {
1076     $upgradescripts{customtables} = "$myconfig->{dbdriver}-custom_tables.sql";
1077   }
1078   if (-f "sql/$myconfig->{dbdriver}-custom_functions.sql") {
1079     $upgradescripts{customfunctions} = "$myconfig->{dbdriver}-custom_functions.sql";
1080   }
1081   
1082   foreach my $key (sort keys %upgradescripts) {
1083
1084     $file = $upgradescripts{$key};
1085   
1086     open(FH, "sql/$file") or $form->error("sql/$file : $!");
1087
1088     push @schema, qq|-- $file\n|;
1089    
1090     while (<FH>) {
1091
1092       if (/create table (\w+)/i) {
1093         push @tables, $1;
1094       }
1095
1096       if (/create sequence (\w+)/i) {
1097         push @sequences, $1;
1098       }
1099
1100       if (/end function/i) {
1101         push @functions, $_;
1102         $function = 0;
1103         next;
1104       }
1105
1106       if (/create function /i) {
1107         $function = 1;
1108       }
1109       
1110       if ($function) {
1111         push @functions, $_;
1112         next;
1113       }
1114
1115       if (/end trigger/i) {
1116         push @triggers, $_;
1117         $trigger = 0;
1118         next;
1119       }
1120
1121       if (/create trigger/i) {
1122         $trigger = 1;
1123       }
1124
1125       if ($trigger) {
1126         push @triggers, $_;
1127         next;
1128       }
1129       
1130       push @schema, $_ if $_ !~ /^(insert|--)/i;
1131       
1132     }
1133     close(FH);
1134     
1135   }
1136
1137
1138   # connect to database
1139   my $dbh = $form->dbconnect($myconfig);
1140
1141   my $today = scalar localtime;
1142
1143   $myconfig->{dbhost} = 'localhost' unless $myconfig->{dbhost};
1144   
1145   print OUT qq|-- SQL-Ledger Backup
1146 -- Dataset: $myconfig->{dbname}
1147 -- Version: $form->{dbversion}
1148 -- Host: $myconfig->{dbhost}
1149 -- Login: $form->{login}
1150 -- User: $myconfig->{name}
1151 -- Date: $today
1152 --
1153 |;
1154
1155  
1156   my $restrict = ($myconfig->{dbdriver} eq 'DB2') ? "RESTRICT" : "";
1157   
1158   @tables = grep !/^temp/, @tables;
1159   # drop tables and sequences
1160   map { print OUT qq|DROP TABLE $_;\n| } @tables;
1161   map { print OUT qq|DROP SEQUENCE $_ $restrict;\n| } @sequences;
1162
1163   print OUT "--\n";
1164   
1165   # triggers and index files are dropped with the tables
1166   
1167   # drop functions
1168   foreach $item (@functions) {
1169     if ($item =~ /create function (.*\))/i) {
1170       print OUT qq|DROP FUNCTION $1;\n|;
1171     }
1172   }
1173   
1174   # add schema
1175   print OUT @schema;
1176   print OUT "\n";
1177   
1178   print OUT qq|-- set options
1179 $myconfig->{dboptions};
1180 --
1181 |;
1182
1183   my $query;
1184   my $sth;
1185   my @arr;
1186   my $fields;
1187   
1188   foreach $table (@tables) {
1189
1190     $query = qq|SELECT * FROM $table|;
1191     $sth = $dbh->prepare($query);
1192     $sth->execute || $form->dberror($query);
1193
1194     $query = qq|INSERT INTO $table (|;
1195     $query .= join ',', (map { $sth->{NAME}->[$_] } (0 .. $sth->{NUM_OF_FIELDS} - 1));
1196     $query .= qq|) VALUES|;
1197     
1198     while (@arr = $sth->fetchrow_array) {
1199
1200       $fields = "(";
1201       
1202       $fields .= join ',', map { $dbh->quote($_) } @arr;
1203       $fields .= ")";
1204         
1205       print OUT qq|$query $fields;\n|;
1206     }
1207     
1208     $sth->finish;
1209   }
1210
1211
1212   # create sequences and triggers
1213   foreach $item (@sequences) {
1214     if ($myconfig->{dbdriver} eq 'DB2') {
1215       $query = qq|SELECT NEXTVAL FOR $item FROM sysibm.sysdummy1|;
1216     } else {
1217       $query = qq|SELECT last_value FROM $item|;
1218     }
1219     
1220     $sth = $dbh->prepare($query);
1221     $sth->execute || $form->dberror($query);
1222     my ($id) = $sth->fetchrow_array;
1223     $sth->finish;
1224     $id++;
1225   
1226     print OUT qq|--
1227 DROP SEQUENCE $item $restrict;\n|;
1228     
1229     if ($myconfig->{dbdriver} eq 'DB2') {
1230       print OUT qq|CREATE SEQUENCE $item AS INTEGER START WITH $id INCREMENT BY 1 MAXVALUE 2147483647 MINVALUE 1 CACHE 5;\n|;
1231     } else {
1232       print OUT qq|CREATE SEQUENCE $item START $id;\n|;
1233     }
1234   }
1235
1236   print OUT "--\n";
1237   
1238   # functions
1239   map { print OUT $_ } @functions;
1240
1241   # triggers
1242   map { print OUT $_ } @triggers;
1243
1244   # add the index files
1245   open(FH, "sql/$myconfig->{dbdriver}-indices.sql");
1246   @a = <FH>;
1247   close(FH);
1248   print OUT @a;
1249   
1250   close(OUT);
1251   
1252   $dbh->disconnect;
1253
1254   # compress backup if gzip defined
1255   my $suffix = "";
1256   if ($gzip) {
1257     my @args = split / /, $gzip;
1258     my @s = @args;
1259     
1260     push @args, "$tmpfile";
1261     system(@args) == 0 or $form->error("$args[0] : $?");
1262     
1263     shift @s;
1264     my %s = @s;
1265     $suffix = ${-S} || ".gz";
1266     $tmpfile .= $suffix;
1267   }
1268   
1269   if ($form->{media} eq 'email') {
1270    
1271     use SL::Mailer;
1272     $mail = new Mailer;
1273
1274     $mail->{to} = qq|"$myconfig->{name}" <$myconfig->{email}>|;
1275     $mail->{from} = qq|"$myconfig->{name}" <$myconfig->{email}>|;
1276     $mail->{subject} = "SQL-Ledger Backup / $myconfig->{dbname}-$form->{dbversion}-$t[5]$t[4]$t[3].sql$suffix";
1277     @{ $mail->{attachments} } = ($tmpfile);
1278     $mail->{version} = $form->{version};
1279     $mail->{fileid} = "$boundary.";
1280
1281     $myconfig->{signature} =~ s/\\n/\r\n/g;
1282     $mail->{message} = "-- \n$myconfig->{signature}";
1283     
1284     $err = $mail->send($out);
1285   }
1286   
1287   if ($form->{media} eq 'file') {
1288    
1289     open(IN, "$tmpfile") or $form->error("$tmpfile : $!");
1290     open(OUT, ">-") or $form->error("STDOUT : $!");
1291    
1292     print OUT qq|Content-Type: application/file;
1293 Content-Disposition: attachment; filename="$myconfig->{dbname}-$form->{dbversion}-$t[5]$t[4]$t[3].sql$suffix"
1294
1295 |;
1296
1297     while (<IN>) {
1298       print OUT $_;
1299     }
1300
1301     close(IN);
1302     close(OUT);
1303     
1304   }
1305
1306   unlink "$tmpfile";
1307    
1308 }
1309
1310
1311 sub closedto {
1312   my ($self, $myconfig, $form) = @_;
1313
1314   my $dbh = $form->dbconnect($myconfig);
1315
1316   my $query = qq|SELECT closedto, revtrans, audittrail
1317                  FROM defaults|;
1318   ($form->{closedto}, $form->{revtrans}, $form->{audittrail}) = $dbh->selectrow_array($query);
1319   
1320   $dbh->disconnect;
1321
1322 }
1323
1324  
1325 sub closebooks {
1326   my ($self, $myconfig, $form) = @_;
1327
1328   my $dbh = $form->dbconnect_noauto($myconfig);
1329
1330   if ($form->{revtrans}) {
1331     
1332     $query = qq|UPDATE defaults SET closedto = NULL,
1333                                     revtrans = '1'|;
1334   } else {
1335     if ($form->{closedto}) {
1336       
1337       $query = qq|UPDATE defaults SET closedto = '$form->{closedto}',
1338                                       revtrans = '0'|;
1339     } else {
1340       
1341       $query = qq|UPDATE defaults SET closedto = NULL,
1342                                       revtrans = '0'|;
1343     }
1344   }
1345
1346   if ($form->{audittrail}) {
1347     $query .= qq|, audittrail = '1'|;
1348   } else {
1349     $query .= qq|, audittrail = '0'|;
1350   }
1351
1352   # set close in defaults
1353   $dbh->do($query) || $form->dberror($query);
1354
1355   if ($form->{removeaudittrail}) {
1356     $query = qq|DELETE FROM audittrail
1357                 WHERE transdate < '$form->{removeaudittrail}'|;
1358     $dbh->do($query) || $form->dberror($query);
1359   }
1360                 
1361   
1362   $dbh->commit;
1363   $dbh->disconnect;
1364   
1365 }
1366
1367
1368 sub earningsaccounts {
1369   my ($self, $myconfig, $form) = @_;
1370
1371   my ($query, $sth, $ref);
1372
1373   # connect to database
1374   my $dbh = $form->dbconnect($myconfig);
1375   
1376   # get chart of accounts
1377   $query = qq|SELECT accno,description
1378               FROM chart
1379               WHERE charttype = 'A'
1380               AND category = 'Q'
1381               ORDER by accno|;
1382   $sth = $dbh->prepare($query);
1383   $sth->execute || $form->dberror($query);
1384   $form->{chart} = "";
1385                                                   
1386   while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
1387     push @{ $form->{chart} }, $ref;
1388   }
1389   $sth->finish;
1390
1391   $dbh->disconnect;
1392               
1393 }
1394
1395
1396 sub post_yearend {
1397   my ($self, $myconfig, $form) = @_;
1398   
1399   # connect to database, turn off AutoCommit
1400   my $dbh = $form->dbconnect_noauto($myconfig);
1401
1402   my $query;
1403   my $uid = time;
1404   $uid .= $form->{login};
1405
1406   $query = qq|INSERT INTO gl (reference, employee_id)
1407               VALUES ('$uid', (SELECT id FROM employee
1408                                WHERE login = '$form->{login}'))|;
1409   $dbh->do($query) || $form->dberror($query);
1410   
1411   $query = qq|SELECT id FROM gl
1412               WHERE reference = '$uid'|;
1413   ($form->{id}) = $dbh->selectrow_array($query);
1414
1415   $query = qq|UPDATE gl SET 
1416               reference = |.$dbh->quote($form->{reference}).qq|,
1417               description = |.$dbh->quote($form->{description}).qq|,
1418               notes = |.$dbh->quote($form->{notes}).qq|,
1419               transdate = '$form->{transdate}',
1420               department_id = 0
1421               WHERE id = $form->{id}|;
1422
1423   $dbh->do($query) || $form->dberror($query);
1424
1425   my $amount;
1426   my $accno;
1427   
1428   # insert acc_trans transactions
1429   for my $i (1 .. $form->{rowcount}) {
1430     # extract accno
1431     ($accno) = split(/--/, $form->{"accno_$i"});
1432     $amount = 0;
1433
1434     if ($form->{"credit_$i"} != 0) {
1435       $amount = $form->{"credit_$i"};
1436     }
1437     if ($form->{"debit_$i"} != 0) {
1438       $amount = $form->{"debit_$i"} * -1;
1439     }
1440
1441
1442     # if there is an amount, add the record
1443     if ($amount != 0) {
1444       $query = qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
1445                   source)
1446                   VALUES
1447                   ($form->{id}, (SELECT id
1448                                  FROM chart
1449                                  WHERE accno = '$accno'),
1450                    $amount, '$form->{transdate}', |
1451                    .$dbh->quote($form->{reference}).qq|)|;
1452     
1453       $dbh->do($query) || $form->dberror($query);
1454     }
1455   }
1456
1457   $query = qq|INSERT INTO yearend (trans_id, transdate)
1458               VALUES ($form->{id}, '$form->{transdate}')|;
1459   $dbh->do($query) || $form->dberror($query);
1460
1461   my %audittrail = ( tablename  => 'gl',
1462                      reference  => $form->{reference},
1463                      formname   => 'yearend',
1464                      action     => 'posted',
1465                      id         => $form->{id} );
1466   $form->audittrail($dbh, "", \%audittrail);
1467   
1468   # commit and redirect
1469   my $rc = $dbh->commit;
1470   $dbh->disconnect;
1471
1472   $rc;
1473
1474 }
1475
1476
1477 1;
1478