[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

SF.net SVN: ledger-smb: [1984] trunk



Revision: 1984
          http://ledger-smb.svn.sourceforge.net/ledger-smb/?rev=1984&view=rev
Author:   einhverfr
Date:     2007-12-19 16:07:59 -0800 (Wed, 19 Dec 2007)

Log Message:
-----------
More contact, payment, voucher fixes/enhancements

Modified Paths:
--------------
    trunk/LedgerSMB/Batch.pm
    trunk/LedgerSMB/DBObject/Company.pm
    trunk/LedgerSMB.pm
    trunk/README.sql-ledger
    trunk/TODO
    trunk/UI/Contact/contact.html
    trunk/UI/batch/filter.html
    trunk/UI/lib/elements.html
    trunk/UI/payments/check_job.html
    trunk/UI/payments/payments_detail.html
    trunk/scripts/vouchers.pl
    trunk/sql/modules/Company.sql
    trunk/utils/process_queue/process_queue.pl

Modified: trunk/LedgerSMB/Batch.pm
===================================================================
--- trunk/LedgerSMB/Batch.pm	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/LedgerSMB/Batch.pm	2007-12-20 00:07:59 UTC (rev 1984)
@@ -31,13 +31,21 @@
 sub post {
     my ($self) = @_;
     ($self->{post_return_ref}) = $self->exec_method(funcname => 'batch_post');
+    $self->{dbh}->commit;
     return $self->{post_return_ref};
 }
 
 sub delete {
     my ($self) = @_;
     ($self->{delete_ref}) = $self->exec_method(funcname => 'batch_delete');
+    $self->{dbh}->commit;
     return $self->{delete_ref};
 }
 
+sub list_vouchers {
+    my ($self) = @_;
+    @{$self->{vouchers}} = $self->exec_method(funcname => 'voucher_list');
+    return @{$self->{vouchers}};
+}
+
 1;

Modified: trunk/LedgerSMB/DBObject/Company.pm
===================================================================
--- trunk/LedgerSMB/DBObject/Company.pm	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/LedgerSMB/DBObject/Company.pm	2007-12-20 00:07:59 UTC (rev 1984)
@@ -14,8 +14,10 @@
 sub save {
     my $self = shift @_;
     $self->set_entity_class();
+    $self->{threshold} = $self->parse_amount(amount => $self->{threshold});
     my ($ref) = $self->exec_method(funcname => 'entity_credit_save');
     $self->{entity_id} = $ref->{entity_credit_save};
+    $self->{threshold} = $self->format_amount(amount => $self->{threshold});
     $self->{dbh}->commit;
 }
 
@@ -88,6 +90,7 @@
     $self->set_entity_class();
     my ($ref) = $self->exec_method(funcname => 'entity__retrieve_credit');
     $self->merge($ref);
+    $self->{threshold} = $self->format_amount(amount => $self->{threshold});
 
     $self->{name} = $self->{legal_name};
 

Modified: trunk/LedgerSMB.pm
===================================================================
--- trunk/LedgerSMB.pm	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/LedgerSMB.pm	2007-12-20 00:07:59 UTC (rev 1984)
@@ -276,7 +276,7 @@
 
     my $regex = qr/([^a-zA-Z0-9_.-])/;
     $str =~ s/$regex/sprintf("%%%02x", ord($1))/ge;
-    $str;
+    return $str;
 }
 
 sub is_blank {
@@ -471,7 +471,7 @@
 sub parse_amount {
     my $self     = shift @_;
     my %args     = @_;
-    my $myconfig = $args{user};
+    my $myconfig = $args{user} || $self->{_user};
     my $amount   = $args{amount};
 
     if ( $amount eq '' or ! defined $amount) {
@@ -809,6 +809,18 @@
         }
     }
 }
+
+sub take_top_level {
+   my ($self) = @_;
+   my $return_hash = {};
+   for my $key (keys %$self){
+       if (!ref($self->{$key}) && $key !~ /^\./){
+          $return_hash->{$key} = $self->{$key}
+       }
+   }
+   return $return_hash;
+}
+
 1;
 
 

