From 22c70177969f30e2e419b32cb5d475c143f10b12 Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 8 Oct 2006 08:17:06 +0000 Subject: [PATCH] add menu items for credit card batching, debug last-minute changes to payby.pm, add ACL for re-processing batches, separate CARD and CHEK batches, fixed defaults for batch formats --- FS/FS/AccessRight.pm | 8 ++- FS/FS/Conf.pm | 25 ++++++- FS/FS/Schema.pm | 1 + FS/FS/Setup.pm | 61 ++++++++++------ FS/FS/cust_bill.pm | 44 +++++++----- FS/FS/pay_batch.pm | 5 +- FS/FS/payby.pm | 29 ++++++-- bin/customer-faker | 20 +++++- htetc/handler.pl | 1 + httemplate/edit/part_bill_event.cgi | 13 ++-- httemplate/elements/menu.html | 13 ++-- httemplate/search/cust_pay_batch.cgi | 88 ++++++++++++++--------- httemplate/search/elements/search.html | 23 ++++-- httemplate/search/pay_batch.cgi | 128 +++++++++++++++++++++------------ 14 files changed, 314 insertions(+), 145 deletions(-) diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index aa4586688..6fdb0b0ce 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -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 diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 7f77e000f..c956b5b0c 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -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' ] }, { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index ea02dfebf..607b2d9f3 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -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, '', '', diff --git a/FS/FS/Setup.pm b/FS/FS/Setup.pm index fff8256b4..c92ea41da 100644 --- a/FS/FS/Setup.pm +++ b/FS/FS/Setup.pm @@ -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 diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index edb951d2c..704df25a7 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -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 } ); diff --git a/FS/FS/pay_batch.pm b/FS/FS/pay_batch.pm index 7d9d9fb09..2bf307c06 100644 --- a/FS/FS/pay_batch.pm +++ b/FS/FS/pay_batch.pm @@ -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; diff --git a/FS/FS/payby.pm b/FS/FS/payby.pm index 54e4092a5..42328b429 100644 --- a/FS/FS/payby.pm +++ b/FS/FS/payby.pm @@ -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"; } diff --git a/bin/customer-faker b/bin/customer-faker index 86c8f7ce0..5ddc6d4ad 100755 --- a/bin/customer-faker +++ b/bin/customer-faker @@ -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"; } diff --git a/htetc/handler.pl b/htetc/handler.pl index cfb48722b..183a5534b 100644 --- a/htetc/handler.pl +++ b/htetc/handler.pl @@ -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; diff --git a/httemplate/edit/part_bill_event.cgi b/httemplate/edit/part_bill_event.cgi index 243975558..da11fc774 100755 --- a/httemplate/edit/part_bill_event.cgi +++ b/httemplate/edit/part_bill_event.cgi @@ -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)', diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index 65907339a..14c471d58 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -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' ] diff --git a/httemplate/search/cust_pay_batch.cgi b/httemplate/search/cust_pay_batch.cgi index 1b0bf6abf..d12e3c44f 100755 --- a/httemplate/search/cust_pay_batch.cgi +++ b/httemplate/search/cust_pay_batch.cgi @@ -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"; @@ -46,30 +45,55 @@ % 'LEFT JOIN pay_batch USING ( batchnum ) ' . % "$search ORDER BY $orderby"; % -%my $html_init = < -%Download batch in format -%

-% -%
-%Upload results
-%Filename
-%Format
-%
-%
-%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!
!; +% if ( $fixed ) { +% $html_init .= qq!!; +% } else { +% $html_init .= qq!Download batch in format !; +% } +% $html_init .= qq!

!; +% } +% +% if ( +% $pay_batch->status eq 'I' +% || ( $pay_batch->status eq 'R' +% && $FS::CurrentUser::CurrentUser->access_right('Reprocess batches') +% ) +% ) { +% $html_init .= qq!
!. +% qq!Upload results
!. +% qq!Filename
!; +% if ( $fixed ) { +% $html_init .= qq!!; +% } else { +% $html_init .= qq!Format
!; +% } +% $html_init .= '

'; +% } +% +%} +% +%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]; @@ -90,7 +114,7 @@ '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', @@ -124,7 +148,7 @@ 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 { diff --git a/httemplate/search/elements/search.html b/httemplate/search/elements/search.html index cbf0887a6..14e1dd095 100644 --- a/httemplate/search/elements/search.html +++ b/httemplate/search/elements/search.html @@ -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 @@ -282,10 +287,18 @@ % 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'} ) { diff --git a/httemplate/search/pay_batch.cgi b/httemplate/search/pay_batch.cgi index fcfa8bef2..7b2b9f00b 100755 --- a/httemplate/search/pay_batch.cgi +++ b/httemplate/search/pay_batch.cgi @@ -37,55 +37,89 @@ % %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" : '' }, + ], ) %> -- 2.11.0