X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fpayinfo_Mixin.pm;h=b30ea35a17bb284bce4ce3f50e956e37550ed8b6;hb=01c2f31cf80bc89cc28d0ac7b99e3ab731431ff2;hp=5c4acf7188c10504cf691e545c1686766d21ea9e;hpb=8eb67bcf0710ecd0257ba8af47209320e74f59e3;p=freeside.git diff --git a/FS/FS/payinfo_Mixin.pm b/FS/FS/payinfo_Mixin.pm index 5c4acf718..b30ea35a1 100644 --- a/FS/FS/payinfo_Mixin.pm +++ b/FS/FS/payinfo_Mixin.pm @@ -4,8 +4,11 @@ use strict; use Business::CreditCard; use FS::payby; use FS::Record qw(qsearch); +use FS::UID qw(driver_name); +use FS::Cursor; +use Time::Local qw(timelocal); -use vars qw($ignore_masked_payinfo); +use vars qw( $ignore_masked_payinfo $allow_closed_replace ); =head1 NAME @@ -38,14 +41,15 @@ For Customers (cust_main): 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), 'MCHK' (Manual electronic +check), 'CBAK' Chargeback, or 'COMP' (free) For Payments (cust_pay): 'CARD' (credit cards), 'CHEK' (electronic check/ACH), 'LECB' (phone bill billing), 'BILL' (billing), 'PREP' (prepaid card), -'CASH' (cash), 'WEST' (Western Union), 'MCRD' (Manual credit card), -'PPAL' (PayPal) +'CASH' (cash), 'WEST' (Western Union), 'MCRD' (Manual credit card), 'MCHK' +(Manual electronic check), 'PPAL' (PayPal) 'COMP' (free) is depricated as a payment type in cust_pay =cut @@ -133,7 +137,11 @@ sub mask_payinfo { return 'N/A (tokenized)'; #? } else { # if not, mask it... - if ($payby eq 'CARD' || $payby eq 'DCRD' || $payby eq 'MCRD') { + if ($payby eq 'CARD' || $payby eq 'DCRD') { + #|| $payby eq 'MCRD') { + #MCRD isn't a card in payinfo, + #its a record of an _offline_ + #card # Credit Cards @@ -163,6 +171,13 @@ sub mask_payinfo { substr($account,(length($account)-2)). ( length($aba) ? "@".$aba : ''); + } elsif ($payby eq 'EDI') { + # EDI. + # These numbers have been seen anywhere from 8 to 30 digits, and + # possibly more. Lacking any better idea I'm going to mask all but + # the last 4 digits. + return 'x' x (length($payinfo) - 4) . substr($payinfo, -4); + } else { # Tie up loose ends return $payinfo; } @@ -174,23 +189,6 @@ sub mask_payinfo { 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), -'LECB' (Phone bill billing), 'BILL' (billing), 'COMP' (free), or -'PREPAY' (special billing type: applies a credit - see L and sets billing type to I) - -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) - -For Payments (cust_pay): -'CARD' (credit cards), 'CHEK' (electronic check/ACH), -'LECB' (phone bill billing), 'BILL' (billing), 'PREP' (prepaid card), -'CASH' (cash), 'WEST' (Western Union), or 'MCRD' (Manual credit card) -'COMP' (free) is depricated as a payment type in cust_pay - =cut sub payinfo_check { @@ -200,10 +198,17 @@ sub payinfo_check { or return "Illegal payby: ". $self->payby; if ( $self->payby eq 'CARD' && ! $self->is_encrypted($self->payinfo) ) { - my $payinfo = $self->payinfo; + + if ( $self->payinfo =~ /^99\d{14}$/ && ! $self->paycardtype ) { + return "paycardtype required (cannot be derived from a token)"; + } else { + $self->set('paycardtype', cardtype($self->payinfo)); + } + if ( $ignore_masked_payinfo and $self->mask_payinfo eq $self->payinfo ) { # allow it } else { + my $payinfo = $self->payinfo; $payinfo =~ s/\D//g; $self->payinfo($payinfo); if ( $self->payinfo ) { @@ -211,13 +216,18 @@ sub payinfo_check { or return "Illegal (mistyped?) credit card number (payinfo)"; $self->payinfo($1); validate($self->payinfo) or return "Illegal credit card number"; - return "Unknown card type" if $self->payinfo !~ /^99\d{14}$/ #token - && cardtype($self->payinfo) eq "Unknown"; + return "Unknown card type" if $self->paycardtype eq "Unknown"; } else { $self->payinfo('N/A'); #??? } } } else { + if ( $self->payby eq 'CARD' and $self->paymask ) { + # if we can't decrypt the card, at least detect the cardtype + $self->set('paycardtype', cardtype($self->paymask)); + } else { + $self->set('paycardtype', ''); + } if ( $self->is_encrypted($self->payinfo) ) { #something better? all it would cause is a decryption error anyway? my $error = $self->ut_anything('payinfo'); @@ -228,9 +238,10 @@ sub payinfo_check { } } + return ''; } -=item payby_payinfo_pretty +=item payby_payinfo_pretty [ LOCALE ] Returns payment method and information (suitably masked, if applicable) as a human-readable string, such as: @@ -245,22 +256,44 @@ or sub payby_payinfo_pretty { my $self = shift; + my $locale = shift; + my $lh = FS::L10N->get_handle($locale); if ( $self->payby eq 'CARD' ) { - 'Card #'. $self->paymask; + if ($self->paymask =~ /tokenized/) { + $lh->maketext('Tokenized Card'); + } else { + $lh->maketext('Card #') . $self->paymask; + } } elsif ( $self->payby eq 'CHEK' ) { - 'E-check acct#'. $self->payinfo; + + #false laziness w/view/cust_main/payment_history.html::translate_payinfo + my( $account, $aba ) = split('@', $self->paymask ); + + if ( $aba =~ /^(\d{5})\.(\d{3})$/ ) { #blame canada + my($branch, $routing) = ($1, $2); + $lh->maketext("Routing [_1], Branch [_2], Acct [_3]", + $routing, $branch, $account); + } else { + $lh->maketext("Routing [_1], Acct [_2]", $aba, $account); + } + } elsif ( $self->payby eq 'BILL' ) { - 'Check #'. $self->payinfo; + $lh->maketext('Check #') . $self->payinfo; } elsif ( $self->payby eq 'PREP' ) { - 'Prepaid card #'. $self->payinfo; + $lh->maketext('Prepaid card #') . $self->payinfo; } elsif ( $self->payby eq 'CASH' ) { - 'Cash '. $self->payinfo; + $lh->maketext('Cash') . ' ' . $self->payinfo; } elsif ( $self->payby eq 'WEST' ) { - 'Western Union'; #. $self->payinfo; + # does Western Union localize their name? + $lh->maketext('Western Union'); } elsif ( $self->payby eq 'MCRD' ) { - 'Manual credit card'; #. $self->payinfo; + $lh->maketext('Manual credit card'); + } elsif ( $self->payby eq 'MCHK' ) { + $lh->maketext('Manual electronic check'); + } elsif ( $self->payby eq 'EDI' ) { + $lh->maketext('EDI') . ' ' . $self->paymask; } elsif ( $self->payby eq 'PPAL' ) { - 'PayPal transaction#' . $self->order_number; + $lh->maketext('PayPal transaction#') . $self->order_number; } else { $self->payby. ' '. $self->payinfo; } @@ -278,18 +311,39 @@ sub payinfo_used { my $payinfo = shift || $self->payinfo; my %hash = ( 'custnum' => $self->custnum, - 'payby' => 'CARD', + 'payby' => $self->payby, ); return 1 if qsearch('cust_pay', { %hash, 'payinfo' => $payinfo } ) - || qsearch('cust_pay', - { %hash, 'paymask' => $self->mask_payinfo('CARD', $payinfo) } ) + || qsearch('cust_pay', { %hash, 'paymask' => $self->mask_payinfo } ) ; return 0; } +=item upgrade_set_cardtype + +Find all records with a credit card payment type and no paycardtype, and +replace them in order to set their paycardtype. + +=cut + +sub upgrade_set_cardtype { + my $class = shift; + # assign cardtypes to CARD/DCRDs that need them; check_payinfo_cardtype + # will do this. ignore any problems with the cards. + local $ignore_masked_payinfo = 1; + my $search = FS::Cursor->new({ + table => $class->table, + extra_sql => q[ WHERE payby IN('CARD','DCRD') AND paycardtype IS NULL ], + }); + while (my $record = $search->fetch) { + my $error = $record->replace; + die $error if $error; + } +} + =back =head1 BUGS