Modified: trunk/README.sql-ledger
===================================================================
--- trunk/README.sql-ledger	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/README.sql-ledger	2007-12-20 00:07:59 UTC (rev 1984)
@@ -12,4 +12,5 @@
 
 The database will be updated on first login.
 
-You will also want to migrate your configuration by running the SL2LS.pl script included in this directory.
+You will also want to migrate your configuration by running the SL2LS.pl script 
+included in this directory.

Modified: trunk/TODO
===================================================================
--- trunk/TODO	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/TODO	2007-12-20 00:07:59 UTC (rev 1984)
@@ -3,12 +3,6 @@
 1)  Refactor admin.pl.  Merge user management with main UI and create separate 
 dataset management interface. (in progress, Chris)
 
-2)  Add real security enforcement (in progress, Chris, part of admin reworking)
+2)  Setup wizard.
 
-3)  Refactor contact management code
 
-4)  Setup wizard.
-
-Additional prerequisites include:
-1)  Refactoring HR code. (In progress, Chris)
-

Modified: trunk/UI/Contact/contact.html
===================================================================
--- trunk/UI/Contact/contact.html	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/UI/Contact/contact.html	2007-12-20 00:07:59 UTC (rev 1984)
@@ -152,6 +152,11 @@
 		value = entity_id
 	} ?>	
 	<?lsmb PROCESS input element_data = {
+		type = "hidden"
+		name = "account_class"
+		value = account_class
+	} ?>	
+	<?lsmb PROCESS input element_data = {
 		label = text('Name:'),
 		type= "text",
 		name = "name",
@@ -289,6 +294,14 @@
 			label = text('Business Type:') #'
 			} ?> 
 	  </td>
+          <td> <?lsmb INCLUDE input element_data = {
+			name = "threshold"
+			value = threshold
+			type = "text"
+			size = "20"
+			label = text('Threshold')
+			class = "numeric"
+               } ?>
 	</tr>
     </table>
 

Modified: trunk/UI/batch/filter.html
===================================================================
--- trunk/UI/batch/filter.html	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/UI/batch/filter.html	2007-12-20 00:07:59 UTC (rev 1984)
@@ -30,7 +30,7 @@
 		options = batch_users
 		value_attr = "entity_id"
 		text_attr = "username"
-		name = "created_by"
+		name = "created_by_eid"
 		default_values = [created_by]
 	} ?></div>
 <div class="input" id="description_div">

Modified: trunk/UI/lib/elements.html
===================================================================
--- trunk/UI/lib/elements.html	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/UI/lib/elements.html	2007-12-20 00:07:59 UTC (rev 1984)
@@ -156,7 +156,7 @@
   <?lsmb IF element_data.defined('text_attr');
 	option_data.text = option_data.$text_attr;
     END ?>
-  <?lsmb  # Selected is a special case -- no attribute key, so it is handled here by looking for the option value in the default_values key.
+  <?lsmb  # Selected is a special case -- no attribute key, so it is handled here by looking for the option value in the default_values list.
     IF element_data.defined('default_values') AND element_data.default_values.grep("^${option_data.value}$").size;
     option_data.selected = ' selected="selected"';
     ELSE;

Modified: trunk/UI/payments/check_job.html
===================================================================
--- trunk/UI/payments/check_job.html	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/UI/payments/check_job.html	2007-12-20 00:07:59 UTC (rev 1984)
@@ -25,10 +25,12 @@
 	ELSE;
 		text('Job Failed');
 	END ?></div>
+ 	<?lsmb IF ! job.success ?>
   <div class="info">
 	<?lsmb text('Error:') ?><br />
 	<?lsmb job.error_condition ?>
   </div>
+	<?lsmb END  # if ! job.success ?>
   <?lsmb END # if job.completed ?>
 </body>
 </html>

Modified: trunk/UI/payments/payments_detail.html
===================================================================
--- trunk/UI/payments/payments_detail.html	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/UI/payments/payments_detail.html	2007-12-20 00:07:59 UTC (rev 1984)
@@ -13,6 +13,11 @@
 <?lsmb payment_type = (account_class == 1) ? text('Payments') : text('Receipts') 
 ?>
 <body id="payment_2_body">
