X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_main.pm;h=8246b93f54e0321e7cd9c0d4d5f5e0d21c760800;hb=30189fa2e5987bafeb4714a83b7f130c568b221c;hp=deb14ae0c68fa5479eb65dba083f24538435430e;hpb=e28cba4f7305371968c96cfc57697221a58bc8cc;p=freeside.git diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index deb14ae0c..8246b93f5 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -1,7 +1,7 @@ package FS::cust_main; use strict; -use vars qw( @ISA @EXPORT_OK $conf $DEBUG $import ); +use vars qw( @ISA @EXPORT_OK $conf $DEBUG $import @encrypted_fields); use vars qw( $realtime_bop_decline_quiet ); #ugh use Safe; use Carp; @@ -53,6 +53,8 @@ $DEBUG = 0; $import = 0; +@encrypted_fields = ('payinfo', 'paycvv'); + #ask FS::UID to run this stuff for us later #$FS::UID::callback{'FS::cust_main'} = sub { install_callback FS::UID sub { @@ -175,11 +177,84 @@ FS::Record. The following fields are currently supported: =item ship_fax - phone (optional) -=item payby - I (credit card - automatic), I (credit card - on-demand), I (electronic check - automatic), I (electronic check - on-demand), I (Phone bill billing), I (billing), I (free), or I (special billing type: applies a payment from a prepaid card - see L - and sets billing type to I) +=item payby + +I (credit card - automatic), I (credit card - on-demand), I (electronic check - automatic), I (electronic check - on-demand), I (Phone bill billing), I (billing), I (free), or I (special billing type: applies a credit - see L and sets billing type to I) + +=item payinfo + +Card Number, P.O., comp issuer (4-8 lowercase alphanumerics; think username) or prepayment identifier (see L) + +=cut + +sub payinfo { + my($self,$payinfo) = @_; + if ( defined($payinfo) ) { + $self->paymask($payinfo); + $self->setfield('payinfo', $payinfo); # This is okay since we are the 'setter' + } else { + $payinfo = $self->getfield('payinfo'); # This is okay since we are the 'getter' + return $payinfo; + } +} + + +=item paycvv + +Card Verification Value, "CVV2" (also known as CVC2 or CID), the 3 or 4 digit number on the back (or front, for American Express) of the credit card + +=cut + +=item paymask - Masked payment type + +=over 4 + +=item Credit Cards + +Mask all but the last four characters. + +=item Checks + +Mask all but last 2 of account number and bank routing number. + +=item Others + +Do nothing, return the unmasked string. + +=back + +=cut + +sub paymask { + my($self,$value)=@_; + + # If it doesn't exist then generate it + my $paymask=$self->getfield('paymask'); + if (!defined($value) && (!defined($paymask) || $paymask eq '')) { + $value = $self->payinfo; + } + + if ( defined($value) && !$self->is_encrypted($value)) { + my $payinfo = $value; + my $payby = $self->payby; + if ($payby eq 'CARD' || $payby eq 'DCARD') { # Credit Cards (Show last four) + $paymask = 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4)); + } elsif ($payby eq 'CHEK' || + $payby eq 'DCHK' ) { # Checks (Show last 2 @ bank) + my( $account, $aba ) = split('@', $payinfo ); + $paymask = 'x'x(length($account)-2). substr($account,(length($account)-2))."@".$aba; + } else { # Tie up loose ends + $paymask = $payinfo; + } + $self->setfield('paymask', $paymask); # This is okay since we are the 'setter' + } elsif (defined($value) && $self->is_encrypted($value)) { + $paymask = 'N/A'; + } + return $paymask; +} + -=item payinfo - card number, P.O., comp issuer (4-8 lowercase alphanumerics; think username) or prepayment identifier (see L) -=item paycvv - Card Verification Value, "CVV2" (also known as CVC2 or CID), the 3 or 4 digit number on the back (or front, for American Express) of the credit card =item paydate - expiration date, mm/yyyy, m/yyyy, mm/yy or m/yy @@ -602,6 +677,16 @@ sub replace { local $SIG{TSTP} = 'IGNORE'; local $SIG{PIPE} = 'IGNORE'; + # If the mask is blank then try to set it - if we can... + if (!defined($self->getfield('paymask')) || $self->getfield('paymask') eq '') { + $self->paymask($self->payinfo); + } + + # We absolutely have to have an old vs. new record to make this work. + if (!defined($old)) { + $old = qsearchs( 'cust_main', { 'custnum' => $self->custnum } ); + } + if ( $self->payby eq 'COMP' && $self->payby ne $old->payby && $conf->config('users-allow_comp') ) { return "You are not permitted to create complimentary accounts." @@ -695,7 +780,7 @@ sub queue_fuzzyfiles_update { Checks all fields to make sure this is a valid customer record. If there is an error, returns the error, otherwise returns false. Called by the insert -and repalce methods. +and replace methods. =cut @@ -826,9 +911,19 @@ sub check { $self->payby =~ /^(CARD|DCRD|CHEK|DCHK|LECB|BILL|COMP|PREPAY)$/ or return "Illegal payby: ". $self->payby; + + # If it is encrypted and the private key is not availaible then we can't + # check the credit card. + + my $check_payinfo = 1; + + if ($self->is_encrypted($self->payinfo)) { + $check_payinfo = 0; + } + $self->payby($1); - if ( $self->payby eq 'CARD' || $self->payby eq 'DCRD' ) { + if ( $check_payinfo && ($self->payby eq 'CARD' || $self->payby eq 'DCRD')) { my $payinfo = $self->payinfo; $payinfo =~ s/\D//g; @@ -841,7 +936,7 @@ sub check { return gettext('unknown_card_type') if cardtype($self->payinfo) eq "Unknown"; if ( defined $self->dbdef_table->column('paycvv') ) { - if ( length($self->paycvv) ) { + if (length($self->paycvv) && !$self->is_encrypted($self->paycvv)) { if ( cardtype($self->payinfo) eq 'American Express card' ) { $self->paycvv =~ /^(\d{4})$/ or return "CVV2 (CID) for American Express cards is four digits."; @@ -856,7 +951,7 @@ sub check { } } - } elsif ( $self->payby eq 'CHEK' || $self->payby eq 'DCHK' ) { + } elsif ($check_payinfo && ( $self->payby eq 'CHEK' || $self->payby eq 'DCHK' )) { my $payinfo = $self->payinfo; $payinfo =~ s/[^\d\@]//g; @@ -2159,31 +2254,29 @@ sub realtime_refund_bop { $payname = "$payfirst $paylast"; } - if ( $method eq 'CC' ) { - - $content{card_number} = $self->payinfo; - $self->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; - $content{expiration} = "$2/$1"; - - #$content{cvv2} = $self->paycvv - # if defined $self->dbdef_table->column('paycvv') - # && length($self->paycvv); + my $payinfo = ''; + if ( $method eq 'CC' ) { - #$content{recurring_billing} = 'YES' - # if qsearch('cust_pay', { 'custnum' => $self->custnum, - # 'payby' => 'CARD', - # 'payinfo' => $self->payinfo, } ); + if ( $cust_pay ) { + $content{card_number} = $payinfo = $cust_pay->payinfo; + #$self->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; + #$content{expiration} = "$2/$1"; + } else { + $content{card_number} = $payinfo = $self->payinfo; + $self->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; + $content{expiration} = "$2/$1"; + } } elsif ( $method eq 'ECHECK' ) { ( $content{account_number}, $content{routing_code} ) = - split('@', $self->payinfo); + split('@', $payinfo = $self->payinfo); $content{bank_name} = $self->payname; $content{account_type} = 'CHECKING'; $content{account_name} = $payname; $content{customer_org} = $self->company ? 'B' : 'I'; $content{customer_ssn} = $self->ss; } elsif ( $method eq 'LEC' ) { - $content{phone} = $self->payinfo; + $content{phone} = $payinfo = $self->payinfo; } #then try refund @@ -2232,7 +2325,7 @@ sub realtime_refund_bop { 'refund' => $amount, '_date' => '', 'payby' => $method2payby{$method}, - 'payinfo' => $self->payinfo, + 'payinfo' => $payinfo, 'paybatch' => $paybatch, 'reason' => $options{'reason'} || 'card or ACH refund', } ); @@ -2480,15 +2573,17 @@ sub paydate_monthyear { =item payinfo_masked -Returns a "masked" payinfo field with all but the last four characters replaced -by 'x'es. Useful for displaying credit cards. +Returns a "masked" payinfo field appropriate to the payment type. Masked characters are replaced by 'x'es. Use this to display publicly accessable account Information. + +Credit Cards - Mask all but the last four characters. +Checks - Mask all but last 2 of account number and bank routing number. +Others - Do nothing, return the unmasked string. =cut sub payinfo_masked { my $self = shift; - my $payinfo = $self->payinfo; - 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4)); + return $self->paymask; } =item invoicing_list [ ARRAYREF ]