From a0ddcb6b2ac38076c48e8f0b69e0758d5283303a Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 19 Dec 2006 10:02:06 +0000 Subject: [PATCH] clean up payinfo_Mixin to use payby.pm for payby info and have card masking full 6-digit BIN prefix for card identification. have cust_pay_batch use payinfo_Mixin. require B:CC 0.30 for mask-aware cardtype(). fix payment reports to use mask too if available, so credit card type selection still works with encryption. --- FS/FS/cust_pay_batch.pm | 11 ++--- FS/FS/payby.pm | 47 ++++++++++---------- FS/FS/payinfo_Mixin.pm | 80 +++++++++++++--------------------- htetc/handler.pl | 2 +- httemplate/edit/cust_main/billing.html | 4 +- httemplate/search/cust_pay.cgi | 33 +++++++++----- 6 files changed, 82 insertions(+), 95 deletions(-) diff --git a/FS/FS/cust_pay_batch.pm b/FS/FS/cust_pay_batch.pm index c9a546870..d263f2176 100644 --- a/FS/FS/cust_pay_batch.pm +++ b/FS/FS/cust_pay_batch.pm @@ -3,10 +3,11 @@ package FS::cust_pay_batch; use strict; use vars qw( @ISA $DEBUG ); use FS::Record qw(dbh qsearch qsearchs); +use FS::payinfo_Mixin; use FS::part_bill_event qw(due_events); use Business::CreditCard 0.28; -@ISA = qw( FS::Record ); +@ISA = qw( FS::Record FS::payinfo_Mixin ); # 1 is mostly method/subroutine entry and options # 2 traces progress of some operations @@ -124,7 +125,7 @@ sub check { my $error = $self->ut_numbern('paybatchnum') - || $self->ut_numbern('trancode') #depriciated + || $self->ut_numbern('trancode') #deprecated || $self->ut_money('amount') || $self->ut_number('invnum') || $self->ut_number('custnum') @@ -142,11 +143,7 @@ sub check { $self->first =~ /^([\w \,\.\-\']+)$/ or return "Illegal first name"; $self->first($1); - $self->payby =~ /^(CARD|CHEK|LECB|BILL|COMP|PREP|CASH|WEST|MCRD)$/ - or return "Illegal payby"; - $self->payby($1); - - $error = FS::payby::payinfo_check($self->payby, \$self->payinfo); + $error = $self->payinfo_check(); return $error if $error; if ( $self->exp eq '' ) { diff --git a/FS/FS/payby.pm b/FS/FS/payby.pm index 42328b429..e44ac6a6d 100644 --- a/FS/FS/payby.pm +++ b/FS/FS/payby.pm @@ -18,6 +18,8 @@ FS::payby - Object methods for payment type records my @payby = FS::payby->payby; + my $bool = FS::payby->can_payby('cust_main', 'CARD'); + tie my %payby, 'Tie::IxHash', FS::payby->payby2longname my @cust_payby = FS::payby->cust_payby; @@ -38,7 +40,7 @@ Payment types. # paybys can be any/all of: # - a customer payment type (cust_main.payby) -# - a payment or refund type (cust_pay.payby) +# - a payment or refund type (cust_pay.payby, cust_pay_batch.payby, cust_refund.payby) # - an event type (part_bill_event.payby) tie %hash, 'Tie::IxHash', @@ -96,6 +98,13 @@ tie %hash, 'Tie::IxHash', tinyname => 'comp', shortname => 'Complimentary', longname => 'Complimentary', + cust_pay => '', # (free) is depricated as a payment type in cust_pay + }, + 'CBAK' => { + tinyname => 'chargeback', + shortname => 'Chargeback', + longname => 'Chargeback', + cust_main => '', # not a customer type }, 'DCLN' => { # This is only an event. tinyname => 'declined', @@ -103,7 +112,7 @@ tie %hash, 'Tie::IxHash', longname => 'Batch declined payment', #its neither of these.. - #cust_main => '', + cust_main => '', cust_pay => '', }, @@ -113,6 +122,18 @@ sub payby { keys %hash; } +sub can_payby { + my( $self, $table, $payby ) = @_; + + #return "Illegal payby" unless $hash{$payby}; + return 0 unless $hash{$payby}; + + $table = 'cust_pay' if $table eq 'cust_pay_batch' || $table eq 'cust_refund'; + return 0 if exists( $hash{$payby}->{$table} ); + + return 1; +} + sub payby2longname { my $self = shift; map { $_ => $hash{$_}->{longname} } $self->payby; @@ -153,28 +174,6 @@ sub cust_payby2longname { map { $_ => $hash{$_}->{longname} } $self->cust_payby; } -sub payinfo_check{ - my($payby, $payinforef) = @_; - - if ($payby eq 'CARD') { - $$payinforef =~ s/\D//g; - if ($$payinforef){ - $$payinforef =~ /^(\d{13,16})$/ - or return "Illegal (mistyped?) credit card number (payinfo)"; - $$payinforef = $1; - validate($$payinforef) or return "Illegal credit card number"; - return "Unknown card type" if cardtype($$payinforef) eq "Unknown"; - } else { - $$payinforef="N/A"; - } - } else { - $$payinforef =~ /^([\w \!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\=]*)$/ - or return "Illegal text (payinfo)"; - $$payinforef = $1; - } - ''; -} - =back =head1 BUGS diff --git a/FS/FS/payinfo_Mixin.pm b/FS/FS/payinfo_Mixin.pm index b1790c625..652dc4149 100644 --- a/FS/FS/payinfo_Mixin.pm +++ b/FS/FS/payinfo_Mixin.pm @@ -2,6 +2,7 @@ package FS::payinfo_Mixin; use strict; use Business::CreditCard; +use FS::payby; =head1 NAME @@ -13,7 +14,7 @@ package FS::some_table; use vars qw(@ISA); @ISA = qw( FS::payinfo_Mixin FS::Record ); -=head1 DESCRIPTION +=had1 DESCRIPTION This is a mixin class for records that contain payinfo. @@ -25,7 +26,7 @@ Encryption - In the Future (Pull from Record.pm) Bad Card Stuff - In the Future (Integrate Banned Pay) Currency - In the Future -=head1 fields +=head1 FIELDS =over 4 @@ -37,12 +38,12 @@ For Customers (cust_main): 'CARD' (credit card - automatic), 'DCRD' (credit card - on-demand), 'CHEK' (electronic check - automatic), 'DCHK' (electronic check - on-demand), 'LECB' (Phone bill billing), 'BILL' (billing), 'COMP' (free), or -'PREPAY' (special billing type: applies a credit - see L and sets billing type to I) +'PREPAY' (special billing type: applies a credit and sets billing type to I - see L) For Refunds (cust_refund): 'CARD' (credit cards), 'CHEK' (electronic check/ACH), 'LECB' (Phone bill billing), 'BILL' (billing), 'CASH' (cash), -'WEST' (Western Union), 'MCRD' (Manual credit card), 'CBAK' Chargeback, or 'COMP' (free), +'WEST' (Western Union), 'MCRD' (Manual credit card), 'CBAK' Chargeback, or 'COMP' (free) For Payments (cust_pay): @@ -52,15 +53,16 @@ For Payments (cust_pay): 'COMP' (free) is depricated as a payment type in cust_pay =cut - -sub payby { - my($self,$payby) = @_; - if ( defined($payby) ) { - $self->setfield('payby', $payby); - } - return $self->getfield('payby') -} +# was this supposed to do something? + +#sub payby { +# my($self,$payby) = @_; +# if ( defined($payby) ) { +# $self->setfield('payby', $payby); +# } +# return $self->getfield('payby') +#} =item payinfo @@ -99,6 +101,7 @@ sub paycvv { } } else { # warn "This doesn't work for other tables besides cust_main + ''; } } @@ -125,7 +128,13 @@ sub paymask { return $paymask; } -=item mask_payinfo() +=back + +=head1 METHODS + +=over 4 + +=item mask_payinfo This method converts the payment info (credit card, bank account, etc.) into a masked string. @@ -142,7 +151,7 @@ sub mask_payinfo { } else { # if not, mask it... if ($payby eq 'CARD' || $payby eq 'DCRD' || $payby eq 'MCRD') { # Credit Cards (Show first and last four) - $paymask = substr($payinfo,0,4). 'x'x(length($payinfo)-8). substr($payinfo,(length($payinfo)-4)); + $paymask = substr($payinfo,0,6). 'x'x(length($payinfo)-10). substr($payinfo,(length($payinfo)-4)); } elsif ($payby eq 'CHEK' || $payby eq 'DCHK' ) { # Checks (Show last 2 @ bank) my( $account, $aba ) = split('@', $payinfo ); @@ -154,15 +163,10 @@ sub mask_payinfo { return $paymask; } -=back - - -=head1 METHODS - -=over 4 - =item payinfo_check +Checks payby and payinfo. + For Customers (cust_main): 'CARD' (credit card - automatic), 'DCRD' (credit card - on-demand), 'CHEK' (electronic check - automatic), 'DCHK' (electronic check - on-demand), @@ -182,33 +186,11 @@ For Payments (cust_pay): =cut - - - - sub payinfo_check { my $self = shift; - # Make sure it's a valid payby - $self->payby =~ /^(CARD|DCRD|CHEK|DCHK|LECB|BILL|COMP|PREPAY|CASH|WEST|MCRD|PREP|CBAK)$/ - or return "Illegal payby (overall payinfo_check)"; - $self->payby($1); - - - # Okay some aren't valid depending on table - if ($self->table eq 'cust_main') { - if ($self->payby =~ /^(CASH|WEST|MCRD|PREP|CBAK)$/) { - return "Illegal payby (cust_main)"; - } - } elsif ($self->table eq 'cust_refund') { - if ($self->payby =~ /^(DCRD|DCHK|PREPAY|PREP)$/) { - return "Illegal payby (cust_refund)"; - } - } elsif ($self->table eq 'cust_pay') { - if ($self->payby =~ /^(DCRD|DCHK|PREPAY|CBAK)$/) { - return "Illegal payby (cust_pay)"; - } - } + FS::payby->can_payby($self->table, $self->payby) + or return "Illegal payby"; if ( $self->payby eq 'CARD' ) { my $payinfo = $self->payinfo; @@ -218,8 +200,8 @@ sub payinfo_check { $self->payinfo =~ /^(\d{13,16})$/ or return "Illegal (mistyped?) credit card number (payinfo)"; $self->payinfo($1); - Business::CreditCard::validate($self->payinfo) or return "Illegal credit card number"; - return "Unknown card type" if Business::CreditCard::cardtype($self->payinfo) eq "Unknown"; + validate($self->payinfo) or return "Illegal credit card number"; + return "Unknown card type" if cardtype($self->payinfo) eq "Unknown"; } else { $self->payinfo('N/A'); } @@ -229,15 +211,13 @@ sub payinfo_check { } } - - =head1 BUGS Have to add the future items... =head1 SEE ALSO -L +L, L =cut diff --git a/htetc/handler.pl b/htetc/handler.pl index d7a6c6a53..2272e2603 100644 --- a/htetc/handler.pl +++ b/htetc/handler.pl @@ -114,7 +114,7 @@ sub handler } use Text::CSV_XS; use Spreadsheet::WriteExcel; - use Business::CreditCard; + use Business::CreditCard 0.30; #for mask-aware cardtype() use String::Approx qw(amatch); use Chart::LinesPoints; use Chart::Mountain; diff --git a/httemplate/edit/cust_main/billing.html b/httemplate/edit/cust_main/billing.html index 77db7b6c6..d3cd77dbb 100644 --- a/httemplate/edit/cust_main/billing.html +++ b/httemplate/edit/cust_main/billing.html @@ -149,8 +149,6 @@ % my $disabled = 'DISABLED style="background-color: #dddddd"'; % my $text_disabled = 'style="color: #999999"'; % -% # this is not going to work unless the mask-generation recognizes -% # Switch/Solo cards % if ( $payby =~ /^(CARD|DCRD)$/ && cardtype($paymask) =~ /^(Switch|Solo)$/ ) { % $disabled = 'style="background-color: #ffffff"'; % $text_disabled = 'style="color: #000000";' @@ -194,7 +192,7 @@ % 'end_year' => (localtime())[5] + 1900, % 'selected_date' => ( % ( $payby =~ /^(CARD|DCRD)$/ -% && cardtype($paymask) =~ /^(Switch|Solo)$/ ) #also +% && cardtype($paymask) =~ /^(Switch|Solo)$/ ) % ? $cust_main->paystart_month. '-'. % $cust_main->paystart_year % : '' diff --git a/httemplate/search/cust_pay.cgi b/httemplate/search/cust_pay.cgi index 98cc0e799..199c66d81 100755 --- a/httemplate/search/cust_pay.cgi +++ b/httemplate/search/cust_pay.cgi @@ -21,9 +21,13 @@ % or die "illegal payby ". $cgi->param('payby'); % push @search, "cust_pay.payby = '$1'"; % if ( $3 ) { -% if ( $3 eq 'VisaMC' ) { +% +% my $cardtype = $3; +% +% my $search; +% if ( $cardtype eq 'VisaMC' ) { % #avoid posix regexes for portability -% push @search, +% $search = % " ( ( substring(cust_pay.payinfo from 1 for 1) = '4' ". % " AND substring(cust_pay.payinfo from 1 for 4) != '4936' ". % " AND substring(cust_pay.payinfo from 1 for 6) ". @@ -43,19 +47,21 @@ % " OR substring(cust_pay.payinfo from 1 for 2) = '54' ". % " OR substring(cust_pay.payinfo from 1 for 2) = '54' ". % " OR substring(cust_pay.payinfo from 1 for 2) = '55' ". +% " OR substring(cust_pay.payinfo from 1 for 2) = '36' ". #Diner's int'l processed as Visa/MC inside US % " ) "; -% } elsif ( $3 eq 'Amex' ) { -% push @search, +% } elsif ( $cardtype eq 'Amex' ) { +% $search = % " ( substring(cust_pay.payinfo from 1 for 2 ) = '34' ". % " OR substring(cust_pay.payinfo from 1 for 2 ) = '37' ". % " ) "; -% } elsif ( $3 eq 'Discover' ) { -% push @search, +% } elsif ( $cardtype eq 'Discover' ) { +% $search = % " ( substring(cust_pay.payinfo from 1 for 4 ) = '6011' ". -% " OR substring(cust_pay.payinfo from 1 for 3 ) = '650' ". +% " OR substring(cust_pay.payinfo from 1 for 2 ) = '65' ". +% " OR substring(cust_pay.payinfo from 1 for 3 ) = '622' ". #China Union Pay processed as Discover outside CN % " ) "; -% } elsif ( $3 eq 'Maestro' ) { -% push @search, +% } elsif ( $cardtype eq 'Maestro' ) { +% $search = % " ( substring(cust_pay.payinfo from 1 for 2 ) = '63' ". % " OR substring(cust_pay.payinfo from 1 for 2 ) = '67' ". % " OR substring(cust_pay.payinfo from 1 for 6 ) = '564182' ". @@ -72,8 +78,15 @@ % " SIMILAR TO '49118[1-2]' ". % " ) "; % } else { -% die "unknown card type $3"; +% die "unknown card type $cardtype"; % } +% +% my $masksearch = $search; +% $masksearch =~ s/cust_pay\.payinfo/cust_pay.paymask/gi; +% +% push @search, +% "( $search OR ( cust_pay.paymask IS NOT NULL AND $masksearch ) )"; +% % } % } % -- 2.11.0