+<!-- CT:  This template produces invalid XHTML due to the use of nested tables.
+    Because nested tables are widely used (perhaps improperly) for layout,
+    most browsers should have no issues with them.  Furthermore, I cannot find
+    any cleaner solution to embedding tabular data within tabular data than
+    this -->
 <div class="listtop"><?lsmb payment_type ?></div>
  <form name="pay_dues" method="post" action="payment.pl">
  <!-- Moving all hidden variables to the top.  -CT -->
@@ -177,7 +182,11 @@
 		} ?>
 		<?lsmb r.account_number ?>
 	</td>
-	<td class="entity_name"><?lsmb r.contact_name ?></td>
+	<td class="entity_name"><span class="<?lsmb
+		IF r.has_vouchers; 'name_has_vouchers' ; 
+		ELSE ; 'name_has_no_vouchers' ; 
+		END
+		?>"><?lsmb r.contact_name ?></span></td>
 	<td class="invoice"><?lsmb r.total_due ?> <?lsmb currency ?></td>
         <td class="payment">
 		<?lsmb INCLUDE input element_data = {
@@ -223,8 +232,10 @@
 		<tr>
 			<td class="invoice_date_list">&nbsp;<?lsmb i.2 ?></td>
 			<td class="invoice_list">&nbsp;<?lsmb i.1 ?></td>
-		        <td class="total_due_list">&nbsp;<?lsmb i.3 ?></td>
-			<td class="paid_list">&nbsp;<?lsmb i.4 ?></td>
+		        <td class="total_due_list">&nbsp;
+				<?lsmb INCLUDE format_money number=i.3 ?></td>
+			<td class="paid_list">&nbsp;
+				<?lsmb INCLUDE format_money number=i.4 ?></td>
 			<td class="net_due_list">&nbsp;
 				<?lsmb INCLUDE format_money number= i.6 ?>
 				<?lsmb currency ?></td>
@@ -249,7 +260,7 @@
 			<?lsmb INCLUDE input element_data = {
 				type = "hidden"
 				name = "net_$i.0"
-				value = i.6
+				value = ${"payment_$r.contact_id_$i.0"}
 			} ?>
 			</td>
 		</tr>

Modified: trunk/scripts/vouchers.pl
===================================================================
--- trunk/scripts/vouchers.pl	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/scripts/vouchers.pl	2007-12-20 00:07:59 UTC (rev 1984)
@@ -29,6 +29,15 @@
 }
 
 sub create_vouchers {
+    my ($request) = shift @_;
+    my $batch = LedgerSMB::Batch->new({base => $request});
+    $batch->{batch_class} = $request->{batch_type};
+    $batch->create;
+    add_vouchers($batch);
+}
+
+
+sub add_vouchers {
     #  This function is not safe for caching as long as the scripts are in bin.
     #  This is because these scripts import all functions into the *current*
     #  namespace.  People using fastcgi and modperl should *not* cache this 
@@ -36,11 +45,7 @@
     #  Also-- request is in 'our' scope here due to the redirect logic.
     our ($request) = shift @_;
     use LedgerSMB::Form;
-
     my $batch = LedgerSMB::Batch->new({base => $request});
-    $batch->{batch_class} = $request->{batch_type};
-    $batch->create;
-
     our $vouchers_dispatch = 
     {
         payable    => {script => 'bin/ap.pl', function => sub {add()}},
@@ -61,8 +66,6 @@
 	
     };
 
-    # Note that the line below is generally considered incredibly bad form. 
-    # However, the code we are including is going to require it for now. -- CT
     our $form = new Form;
     our $locale = $request->{_locale};
 
@@ -84,10 +87,13 @@
     $form->{script} =~ s|.*/||;
     if ($script =~ /^bin/){
 
+        # Note that the line below is generally considered incredibly bad form. 
+        # However, the code we are including is going to require it for now. 
+        # -- CT
         { no strict; no warnings 'redefine'; do $script; }
 
     } elsif ($script =~ /scripts/) {
-
+	# Maybe we should move this to a require statement?  --CT
          { do $script } 
 
     }
@@ -95,19 +101,242 @@
     $vouchers_dispatch->{$request->{batch_type}}{function}($request);
 }
 
