add menu items for credit card batching, debug last-minute changes to payby.pm, add...
authorivan <ivan>
Sun, 8 Oct 2006 08:17:06 +0000 (08:17 +0000)
committerivan <ivan>
Sun, 8 Oct 2006 08:17:06 +0000 (08:17 +0000)
14 files changed:
FS/FS/AccessRight.pm
FS/FS/Conf.pm
FS/FS/Schema.pm
FS/FS/Setup.pm
FS/FS/cust_bill.pm
FS/FS/pay_batch.pm
FS/FS/payby.pm
bin/customer-faker
htetc/handler.pl
httemplate/edit/part_bill_event.cgi
httemplate/elements/menu.html
httemplate/search/cust_pay_batch.cgi
httemplate/search/elements/search.html
httemplate/search/pay_batch.cgi

index aa45866..6fdb0b0 100644 (file)
@@ -165,9 +165,11 @@ assigned to users and/or groups.
 ###
 # misc rights
 ###
-  'Job queue', # these are not currently agent-virtualized
-  'Import',    #
-  'Export',    #
+  'Job queue',         # these are not currently agent-virtualized
+  'Process batches',   #
+  'Reprocess batches', #
+  'Import',            #
+  'Export',            #
 
 ###
 # setup/config rights
index 7f77e00..c956b5b 100644 (file)
@@ -1729,11 +1729,34 @@ httemplate/docs/config.html
   },
 
   {
+    'key'         => 'batch-enable',
+    'section'     => 'billing',
+    'description' => 'Enable credit card batching - leave disabled for real-time installations.',
+    'type'        => 'checkbox',
+  },
+
+  {
     'key'         => 'batch-default_format',
     'section'     => 'billing',
     'description' => 'Default format for batches.',
     'type'        => 'select',
-    'select_enum' => [ 'csv-td_canada_trust-merchant_pc_batch', 'BoM' ]
+    'select_enum' => [ 'csv-td_canada_trust-merchant_pc_batch', 'BoM', 'PAP' ]
+  },
+
+  {
+    'key'         => 'batch-fixed_format-CARD',
+    'section'     => 'billing',
+    'description' => 'Fixed (unchangeable) format for credit card batches.',
+    'type'        => 'select',
+    'select_enum' => [ 'csv-td_canada_trust-merchant_pc_batch', 'BoM', 'PAP' ]
+  },
+
+  {
+    'key'         => 'batch-fixed_format-CHEK',
+    'section'     => 'billing',
+    'description' => 'Fixed (unchangeable) format for electronic check batches.',
+    'type'        => 'select',
+    'select_enum' => [ 'csv-td_canada_trust-merchant_pc_batch', 'BoM', 'PAP' ]
   },
 
   {
index ea02dfe..607b2d9 100644 (file)
@@ -592,6 +592,7 @@ sub tables_hashref {
     'pay_batch' => { #batches of payments to an external processor
       'columns' => [
         'batchnum',   'serial',    '',   '', '', '', 
+       'payby',      'char',      '',    4, '', '', # CARD/CHEK
         'status',     'char', 'NULL',     1, '', '', 
         'download',   @date_type, '', '', 
         'upload',     @date_type, '', '', 
index fff8256..c92ea41 100644 (file)
@@ -71,13 +71,8 @@ sub populate_locales {
     my @states = $subcountry ? $subcountry->all_codes : undef;
   
     if ( !scalar(@states) || ( scalar(@states)==1 && !defined($states[0]) ) ) {
-  
-      my $cust_main_county = new FS::cust_main_county({
-        'tax'   => 0,
-        'country' => $country,
-      });  
-      my $error = $cust_main_county->insert;
-      die $error if $error;
+
+      _add_locale( 'country'=>$country );
   
     } else {
   
@@ -86,15 +81,7 @@ sub populate_locales {
       }
   
       foreach my $state ( @states ) {
-  
-        my $cust_main_county = new FS::cust_main_county({
-          'state' => $state,
-          'tax'   => 0,
-          'country' => $country,
-        });  
-        my $error = $cust_main_county->insert;
-        die $error if $error;
-  
+        _add_locale( 'country'=>$country, 'state'=>$state);
       }
     
     }
@@ -102,6 +89,34 @@ sub populate_locales {
 
 }
 
+sub populate_addl_locales {
+
+  my %addl = (
+    'US' => {
+      'FM' => 'Federated States of Micronesia',
+      'MH' => 'Federated States of Micronesia',
+      'PW' => 'Federated States of Micronesia',
+      'AA' => "Armed Forces Americas (except Canada)",
+      'AE' => "Armed Forces Europe / Canada / Middle East / Africa",
+      'AP' => "Armed Forces Pacific",
+    },
+  );
+
+  foreach my $country ( keys %addl ) {
+    foreach my $state ( keys %{ $addl{$country} } ) {
+      # $longname = $addl{$country}{$state};
+      _add_locale( 'country'=>$country, 'state'=>$state);
+    }
+  }
+
+}
+
+sub _add_locale {
+  my $cust_main_county = new FS::cust_main_county( { 'tax'=>0, @_ });  
+  my $error = $cust_main_county->insert;
+  die $error if $error;
+}
+
 sub populate_initial_data {
   my %opt = @_;
 
@@ -175,13 +190,13 @@ sub initial_data {
         'weight'    => 40,
         'plan'      => 'suspend',
       },
-      { 'payby'     => 'DCLN',
-        'event'     => 'Retriable',
-        'seconds'   => 0,
-        'eventcode' => '$cust_bill_event->retriable();',
-        'weight'    => 60,
-        'plan'      => 'retriable',
-      },
+      #{ 'payby'     => 'DCLN',
+      #  'event'     => 'Retriable',
+      #  'seconds'   => 0,
+      #  'eventcode' => '$cust_bill_event->retriable();',
+      #  'weight'    => 60,
+      #  'plan'      => 'retriable',
+      #},
     ],
     
     #you must create a service definition. An example of a service definition
index edb951d..704df25 100644 (file)
@@ -1319,9 +1319,10 @@ sub batch_card {
   return '' unless $amount > 0;
   
   if ($options{'realtime'}) {
-    return $cust_main->realtime_bop ( $FS::payby::payby2bop{$cust_main->payby}, $amount,
-      %options,
-    );
+    return $cust_main->realtime_bop( FS::payby->payby2bop($cust_main->payby),
+                                     $amount,
+                                     %options,
+                                   );
   }
 
   my $oldAutoCommit = $FS::UID::AutoCommit;
@@ -1331,11 +1332,15 @@ sub batch_card {
   $dbh->do("LOCK TABLE pay_batch IN SHARE ROW EXCLUSIVE MODE")
     or return "Cannot lock pay_batch: " . $dbh->errstr;
 
-  my $pay_batch = qsearchs('pay_batch', {'status' => 'O'});
+  my %pay_batch = (
+    'status' => 'O',
+    'payby'  => FS::payby->payby2payment($cust_main->payby),
+  );
+
+  my $pay_batch = qsearchs( 'pay_batch', \%pay_batch );
 
   unless ( $pay_batch ) {
-    $pay_batch = new FS::pay_batch;
-    $pay_batch->setfield('status' => 'O');
+    $pay_batch = new FS::pay_batch \%pay_batch;
     my $error = $pay_batch->insert;
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
@@ -1344,26 +1349,29 @@ sub batch_card {
   }
 
   my $old_cust_pay_batch = qsearchs('cust_pay_batch', {
-      'batchnum' => $pay_batch->getfield('batchnum'),
-      'custnum'  => $cust_main->getfield('custnum'),
+      'batchnum' => $pay_batch->batchnum,
+      'custnum'  => $cust_main->custnum,
   } );
 
   my $cust_pay_batch = new FS::cust_pay_batch ( {
-    'batchnum' => $pay_batch->getfield('batchnum'),
+    'batchnum' => $pay_batch->batchnum,
     'invnum'   => $self->getfield('invnum'),       # is there a better value?
-    'custnum'  => $cust_main->getfield('custnum'),
+                                                   # this field should be
+                                                  # removed...
+                                                  # cust_bill_pay_batch now
+    'custnum'  => $cust_main->custnum,
     'last'     => $cust_main->getfield('last'),
     'first'    => $cust_main->getfield('first'),
-    'address1' => $cust_main->getfield('address1'),
-    'address2' => $cust_main->getfield('address2'),
-    'city'     => $cust_main->getfield('city'),
-    'state'    => $cust_main->getfield('state'),
-    'zip'      => $cust_main->getfield('zip'),
-    'country'  => $cust_main->getfield('country'),
+    'address1' => $cust_main->address1,
+    'address2' => $cust_main->address2,
+    'city'     => $cust_main->city,
+    'state'    => $cust_main->state,
+    'zip'      => $cust_main->zip,
+    'country'  => $cust_main->country,
     'payby'    => $cust_main->payby,
     'payinfo'  => $cust_main->payinfo,
-    'exp'      => $cust_main->getfield('paydate'),
-    'payname'  => $cust_main->getfield('payname'),
+    'exp'      => $cust_main->paydate,
+    'payname'  => $cust_main->payname,
     'amount'   => $amount,                          # consolidating
   } );
   
index 7d9d9fb..2bf307c 100644 (file)
@@ -34,7 +34,9 @@ FS::Record.  The following fields are currently supported:
 
 =item batchnum - primary key
 
-=item status -  
+=item payby - CARD or CHEK
+
+=item status - O (Open), I (In-transit), or R (Resolved)
 
 =item download - 
 
@@ -102,6 +104,7 @@ sub check {
 
   my $error = 
     $self->ut_numbern('batchnum')
+    || $self->ut_enum('payby', [ 'CARD', 'CHEK' ])
     || $self->ut_enum('status', [ 'O', 'I', 'R' ])
   ;
   return $error if $error;
index 54e4092..42328b4 100644 (file)
@@ -3,6 +3,7 @@ package FS::payby;
 use strict;
 use vars qw(%hash %payby2bop);
 use Tie::IxHash;
+use Business::CreditCard;
 
 
 =head1 NAME
@@ -98,11 +99,11 @@ tie %hash, 'Tie::IxHash',
   },
   'DCLN' => {  # This is only an event.
     tinyname  => 'declined',
-    shortname => 'Declined payment',
-    longname  => 'Declined payment',
+    shortname => 'Batch declined payment',
+    longname  => 'Batch declined payment',
 
     #its neither of these..
-    cust_main => '',
+    #cust_main => '',
     cust_pay  => '',
 
   },
@@ -117,11 +118,31 @@ sub payby2longname {
   map { $_ => $hash{$_}->{longname} } $self->payby;
 }
 
+sub shortname {
+  my( $self, $payby ) = @_;
+  $hash{$payby}->{shortname};
+}
+
+sub longname {
+  my( $self, $payby ) = @_;
+  $hash{$payby}->{longname};
+}
+
 %payby2bop = (
   'CARD' => 'CC',
   'CHEK' => 'ECHECK',
 );
 
+sub payby2bop {
+  my( $self, $payby ) = @_;
+  $payby2bop{ $self->payby2payment($payby) };
+}
+
+sub payby2payment {
+  my( $self, $payby ) = @_;
+  $hash{$payby}{'cust_pay'} || $payby;
+}
+
 sub cust_payby {
   my $self = shift;
   grep { ! exists $hash{$_}->{cust_main} } $self->payby;
@@ -142,7 +163,7 @@ sub payinfo_check{
         or return "Illegal (mistyped?) credit card number (payinfo)";
       $$payinforef = $1;
       validate($$payinforef) or return "Illegal credit card number";
-      return "Unknown card type" if cardype($$payinforef) eq "Unknown";
+      return "Unknown card type" if cardtype($$payinforef) eq "Unknown";
     } else {
       $$payinforef="N/A";
     }
index 86c8f7c..5ddc6d4 100755 (executable)
@@ -2,12 +2,17 @@
 
 use strict;
 use Data::Faker;
+use Business::CreditCard;
 use FS::UID qw(adminsuidsetup);
 use FS::cust_main;
+use Getopt::Std;
 
 my $agentnum = 1;
 my $refnum = 1;
 
+use vars qw( $opt_p );
+getopts('p:');
+
 my $user = shift or die &usage;
 my $num = shift or die &usage;
 adminsuidsetup($user);
@@ -38,6 +43,18 @@ until ( $num-- <= 0 ) {
     'payip'    => $faker->ip_address,
   };
 
+  if ( $opt_p eq 'CARD' || ( !$opt_p && rand() > .33 ) ) {
+    $cust_main->payby('CARD');
+    my $cardnum = '4123'. sprintf('%011u', int(rand(100000000000)) );
+    $cust_main->payinfo( $cardnum. generate_last_digit($cardnum) );
+    $cust_main->paydate( '2009-05-01' );
+  } elsif ( $opt_p eq 'CHEK' || ( !$opt_p && rand() > .66 ) ) {
+    $cust_main->payby('CHEK');
+    my $payinfo = sprintf('%7u@%09u', int(rand(10000000)), int(rand(1000000000)) ); 
+    $cust_main->payinfo($payinfo);
+    $cust_main->payname( 'First International Bank of Testing' );
+  }
+
   # could insert invoicing_list and other stuff too..  hell, could insert
   # packages, services, more
   # but i just wanted 10k customers to test the pager and this was good enough
@@ -50,11 +67,12 @@ until ( $num-- <= 0 ) {
 my $end = time;
 
 my $sec = $end-$start;
+$sec=1 if $sec==0;
 my $persec = $onum / $sec;
 print "$onum customers inserted in $sec seconds ($persec customers/sec)\n";
 
 #---
 
 sub usage {
-  die "Usage:\n\n  customer-faker user num_fakes\n";
+  die "Usage:\n\n  customer-faker [ -p payby ] user num_fakes\n";
 }
index cfb4872..183a553 100644 (file)
@@ -97,6 +97,7 @@ sub handler
       use Date::Parse;
       use Time::Local;
       use Time::Duration;
+      use Lingua::EN::Inflect qw(PL);
       use Tie::IxHash;
       use URI::Escape;
       use HTML::Entities;
index 2439755..da11fc7 100755 (executable)
@@ -215,16 +215,17 @@ Invoice Event #<% $hashref->{eventpart} ? $hashref->{eventpart} : "(NEW)" %>
 %  },
 %
 %  'batch-card' => {
-%    'name' => 'Add card to the pending credit card batch',
+%    'name' => 'Add card or check to a pending batch',
 %    'code' => '$cust_bill->batch_card(%options);',
 %    'weight' => 40,
 %  },
 %
-%  'retriable' => {
-%    'name' => 'Mark batched card event as retriable',
-%    'code' => '$cust_pay_batch->retriable();',
-%    'weight' => 60,
-%  },
+%  
+%  #'retriable' => {
+%  #  'name' => 'Mark batched card event as retriable',
+%  #  'code' => '$cust_pay_batch->retriable();',
+%  #  'weight' => 60,
+%  #},
 %
 %  'send' => {
 %    'name' => 'Send invoice (email/print/fax)',
index 6590733..14c471d 100644 (file)
@@ -157,10 +157,13 @@ tie my %report_financial, 'Tie::IxHash',
   'Sales, Credits and Receipts' => [ $fsurl.'graph/report_money_time.html', 'Sales, credits and receipts summary graph' ],
   'Sales Report' => [ $fsurl.'graph/report_cust_bill_pkg.html', 'Sales report and graph (by agent, package class and/or date range)' ],
   'Credit Report' => [ $fsurl.'search/report_cust_credit.html', 'Credit report (by employee and/or date range)' ],
-  'Payment Report' => [ $fsurl.'search/report_cust_pay.html', 'Credit report (by type and/or date range)' ],
-  'A/R Aging' => [ $fsurl.'search/report_receivables.html', 'Accounts Receivable Aging report' ],
-  'Prepaid Income' => [ $fsurl.'search/report_prepaid_income.html', 'Prepaid income (unearned revenue)  report' ],
-  'Sales Tax Liability' => [ $fsurl.'search/report_tax.html', 'Sales tax liability report' ],
+  'Payment Report' => [ $fsurl.'search/report_cust_pay.html', 'Payment report (by type and/or date range)' ],
+;
+$report_financial{'Payment Batch Report'} = [ $fsurl.'search/pay_batch.html', 'Payment batches (by status and/or date range)' ]
+  if $conf->exists('batch-enable');
+$report_financial{'A/R Aging'} = [ $fsurl.'search/report_receivables.html', 'Accounts Receivable Aging report' ];
+$report_financial{'Prepaid Income'} = [ $fsurl.'search/report_prepaid_income.html', 'Prepaid income (unearned revenue)  report' ];
+$report_financial{'Sales Tax Liability'} = [ $fsurl.'search/report_tax.html', 'Sales tax liability report' ];
 ;
 
 tie my %report_menu, 'Tie::IxHash';
@@ -197,6 +200,8 @@ tie my %tools_exporting, 'Tie::IxHash',
 tie my %tools_menu, 'Tie::IxHash', ();
 $tools_menu{'Quick payment entry'} =  [ $fsurl.'misc/batch-cust_pay.html', 'Enter multiple payments in a batch' ]
   if $curuser->access_right('Post payment batch');
+$tools_menu{'Process payment batches'} = [ $fsurl.'search/pay_batch.cgi?magic=_date;open=1;intransit=1', 'Process credit card and electronic check batches' ]
+  if $conf->exists('batch-enable') && $curuser->access_right('Process batches');
 $tools_menu{'Job Queue'} =  [ $fsurl.'search/queue.html', 'View pending job queue' ]
   if $curuser->access_right('Job queue');
 $tools_menu{'Importing'} =  [ \%tools_importing, 'Import tools' ]
index 1b0bf6a..d12e3c4 100755 (executable)
@@ -1,18 +1,17 @@
-%
-%
-%my ($count_query, $sql_query, $batchnum);
+%my( $count_query, $sql_query );
 %my $hashref = {};
 %my @search = ();
 %my $orderby = 'paybatchnum';
 %
+%my( $pay_batch, $batchnum ) = ( '', '');
 %if ( $cgi->param('batchnum') && $cgi->param('batchnum') =~ /^(\d+)$/ ) {
 %  push @search, "batchnum = $1";
-%  my $pay_batch = qsearchs('pay_batch', { 'batchnum' => $1 } );
+%  $pay_batch = qsearchs('pay_batch', { 'batchnum' => $1 } );
 %  die "Batch $1 not found!" unless $pay_batch;
 %  $batchnum = $pay_batch->batchnum;
 %}
 %
-%if ( $cgi->param('payby')  ) {
+%if ( $cgi->param('payby') ) {
 %  $cgi->param('payby') =~ /^(CARD|CHEK)$/
 %    or die "illegal payby " . $cgi->param('payby');
 %
@@ -24,7 +23,7 @@
 %}
 %
 %my ($beginning, $ending) = FS::UI::Web::parse_beginning_ending($cgi);
-%unless ($batchnum){
+%unless ($pay_batch){
 %  push @search, "pay_batch.upload >= $beginning" if ($beginning);
 %  push @search, "pay_batch.upload <= $ending" if ($ending < 4294967295);#2^32-1
 %  $orderby = "pay_batch.download,paybatchnum";
 %             'LEFT JOIN pay_batch USING ( batchnum ) ' .
 %             "$search ORDER BY $orderby";
 %
-%my $html_init = <<EOF;
-%<FORM ACTION="$p/misc/download-batch.cgi" METHOD="POST">
-%Download batch in format <SELECT NAME="format">
-%<OPTION VALUE="">Default batch mode</OPTION>
-%<OPTION VALUE="csv-td_canada_trust-merchant_pc_batch">CSV file for TD Canada Trust Merchant PC Batch</OPTION>
-%<OPTION VALUE="PAP">80 byte file for TD Canada Trust PAP Batch</OPTION>
-%<OPTION VALUE="BoM">Bank of Montreal ECA batch</OPTION>
-%</SELECT><INPUT TYPE="hidden" NAME="batchnum" VALUE="$batchnum"><INPUT TYPE="submit" VALUE="Download"></FORM>
-%<BR><BR>
-%
-%<FORM ACTION="$p/misc/upload-batch.cgi" METHOD="POST" ENCTYPE="multipart/form-data">
-%Upload results<BR>
-%Filename <INPUT TYPE="file" NAME="batch_results"><BR>
-%Format <SELECT NAME="format">
-%<OPTION VALUE="">Default batch mode</OPTION>
-%<OPTION VALUE="csv-td_canada_trust-merchant_pc_batch">CSV results from TD Canada Trust Merchant PC Batch</OPTION>
-%<OPTION VALUE="PAP">264 byte results for TD Canada Trust PAP Batch</OPTION>
-%<OPTION VALUE="BoM">Bank of Montreal ECA results</OPTION>
-%</SELECT><BR>
-%<INPUT TYPE="submit" VALUE="Upload"></FORM>
-%<BR>
-%EOF
-%
-%if ($batchnum) {
+%my $html_init = '';
+%if ( $pay_batch ) {
+%  my $conf = new FS::Conf;
+%  my $fixed = $conf->config('batch-fixed_format-'. $pay_batch->payby);
+%  if (
+%       $pay_batch->status eq 'O' 
+%       || ( $pay_batch->status eq 'I'
+%            && $FS::CurrentUser::CurrentUser->access_right('Reprocess batches')
+%          ) 
+%  ) {
+%    $html_init .= qq!<FORM ACTION="$p/misc/download-batch.cgi" METHOD="POST">!;
+%    if ( $fixed ) {
+%      $html_init .= qq!<INPUT TYPE="hidden" NAME="format" VALUE="$fixed">!;
+%    } else {
+%      $html_init .= qq!Download batch in format <SELECT NAME="format">!.
+%                    qq!<OPTION VALUE="">Default batch mode</OPTION>!.
+%                    qq!<OPTION VALUE="csv-td_canada_trust-merchant_pc_batch">CSV file for TD Canada Trust Merchant PC Batch</OPTION>!.
+%                    qq!<OPTION VALUE="PAP">80 byte file for TD Canada Trust PAP Batch</OPTION>!.
+%                    qq!<OPTION VALUE="BoM">Bank of Montreal ECA batch</OPTION>!.
+%                    qq!</SELECT>!;
+%    }
+%    $html_init .= qq!<INPUT TYPE="hidden" NAME="batchnum" VALUE="$batchnum"><INPUT TYPE="submit" VALUE="Download"></FORM><BR>!;
+%  }
+%
+%  if (
+%       $pay_batch->status eq 'I' 
+%       || ( $pay_batch->status eq 'R'
+%            && $FS::CurrentUser::CurrentUser->access_right('Reprocess batches')
+%          ) 
+%  ) {
+%    $html_init .= qq!<FORM ACTION="$p/misc/upload-batch.cgi" METHOD="POST" ENCTYPE="multipart/form-data">!.
+%                  qq!Upload results<BR>!.
+%                  qq!Filename <INPUT TYPE="file" NAME="batch_results"><BR>!;
+%    if ( $fixed ) {
+%      $html_init .= qq!<INPUT TYPE="hidden" NAME="format" VALUE="$fixed">!;
+%    } else {
+%      $html_init .= qq!Format <SELECT NAME="format">!.
+%                    qq!<OPTION VALUE="">Default batch mode</OPTION>!.
+%                    qq!<OPTION VALUE="csv-td_canada_trust-merchant_pc_batch">CSV results from TD Canada Trust Merchant PC Batch</OPTION>!.
+%                    qq!<OPTION VALUE="PAP">264 byte results for TD Canada Trust PAP Batch</OPTION>!.
+%                    qq!<OPTION VALUE="BoM">Bank of Montreal ECA results</OPTION>!.
+%                    qq!</SELECT><BR>!;
+%    }
+%    $html_init .= '<INPUT TYPE="submit" VALUE="Upload"></FORM><BR>';
+%  }
+%
+%}
+%
+%if ($pay_batch) {
 %  my $sth = dbh->prepare($count_query) or die dbh->errstr. "doing $count_query";
 %  $sth->execute or die "Error executing \"$count_query\": ". $sth->errstr;
 %  my $cards = $sth->fetchrow_arrayref->[0];
              'menubar'     => ['Main Menu'  => $p,],
              'query'       => $sql_query,
              'count_query' => $count_query,
-              'html_init'   => $batchnum ? $html_init : '',
+              'html_init'   => $pay_batch ? $html_init : '',
              'header'      => [ '#',
                                 'Inv #',
                                 'Customer',
                                 sub {
                                   shift->[7] =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
                                    my( $mon, $year ) = ( $2, $1 );
-                                   $mon = "0$mon" if $mon < 10;
+                                   $mon = "0$mon" if length($mon) == 1;
                                    "$mon/$year";
                                 },
                                 sub {
index cbf0887..14e1dd0 100644 (file)
@@ -4,8 +4,13 @@
 %  # (everything not commented required is optional)
 %  #
 %  # # basic options, required
-%  # 'title'       => 'Page title',
-%  # 'name'        => 'items', #name for the records returned
+%  # 'title'         => 'Page title',
+%  # 
+%  # 'name_singular' => 'item',  #singular name for the records returned
+%  #    #OR#                     # (preferred, will be pluralized automatically)
+%  # 'name'          => 'items', #plural name for the records returned
+%  #                             # (deprecated, will be singularlized
+%  #                             #  simplisticly)
 %  #
 %  # # some HTML callbacks...
 %  # 'menubar'          => '', #menubar arrayref
 %      my( $url, $method ) = @$redirect;
 %      redirect( $url. $rows->[0]->$method() );
 %    } else {
+%      if ( $opt{'name_singular'} ) {
+%        $opt{'name'} = PL($opt{'name_singular'});
+%      }
 %      ( my $xlsname = $opt{'name'} ) =~ s/\W//g;
-%      #$opt{'name'} =~ s/s$// if $total == 1;
-%      $opt{'name'} =~ s/((s)e)?s$/$2/ if $total == 1;  #should use Lingua::bs
-%                                                       # to "depluralize"
+%      if ( $total == 1 ) {
+%        if ( $opt{'name_singular'} ) {
+%          $opt{'name'} = $opt{'name_singular'}
+%        } else {
+%          #$opt{'name'} =~ s/s$// if $total == 1;
+%          $opt{'name'} =~ s/((s)e)?s$/$2/ if $total == 1;
+%        }
+%      }                                               
 %
 %      my @menubar = ();
 %      if ( $opt{'menubar'} ) {
index fcfa8be..7b2b9f0 100755 (executable)
 %
 %my $extra_sql = scalar(@where) ? 'WHERE ' . join(' AND ', @where) : ''; 
 %
+%my $link = [ "${p}search/cust_pay_batch.cgi?batchnum=", 'batchnum' ];
 %
 <% include( 'elements/search.html',
-                 'title'        => 'Credit Card Batches',
-                'menubar'      => [ 'Main Menu' => $p, ],
-                'name'         => 'batches',
-                'query'        => { 'table'     => 'pay_batch',
-                                    'hashref'   => $hashref,
-                                    'extra_sql' => "$extra_sql ORDER BY batchnum DESC",
-                                  },
-                'count_query'  => "$count_query $extra_sql",
-                'header'       => [ 'Batch',
-                                    'First Download',
-                                    'Last Upload',
-                                    'Item Count',
-                                    'Amount',
-                                    'Status',
-                                  ],
-                'align'        => 'lllrrl',
-                'fields'       => [ 'batchnum',
-                                     sub {
-                                      my $_date = shift->download;
-                                      $_date ? time2str("%a %b %e %T %Y", $_date) : '' 
-                                    },
-                                     sub {
-                                      my $_date = shift->upload;
-                                      $_date ? time2str("%a %b %e %T %Y", $_date) : '' 
-                                    },
-                                    sub {
-                                       my $st = "SELECT COUNT(*) from cust_pay_batch WHERE batchnum=" . shift->batchnum;
-                                       my $sth = dbh->prepare($st)
-                                         or die dbh->errstr. "doing $st";
-                                       $sth->execute
-                                        or die "Error executing \"$st\": ". $sth->errstr;
-                                       $sth->fetchrow_arrayref->[0];
-                                    },
-                                    sub {
-                                       my $st = "SELECT SUM(amount) from cust_pay_batch WHERE batchnum=" . shift->batchnum;
-                                       my $sth = dbh->prepare($st)
-                                        or die dbh->errstr. "doing $st";
-                                       $sth->execute
-                                        or die "Error executing \"$st\": ". $sth->errstr;
-                                       $sth->fetchrow_arrayref->[0];
-                                    },
-                                     sub {
-                                      $statusmap{shift->status};
-                                    },
-                                  ],
-                'links'        => [ [ "${p}search/cust_pay_batch.cgi?batchnum=", 'batchnum',],
-                                  ],
+                 'title'         => 'Payment Batches',
+                'name_singular' => 'batch',
+                'query'         => { 'table'     => 'pay_batch',
+                                     'hashref'   => $hashref,
+                                     'extra_sql' => "$extra_sql ORDER BY batchnum DESC",
+                                   },
+                'count_query'   => "$count_query $extra_sql",
+                'header'        => [ 'Batch',
+                                     'Type',
+                                     'First Download',
+                                     'Last Upload',
+                                     'Item Count',
+                                     'Amount',
+                                     'Status',
+                                    ],
+                'align'         => 'rcllrrc',
+                'fields'        => [ 'batchnum',
+                                     sub { 
+                                       FS::payby->shortname(shift->payby);
+                                     },
+                                      sub {
+                                       my $self = shift;
+                                       my $_date = $self->download;
+                                       if ( $_date ) {
+                                         time2str("%a %b %e %T %Y", $_date);
+                                       } elsif ( $self->status eq 'O' ) {
+                                         'Download batch';
+                                       } else {
+                                         '';
+                                       }
+                                     },
+                                      sub {
+                                       my $self = shift;
+                                       my $_date = $self->upload;
+                                       if ( $_date ) {
+                                         time2str("%a %b %e %T %Y", $_date);
+                                       } elsif ( $self->status eq 'I' ) {
+                                         'Upload results';
+                                       } else {
+                                         '';
+                                       }
+                                     },
+                                     sub {
+                                        my $st = "SELECT COUNT(*) from cust_pay_batch WHERE batchnum=" . shift->batchnum;
+                                        my $sth = dbh->prepare($st)
+                                          or die dbh->errstr. "doing $st";
+                                        $sth->execute
+                                         or die "Error executing \"$st\": ". $sth->errstr;
+                                        $sth->fetchrow_arrayref->[0];
+                                     },
+                                     sub {
+                                        my $st = "SELECT SUM(amount) from cust_pay_batch WHERE batchnum=" . shift->batchnum;
+                                        my $sth = dbh->prepare($st)
+                                         or die dbh->errstr. "doing $st";
+                                        $sth->execute
+                                         or die "Error executing \"$st\": ". $sth->errstr;
+                                        $sth->fetchrow_arrayref->[0];
+                                     },
+                                      sub {
+                                       $statusmap{shift->status};
+                                     },
+                                   ],
+                'links'         => [
+                                     $link,
+                                     '',
+                                     sub { shift->status eq 'O' ? $link : '' },
+                                     sub { shift->status eq 'I' ? $link : '' },
+                                   ],
+                'size'         => [
+                                     '',
+                                     '',
+                                     sub { shift->status eq 'O' ? "+1" : '' },
+                                     sub { shift->status eq 'I' ? "+1" : '' },
+                                   ],
+                'style'         => [
+                                     '',
+                                     '',
+                                     sub { shift->status eq 'O' ? "b" : '' },
+                                     sub { shift->status eq 'I' ? "b" : '' },
+                                   ],
       )
 
 %>