+sub search_batch {
+    my ($request) = @_;
+    my $batch_request = LedgerSMB::Batch->new(base => $request);
+    $batch_request->get_search_criteria();
+    my $template = LedgerSMB::Template->new(
+        user     => $request->{_user},
+        locale   => $request->{_locale},
+        path     => 'UI/batch',
+        template => 'filter',
+        format   => 'HTML', 
+    );
+    $template->render($batch_request);
+}
+
+sub list_batches {
+    my ($request) = @_;
+    my $batch = LedgerSMB::Batch->new(base => $request);
+    my @search_results = $batch->get_search_results;
+    $batch->{script} = "vouchers.pl";
+
+    my @columns = 
+        qw(select id control_code description transaction_total payment_total);
+
+    my $base_href = "vouchers.pl";
+    my $search_href = "$base_href?action=list_batches";
+    my $batch_href = "$base_href?action=get_batch";
+
+    for my $key (
+       qw(class_id approved created_by description amount_gt amount_lt)
+    ){
+       $search_href .= "&$key=$batch->{key}";
+    }
+
+    my %column_heading = (
+        'select'          => $batch->{_locale}->text('Select'),
+        transaction_total => {
+             text => $batch->{_locale}->text('AR/AP/GL Total'),
+             href => "$search_href&order_by=transaction_total"
+        },
+        payment_total     => { 
+             text => $batch->{_locale}->text('Paid/Received Total'),
+             href => "$search_href&order_by=payment_total"
+        },
+        description       => {
+             text => $batch->{_locale}->text('Description'),
+             href => "$search_href&order_by=description"
+        },
+        control_code      => {
+             text => $batch->{_locale}->text('Batch Number'),
+             href => "$search_href&order_by=control_code"
+        },
+        id                => {
+             text => $batch->{_locale}->text('ID'),
+             href => "$search_href&order_by=control_code"
+        },
+    );
+    my $count = 0;
+    my @rows;
+    for my $result (@search_results){
+        ++$count;
+        $batch->{"row_$count"} = $result->{id};
+        push @rows, {
+            'select'          => {
+                                 input => {
+                                           type  => 'checkbox',
+                                           value => 1,
+                                           name  => "batch_$result->{id}"
+                                 }
+            },
+            transaction_total => $batch->format_amount(
+                                     amount => $result->{transaction_total}
+				),
+            payment_total     => $batch->format_amount (
+                                     amount => $result->{payment_total}
+                                ),
+            description => $result->{description},
+            control_code => {
+                             text  => $result->{control_code},
+                             href  => "$batch_href&batch_id=$result->{id}",
+
+            },
+            id => $result->{id},
+        };
+    }
+    $batch->{rowcount} = $count;
+    my $template = LedgerSMB::Template->new(
+        user     => $request->{_user},
+        locale   => $request->{_locale},
+        path     => 'UI',
+        template => 'form-dynatable',
+        format   => ($batch->{format}) ? $batch->{format} : 'HTML', 
+    );
+
+    my $hiddens = $batch->take_top_level();
+    $batch->{rowcount} = "$count";
+    delete $batch->{search_results};
+
+    $template->render({ 
+	form    => $batch,
+	columns => ..hidden..,
+	heading => \%column_heading,
+        rows    => ..hidden..,
+        hiddens => $hiddens,
+        buttons => [{
+                    name  => 'action',
+                    type  => 'submit',
+                    text  => $request->{_locale}->text('Post'),
+                    value => 'batch_approve',
+                    class => 'submit',
+		},{
+                    name  => 'action',
+                    type  => 'submit',
+                    text  => $request->{_locale}->text('Delete'),
+                    value => 'batch_delete',
+                    class => 'submit',
+               }]
+    });
+        
+}
+
 sub get_batch {
+    my ($request)  = @_;
+    my $batch = LedgerSMB::Batch->new(base => $request);
+    my $rows = [];
+
+    $batch->{id} ||= $batch->{batch_id};
+    # $batch->get;
+    my @vouchers = $batch->list_vouchers;
+
+    my $base_href = "vouchers.pl?action=get_batch&batch_id=$batch->{batch_id}";
+
+    my @columns = qw(id description batch_class reference amount date);
+    my $heading = {
+        id          => {
+                        text => $request->{_locale}->text('ID'),
+                        href => "$base_href&order_by=id"
+        },
+        description => { 
+                        href => "$base_href&order_by=description",
+                        text => $request->{_locale}->text('Description'),
+        },
+        batch_class => {
+                        text => $request->{_locale}->text('Class'),
+                        href => "$base_href&order_by=class"
+        },
+        amount      => {
+                        text => $request->{_locale}->text('Amount'),
+                        href => "$base_href&order_by=amount"
+        }, 
+        reference   => {
+                        text => $request->{_locale}->text('Source/Reference'),
+                        href => "$base_href&order_by=reference"
+        },
+        date        => {
+                        text => $request->{_locale}->text('Date'),
+                        href => "$base_href&order_by=date"
+        }
+    };
+
+    my $classcount;
+
+    for my $row (@vouchers) {
+       $classcount = ($classcount + 1) % 2;
+       $classcount ||= 0;
+       push @$rows, {
+           description => $row->{description},
+           id          => $row->{id},
+           batch_class => $row->{batch_class},
+           amount      => $batch->format_amount(amount => $row->{amount}),
+           date        => $row->{transaction_date},
+           reference   => $row->{reference},
+           class       => "listrow$classcount"
+         
+       };
+    }
+    $batch->{title} = "Batch ID: $batch->{batch_id}";
+    my $template = LedgerSMB::Template->new(
+        user     => $request->{_user},
+        locale   => $request->{_locale},
+        path     => 'UI',
+        template => 'form-dynatable',
+        format   => ($batch->{format}) ? $batch->{format} : 'HTML', 
+    );
+    my $hiddens = $batch->take_top_level();
+    $template->render({ 
+	form    => $batch,
+	columns => ..hidden..,
+	heading => $heading,
+        rows    => $rows,
+        hiddens => $hiddens,
+        buttons => [{
+                    name  => 'action',
+                    type  => 'submit',
+                    text  => $request->{_locale}->text('Post'),
+                    value => 'batch_approve',
+                    class => 'submit',
+		},{
+                    name  => 'action',
+                    type  => 'submit',
+                    text  => $request->{_locale}->text('Delete'),
+                    value => 'batch_delete',
+                    class => 'submit',
+               }]
+    });
+        
+    
 }
 
-sub list_vouchers {
+sub list_batches_batch_delete {
+    batch_delete(@_);
 }
 
-sub add_vouchers {
+sub list_batches_batch_approve {
+    batch_approve(@_);
 }
 
-sub approve_batch {
+sub batch_approve {
+    my ($request) = @_;
+    my $batch = LedgerSMB::Batch->new(base => $request);
+    for my $count (1 .. $batch->{rowcount}){
+        next unless $batch->{"batch_" . $batch->{"row_$count"}};
+        $batch->{batch_id} = $batch->{"row_$count"};
+        $batch->post;
+    }
+    search_batch($request);
 }
 
-sub delete_batch {
+sub batch_delete {
+    my ($request)  = @_;
+    my $batch = LedgerSMB::Batch->new(base => $request);
+    for my $count (1 .. $batch->{rowcount}){
+        next unless $batch->{"batch_" . $batch->{"row_$count"}};
+        $batch->{batch_id} = $batch->{"row_$count"};
+        $batch->delete;
+    }
+    search_batch($request);
 }
 
 eval { do "scripts/custom/Voucher.pl"};

Modified: trunk/sql/modules/Company.sql
===================================================================
--- trunk/sql/modules/Company.sql	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/sql/modules/Company.sql	2007-12-20 00:07:59 UTC (rev 1984)
@@ -126,7 +126,10 @@
         pricegroup_id int,
         curr char(3),
         startdate date,
-        enddate date
+        enddate date,
+        ar_ap_account_id int,
+        cash_account_id int,
+        threshold numeric
 );
 
 COMMENT ON TYPE entity_credit_search_return IS
@@ -142,7 +145,8 @@
 	SELECT c.legal_name, c.id, e.id, ec.entity_class, ec.discount,
 		ec.taxincluded, ec.creditlimit, ec.terms, ec.meta_number,
 		ec.business_id, ec.language_code, ec.pricegroup_id, 
-		ec.curr::char(3), ec.startdate, ec.enddate
+		ec.curr::char(3), ec.startdate, ec.enddate, ec.ar_ap_account_id,
+		ec.cash_account_id, ec.threshold
 	INTO out_row
 	FROM company c
 	JOIN entity e ON (c.entity_id = e.id)
@@ -166,7 +170,9 @@
     in_curr char, in_startdate date, in_enddate date, 
     in_notes text, 
     in_name text, in_tax_id TEXT,
-    in_threshold NUMERIC
+    in_threshold NUMERIC,
+    in_ar_ap_account_id int, 
+    in_cash_account_id int
     
 ) returns INT as $$
     
@@ -178,7 +184,7 @@
     BEGIN
         
         -- TODO:  Move every table to an upsert mode independantly.
-        SELECT INTO v_row * FROM company WHERE id = in_id;
+        SELECT INTO v_row * FROM company WHERE legal_name = in_name;
         
         IF NOT FOUND THEN
             -- do some inserts
@@ -209,7 +215,9 @@
                 startdate,
                 enddate,
                 discount_terms,
-                threshold
+                threshold,
+		ar_ap_account_id,
+                cash_account_id
             )
             VALUES (
                 new_entity_id,
@@ -226,7 +234,9 @@
                 in_startdate,
                 in_enddate,
                 in_discount_terms,
-                in_threshold
+                in_threshold,
+                in_ar_ap_account_id,
+                in_cash_account_id
             );
             -- entity note class
             insert into entity_note (note_class, note, ref_key, vector) VALUES (
@@ -236,12 +246,14 @@
 
         ELSIF FOUND THEN
         
-            update company set tax_id = in_tax_id where id = in_id;
+            update company set tax_id = in_tax_id where id = v_row.id;
             update entity_credit_account SET
                 discount = in_discount,
                 taxincluded = in_taxincluded,
                 creditlimit = in_creditlimit,
                 terms = in_terms,
+                ar_ap_account_id = in_ar_ap_account_id,
+                cash_account_id = in_cash_account_id,
                 meta_number = in_meta_number,
                 business_id = in_business_id,
                 language_code = in_language,
@@ -253,12 +265,7 @@
                 discount_terms = in_discount_terms
             where entity_id = v_row.entity_id;
             
-            
-            UPDATE entity_note SET
-                note = in_note
-            WHERE ref_key = v_row.entity_id;
-            return in_id;
-        
+            return v_row.entity_id;    
         END IF;
     END;
     

Modified: trunk/utils/process_queue/process_queue.pl
===================================================================
--- trunk/utils/process_queue/process_queue.pl	2007-12-19 22:17:24 UTC (rev 1983)
+++ trunk/utils/process_queue/process_queue.pl	2007-12-20 00:07:59 UTC (rev 1984)
@@ -28,19 +28,20 @@
     my $job_id = 1;
     while ($job_id){
         ($job_id) = $dbh->selectrow_array( 
-		"SELECT min(id) from pending_job
+		"SELECT id from pending_job
 		WHERE completed_at IS NULL
+		ORDER BY id LIMIT 1
                 FOR UPDATE" 
     	);
     	if ($job_id){
             $job_id = $dbh->quote($job_id);
             my ($job_class) = $dbh->selectrow_array(
 		"select class from batch_class where id = 
-			(select batch_class from pending_job where id = $job_id"
+			(select batch_class from pending_job where id = $job_id)"
             );
             # Right now, we assume that every pending job has a batch id.
             # Longer-run we may need to use a template handle as well. -CT
-            $dbh->execute('SELECT ' .
+            $dbh->do('SELECT ' .
                $dbh->quote_identifier("job__process_$job_class") . "($job_id)"
             );
             my $errstr = $dbh->errstr;
@@ -60,6 +61,7 @@
             # The line below is necessary because the job process functions
             # use set session authorization so one must reconnect to reset
             # administrative permissions. -CT
+            $dbh->disconnect;
             $dbh = db_init(); 
         }
     }


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.