summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/ClientAPI/MyAccount.pm4
-rw-r--r--FS/FS/Record.pm56
-rw-r--r--FS/FS/Schema.pm9
-rw-r--r--FS/FS/cust_main.pm87
-rw-r--r--FS/FS/cust_pay.pm66
-rw-r--r--FS/FS/cust_pay_void.pm11
-rw-r--r--FS/FS/cust_refund.pm47
-rw-r--r--FS/FS/payinfo_Mixin.pm245
-rw-r--r--FS/MANIFEST2
-rw-r--r--FS/t/payinfo_Mixin.t5
-rw-r--r--httemplate/edit/cust_main/billing.html26
-rwxr-xr-xhttemplate/edit/cust_refund.cgi147
-rwxr-xr-xhttemplate/edit/process/cust_main.cgi6
-rw-r--r--httemplate/misc/payment.cgi4
-rw-r--r--httemplate/misc/process/payment.cgi21
-rwxr-xr-xhttemplate/search/cust_pay.cgi2
-rw-r--r--httemplate/view/cust_main/billing.html8
-rw-r--r--httemplate/view/cust_main/payment_history.html4
18 files changed, 494 insertions, 256 deletions
diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm
index ff5b77565..de364724a 100644
--- a/FS/FS/ClientAPI/MyAccount.pm
+++ b/FS/FS/ClientAPI/MyAccount.pm
@@ -130,7 +130,7 @@ sub customer_info {
}
if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) {
- $return{payinfo} = $cust_main->payinfo_masked;
+ $return{payinfo} = $cust_main->paymask;
@return{'month', 'year'} = $cust_main->paydate_monthyear;
}
@@ -175,7 +175,7 @@ sub edit_info {
if ( $p->{'payby'} =~ /^(CARD|DCRD)$/ ) {
$new->paydate($p->{'year'}. '-'. $p->{'month'}. '-01');
- if ( $new->payinfo eq $cust_main->payinfo_masked ) {
+ if ( $new->payinfo eq $cust_main->paymask ) {
$new->payinfo($cust_main->payinfo);
} else {
$new->paycvv($p->{'paycvv'});
diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm
index 8f11fdbeb..29f2dc618 100644
--- a/FS/FS/Record.pm
+++ b/FS/FS/Record.pm
@@ -2,7 +2,8 @@ package FS::Record;
use strict;
use vars qw( $AUTOLOAD @ISA @EXPORT_OK $DEBUG
- $me %virtual_fields_cache $nowarn_identical );
+ $conf $me
+ %virtual_fields_cache $nowarn_identical );
use Exporter;
use Carp qw(carp cluck croak confess);
use File::CounterFile;
@@ -36,9 +37,11 @@ my $rsa_encrypt;
my $rsa_decrypt;
FS::UID->install_callback( sub {
- $File::CounterFile::DEFAULT_DIR = "/usr/local/etc/freeside/counters.". datasrc;
+ $conf = new FS::Conf;
+ $File::CounterFile::DEFAULT_DIR = $conf->base_dir . "/counters.". datasrc;
} );
+
=head1 NAME
FS::Record - Database record objects
@@ -442,8 +445,11 @@ sub qsearch {
}
# Check for encrypted fields and decrypt them.
- my $conf = new FS::Conf;
- if ($conf->exists('encryption') && eval 'defined(@FS::'. $table . '::encrypted_fields)') {
+ ## only in the local copy, not the cached object
+ if ( $conf && $conf->exists('encryption') # $conf doesn't exist when doing
+ # the initial search for
+ # access_user
+ && eval 'defined(@FS::'. $table . '::encrypted_fields)') {
foreach my $record (@return) {
foreach my $field (eval '@FS::'. $table . '::encrypted_fields') {
# Set it directly... This may cause a problem in the future...
@@ -713,11 +719,10 @@ sub insert {
# Encrypt before the database
- my $conf = new FS::Conf;
if ($conf->exists('encryption') && defined(eval '@FS::'. $table . '::encrypted_fields')) {
foreach my $field (eval '@FS::'. $table . '::encrypted_fields') {
$self->{'saved'} = $self->getfield($field);
- $self->setfield($field, $self->enrypt($self->getfield($field)));
+ $self->setfield($field, $self->encrypt($self->getfield($field)));
}
}
@@ -1006,7 +1011,7 @@ sub replace {
# Encrypt for replace
my $conf = new FS::Conf;
my $saved = {};
- if ($conf->exists('encryption') && defined(eval '@FS::'. $new->table . 'encrypted_fields')) {
+ if ($conf->exists('encryption') && defined(eval '@FS::'. $new->table . '::encrypted_fields')) {
foreach my $field (eval '@FS::'. $new->table . '::encrypted_fields') {
$saved->{$field} = $new->getfield($field);
$new->setfield($field, $new->encrypt($new->getfield($field)));
@@ -1205,6 +1210,12 @@ sub _h_statement {
grep { defined($self->getfield($_)) && $self->getfield($_) ne "" }
real_fields($self->table);
;
+
+ # If we're encrypting then don't ever store the payinfo or CVV2 in the history....
+ # You can see if it changed by the paymask...
+ if ($conf->exists('encryption') ) {
+ @fields = grep $_ ne 'payinfo' && $_ ne 'cvv2', @fields;
+ }
my @values = map { _quote( $self->getfield($_), $self->table, $_) } @fields;
"INSERT INTO h_". $self->table. " ( ".
@@ -1869,6 +1880,17 @@ sub _dump {
} (fields($self->table)) );
}
+=item encrypt($value)
+
+Encrypts the credit card using a combination of PK to encrypt and uuencode to armour.
+
+Returns the encrypted string.
+
+You should generally not have to worry about calling this, as the system handles this for you.
+
+=cut
+
+
sub encrypt {
my ($self, $value) = @_;
my $encrypted;
@@ -1893,17 +1915,32 @@ sub encrypt {
return $encrypted;
}
+=item is_encrypted($value)
+
+Checks to see if the string is encrypted and returns true or false (1/0) to indicate it's status.
+
+=cut
+
+
sub is_encrypted {
my ($self, $value) = @_;
# Possible Bug - Some work may be required here....
- if (length($value) > 80) {
+ if ($value =~ /^M/ && length($value) > 80) {
return 1;
} else {
return 0;
}
}
+=item decrypt($value)
+
+Uses the private key to decrypt the string. Returns the decryoted string or undef on failure.
+
+You should generally not have to worry about calling this, as the system handles this for you.
+
+=cut
+
sub decrypt {
my ($self,$value) = @_;
my $decrypted = $value; # Will return the original value if it isn't encrypted or can't be decrypted.
@@ -1912,7 +1949,8 @@ sub decrypt {
$self->loadRSA;
if (ref($rsa_decrypt) =~ /::RSA/) {
my $encrypted = unpack ("u*", $value);
- $decrypted = unpack("Z*", $rsa_decrypt->decrypt($encrypted));
+ $decrypted = unpack("Z*", eval{$rsa_decrypt->decrypt($encrypted)});
+ if ($@) {warn "Decryption Failed"};
}
}
return $decrypted;
diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index a97c396c5..691edd7a7 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -520,7 +520,8 @@ sub tables_hashref {
'payby', 'char', '', 4, '', '', # CARD/BILL/COMP, should be
# index into payby table
# eventually
- 'payinfo', 'varchar', 'NULL', $char_d, '', '', #see cust_main above
+ 'payinfo', 'varchar', 'NULL', 512, '', '', #see cust_main above
+ 'paymask', 'varchar', 'NULL', $char_d, '', '',
'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes.
'closed', 'char', 'NULL', 1, '', '',
],
@@ -538,7 +539,8 @@ sub tables_hashref {
'payby', 'char', '', 4, '', '', # CARD/BILL/COMP, should be
# index into payby table
# eventually
- 'payinfo', 'varchar', 'NULL', $char_d, '', '', #see cust_main above
+ 'payinfo', 'varchar', 'NULL', 512, '', '', #see cust_main above
+ 'paymask', 'varchar', 'NULL', $char_d, '', '',
'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes.
'closed', 'char', 'NULL', 1, '', '',
'void_date', @date_type, '', '',
@@ -677,7 +679,8 @@ sub tables_hashref {
'payby', 'char', '', 4, '', '', # CARD/BILL/COMP, should
# be index into payby
# table eventually
- 'payinfo', 'varchar', 'NULL', $char_d, '', '', #see cust_main above
+ 'payinfo', 'varchar', 'NULL', 512, '', '', #see cust_main above
+ 'paymask', 'varchar', 'NULL', $char_d, '', '',
'paybatch', 'varchar', 'NULL', $char_d, '', '',
'closed', 'char', 'NULL', 1, '', '',
],
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index 712777526..80b1a5b6e 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -50,8 +50,9 @@ use FS::type_pkgs;
use FS::payment_gateway;
use FS::agent_payment_gateway;
use FS::banned_pay;
+use FS::payinfo_Mixin;
-@ISA = qw( FS::Record );
+@ISA = qw( FS::Record FS::payinfo_Mixin );
@EXPORT_OK = qw( smart_search );
@@ -189,81 +190,15 @@ FS::Record. The following fields are currently supported:
=item ship_fax - phone (optional)
-=item payby
+=item payby - Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
-I<CARD> (credit card - automatic), I<DCRD> (credit card - on-demand), I<CHEK> (electronic check - automatic), I<DCHK> (electronic check - on-demand), I<LECB> (Phone bill billing), I<BILL> (billing), I<COMP> (free), or I<PREPAY> (special billing type: applies a credit - see L<FS::prepay_credit> and sets billing type to I<BILL>)
-
-=item payinfo
-
-Card Number, P.O., comp issuer (4-8 lowercase alphanumerics; think username) or prepayment identifier (see L<FS::prepay_credit>)
-
-=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 payinfo - Payment Information (See L<FS::payinfo_Mixin> for data format)
+=item paymask - Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
=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 'DCRD') { # 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;
-}
+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
@@ -1141,11 +1076,6 @@ 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 } );
@@ -1486,11 +1416,10 @@ sub check {
$payinfo =~ s/[^\d\@]//g;
if ( $conf->exists('echeck-nonus') ) {
$payinfo =~ /^(\d+)\@(\d+)$/ or return 'invalid echeck account@aba';
- $payinfo = "$1\@$2";
} else {
$payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account@aba';
- $payinfo = "$1\@$2";
}
+ $payinfo = "$1\@$2";
$self->payinfo($payinfo);
$self->paycvv('') if $self->dbdef_table->column('paycvv');
@@ -3405,6 +3334,8 @@ sub paydate_monthyear {
=item payinfo_masked
+< DEPRICATED > Use $self->paymask
+
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.
diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm
index bc5fbab08..a86bbc23a 100644
--- a/FS/FS/cust_pay.pm
+++ b/FS/FS/cust_pay.pm
@@ -1,7 +1,7 @@
package FS::cust_pay;
use strict;
-use vars qw( @ISA $conf $unsuspendauto $ignore_noapply );
+use vars qw( @ISA $conf $unsuspendauto $ignore_noapply @encrypted_fields );
use Date::Format;
use Business::CreditCard;
use Text::Template;
@@ -14,7 +14,7 @@ use FS::cust_pay_refund;
use FS::cust_main;
use FS::cust_pay_void;
-@ISA = qw( FS::cust_main_Mixin FS::Record );
+@ISA = qw(FS::Record FS::cust_main_Mixin FS::payinfo_Mixin );
$ignore_noapply = 0;
@@ -24,6 +24,8 @@ FS::UID->install_callback( sub {
$unsuspendauto = $conf->exists('unsuspendauto');
} );
+@encrypted_fields = ('payinfo');
+
=head1 NAME
FS::cust_pay - Object methods for cust_pay objects
@@ -60,12 +62,11 @@ currently supported:
=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
L<Time::Local> and L<Date::Parse> for conversion functions.
-=item payby - `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), or
-`COMP' (free)
+=item payby - Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
+
+=item payinfo - Payment Information (See L<FS::payinfo_Mixin> for data format)
-=item payinfo - card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively
+=item paymask - Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
=item paybatch - text field for tracking card processing
@@ -327,7 +328,7 @@ sub delete {
'paid: $'. sprintf("%.2f", $self->paid). "\n",
'date: '. time2str("%a %b %e %T %Y", $self->_date). "\n",
'payby: '. $self->payby. "\n",
- 'payinfo: '. $self->payinfo. "\n",
+ 'payinfo: '. $self->paymask. "\n",
'paybatch: '. $self->paybatch. "\n",
],
);
@@ -375,6 +376,7 @@ sub check {
|| $self->ut_numbern('_date')
|| $self->ut_textn('paybatch')
|| $self->ut_enum('closed', [ '', 'Y' ])
+ || $self->payinfo_check()
;
return $error if $error;
@@ -386,30 +388,6 @@ sub check {
$self->_date(time) unless $self->_date;
- $self->payby =~ /^(CARD|CHEK|LECB|BILL|COMP|PREP|CASH|WEST|MCRD)$/
- or return "Illegal payby";
- $self->payby($1);
-
- #false laziness with cust_refund::check
- if ( $self->payby eq 'CARD' ) {
- my $payinfo = $self->payinfo;
- $payinfo =~ s/\D//g;
- $self->payinfo($payinfo);
- if ( $self->payinfo ) {
- $self->payinfo =~ /^(\d{13,16})$/
- 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 cardtype($self->payinfo) eq "Unknown";
- } else {
- $self->payinfo('N/A');
- }
-
- } else {
- $error = $self->ut_textn('payinfo');
- return $error if $error;
- }
-
$self->SUPER::check;
}
@@ -542,31 +520,27 @@ sub cust_main {
=item payinfo_masked
-Returns a "masked" payinfo field with all but the last four characters replaced
-by 'x'es. Useful for displaying credit cards.
+<DEPRICATED> Use $self->paymask
+
+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;
- #some false laziness w/cust_main::paymask
- if ( $self->payby eq 'CARD' ) {
- my $payinfo = $self->payinfo;
- 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4));
- } elsif ( $self->payby eq 'CHEK' ) {
- my( $account, $aba ) = split('@', $self->payinfo );
- 'x'x(length($account)-2). substr($account,(length($account)-2)). "@". $aba;
- } else {
- $self->payinfo;
- }
+ return $self->paymask;
}
+
=back
=head1 BUGS
-Delete and replace methods. payinfo_masked false laziness with cust_main.pm
-and cust_refund.pm
+Delete and replace methods.
=head1 SEE ALSO
diff --git a/FS/FS/cust_pay_void.pm b/FS/FS/cust_pay_void.pm
index 946d69fe1..9a0e58293 100644
--- a/FS/FS/cust_pay_void.pm
+++ b/FS/FS/cust_pay_void.pm
@@ -1,6 +1,6 @@
package FS::cust_pay_void;
use strict;
-use vars qw( @ISA );
+use vars qw( @ISA @encrypted_fields );
use Business::CreditCard;
use FS::UID qw(getotaker);
use FS::Record qw(qsearchs dbh fields); # qsearch );
@@ -10,7 +10,9 @@ use FS::cust_pay;
#use FS::cust_pay_refund;
#use FS::cust_main;
-@ISA = qw( FS::Record );
+@ISA = qw( FS::Record FS::payinfo_Mixin );
+
+@encrypted_fields = ('payinfo');
=head1 NAME
@@ -209,6 +211,8 @@ sub cust_main {
=item payinfo_masked
+< DEPRICATED > Use $self->paymask
+
Returns a "masked" payinfo field with all but the last four characters replaced
by 'x'es. Useful for displaying credit cards.
@@ -216,8 +220,7 @@ by 'x'es. Useful for displaying credit cards.
sub payinfo_masked {
my $self = shift;
- my $payinfo = $self->payinfo;
- 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4));
+ return $self->paymask;
}
=back
diff --git a/FS/FS/cust_refund.pm b/FS/FS/cust_refund.pm
index 8c672b8d7..a3a0e5ede 100644
--- a/FS/FS/cust_refund.pm
+++ b/FS/FS/cust_refund.pm
@@ -1,7 +1,7 @@
package FS::cust_refund;
use strict;
-use vars qw( @ISA );
+use vars qw( @ISA @encrypted_fields );
use Business::CreditCard;
use FS::Record qw( qsearch qsearchs dbh );
use FS::UID qw(getotaker);
@@ -9,8 +9,11 @@ use FS::cust_credit;
use FS::cust_credit_refund;
use FS::cust_pay_refund;
use FS::cust_main;
+use FS::payinfo_Mixin;
-@ISA = qw( FS::Record );
+@ISA = qw( FS::Record FS::payinfo_Mixin );
+
+@encrypted_fields = ('payinfo');
=head1 NAME
@@ -50,11 +53,11 @@ inherits from FS::Record. The following fields are currently supported:
=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
L<Time::Local> and L<Date::Parse> for conversion functions.
-=item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH),
-`LECB' (Phone bill billing), `BILL' (billing), `CASH' (cash),
-`WEST' (Western Union), `MCRD' (Manual credit card), or `COMP' (free)
+=item payby - Payment Type (See L<FS::payinfo_Mixin> for valid payby values)
+
+=item payinfo - Payment Information (See L<FS::payinfo_Mixin> for data format)
-=item payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username)
+=item paymask - Masked payinfo (See L<FS::payinfo_Mixin> for how this works)
=item paybatch - text field for tracking card processing
@@ -212,29 +215,8 @@ sub check {
unless $self->crednum
|| qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
- $self->payby =~ /^(CARD|CHEK|LECB|BILL|COMP|CASH|WEST|MCRD)$/
- or return "Illegal payby";
- $self->payby($1);
-
- #false laziness with cust_pay::check
- if ( $self->payby eq 'CARD' ) {
- my $payinfo = $self->payinfo;
- $payinfo =~ s/\D//g;
- $self->payinfo($payinfo);
- if ( $self->payinfo ) {
- $self->payinfo =~ /^(\d{13,16})$/
- 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 cardtype($self->payinfo) eq "Unknown";
- } else {
- $self->payinfo('N/A');
- }
-
- } else {
- $error = $self->ut_textn('payinfo');
- return $error if $error;
- }
+ $error = $self->payinfo_check;
+ return $error if $error;
$self->otaker(getotaker);
@@ -285,10 +267,10 @@ sub unapplied {
sprintf("%.2f", $amount );
}
-
-
=item payinfo_masked
+<DEPRICATED> Use $self->paymask
+
Returns a "masked" payinfo field with all but the last four characters replaced
by 'x'es. Useful for displaying credit cards.
@@ -297,8 +279,7 @@ by 'x'es. Useful for displaying credit cards.
sub payinfo_masked {
my $self = shift;
- my $payinfo = $self->payinfo;
- 'x'x(length($payinfo)-4). substr($payinfo,(length($payinfo)-4));
+ return $self->paymask;
}
diff --git a/FS/FS/payinfo_Mixin.pm b/FS/FS/payinfo_Mixin.pm
new file mode 100644
index 000000000..b1790c625
--- /dev/null
+++ b/FS/FS/payinfo_Mixin.pm
@@ -0,0 +1,245 @@
+package FS::payinfo_Mixin;
+
+use strict;
+use Business::CreditCard;
+
+=head1 NAME
+
+FS::payinfo_Mixin - Mixin class for records in tables that contain payinfo.
+
+=head1 SYNOPSIS
+
+package FS::some_table;
+use vars qw(@ISA);
+@ISA = qw( FS::payinfo_Mixin FS::Record );
+
+=head1 DESCRIPTION
+
+This is a mixin class for records that contain payinfo.
+
+This class handles the following functions for payinfo...
+
+Payment Mask (Generation and Storage)
+Data Validation (parent checks need to be sure to call this)
+Encryption - In the Future (Pull from Record.pm)
+Bad Card Stuff - In the Future (Integrate Banned Pay)
+Currency - In the Future
+
+=head1 fields
+
+=over 4
+
+=item payby
+
+The following payment types (payby) are supported:
+
+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<FS::prepay_credit> and sets billing type to I<BILL>)
+
+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 payby {
+ my($self,$payby) = @_;
+ if ( defined($payby) ) {
+ $self->setfield('payby', $payby);
+ }
+ return $self->getfield('payby')
+}
+
+
+=item payinfo
+
+Payment information (payinfo) can be one of the following types:
+
+Card Number, P.O., comp issuer (4-8 lowercase alphanumerics; think username) or prepayment identifier (see L<FS::prepay_credit>)
+
+=cut
+
+sub payinfo {
+ my($self,$payinfo) = @_;
+ if ( defined($payinfo) ) {
+ $self->setfield('payinfo', $payinfo); # This is okay since we are the 'setter'
+ $self->paymask($self->mask_payinfo());
+ } 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
+
+sub paycvv {
+ my($self,$paycvv) = @_;
+ # This is only allowed in cust_main... Even then it really shouldn't be stored...
+ if ($self->table eq 'cust_main') {
+ if ( defined($paycvv) ) {
+ $self->setfield('paycvv', $paycvv); # This is okay since we are the 'setter'
+ } else {
+ $paycvv = $self->getfield('paycvv'); # This is okay since we are the 'getter'
+ return $paycvv;
+ }
+ } else {
+# warn "This doesn't work for other tables besides cust_main
+ }
+}
+
+=item paymask
+
+=cut
+
+sub paymask {
+ my($self,$paymask)=@_;
+
+
+ if ($paymask ne '') {
+ # I hate this little bit of magic... I don't expect it to cause a problem, but who knows...
+ # If the payinfo is passed in masked then ignore it and set it based on the payinfo
+ # The only guy that should call this in this way is... $self->payinfo
+ $self->setfield('paymask', $self->mask_payinfo());
+ } else {
+ $paymask=$self->getfield('paymask');
+ if (!defined($paymask) || $paymask eq '') {
+ # Generate it if it's blank - Note that we're not going to set it - just generate
+ $paymask = $self->mask_payinfo();
+ }
+ }
+ return $paymask;
+}
+
+=item mask_payinfo()
+
+This method converts the payment info (credit card, bank account, etc.) into a masked string.
+
+=cut
+
+sub mask_payinfo {
+ my $self = shift;
+ my $paymask;
+ my $payinfo = $self->payinfo;
+ my $payby = $self->payby;
+ # Check to see if it's encrypted...
+ if ($self->is_encrypted($payinfo)) {
+ $paymask = 'N/A';
+ } 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));
+ } 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;
+ }
+ }
+ return $paymask;
+}
+
+=back
+
+
+=head1 METHODS
+
+=over 4
+
+=item payinfo_check
+
+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<FS::prepay_credit> and sets billing type to I<BILL>)
+
+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 {
+ 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)";
+ }
+ }
+
+ if ( $self->payby eq 'CARD' ) {
+ my $payinfo = $self->payinfo;
+ $payinfo =~ s/\D//g;
+ $self->payinfo($payinfo);
+ if ( $self->payinfo ) {
+ $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";
+ } else {
+ $self->payinfo('N/A');
+ }
+ } else {
+ my $error = $self->ut_textn('payinfo');
+ return $error if $error;
+ }
+}
+
+
+
+=head1 BUGS
+
+Have to add the future items...
+
+=head1 SEE ALSO
+
+L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/MANIFEST b/FS/MANIFEST
index aeb012851..906cc9cdb 100644
--- a/FS/MANIFEST
+++ b/FS/MANIFEST
@@ -81,6 +81,7 @@ FS/h_svc_external.pm
FS/h_svc_forward.pm
FS/h_svc_www.pm
FS/part_bill_event.pm
+FS/payinfo_Mixin.pm
FS/export_svc.pm
FS/part_export.pm
FS/part_export_option.pm
@@ -272,6 +273,7 @@ t/part_referral.t
t/part_svc.t
t/part_svc_column.t
t/payby.t
+t/payinfo_Mixin.t
t/pkg_class.t
t/pkg_svc.t
t/port.t
diff --git a/FS/t/payinfo_Mixin.t b/FS/t/payinfo_Mixin.t
new file mode 100644
index 000000000..3567c8e08
--- /dev/null
+++ b/FS/t/payinfo_Mixin.t
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::payinfo_Mixin;
+$loaded=1;
+print "ok 1\n";
diff --git a/httemplate/edit/cust_main/billing.html b/httemplate/edit/cust_main/billing.html
index 78a2002a4..ae5630739 100644
--- a/httemplate/edit/cust_main/billing.html
+++ b/httemplate/edit/cust_main/billing.html
@@ -23,7 +23,10 @@
<FORM NAME="<% $cust_main->payby %>" STYLE="margin-top: 0; margin-bottom: 0">
% # XXX key
-% foreach my $field (qw( payinfo payname paycvv paystart_month paystart_year payissue payip )) {
+
+
+ <INPUT TYPE="hidden" NAME="payinfo" VALUE="<% $cust_main->paymask %>">
+% foreach my $field (qw( payname paycvv paystart_month paystart_year payissue payip )) {
<INPUT TYPE="hidden" NAME="<% $field %>" VALUE="<% $cust_main->getfield($field) %>">
@@ -136,16 +139,19 @@
</SCRIPT>
%
%
-% my($payby, $payinfo, $payname)=(
+% my($payby, $paymask, $payname)=(
% $cust_main->payby,
-% $cust_main->payinfo,
+% $cust_main->paymask,
% $cust_main->payname,
% );
-% my( $account, $aba ) = split('@', $payinfo);
+% my( $account, $aba ) = split('@', $paymask);
%
% my $disabled = 'DISABLED style="background-color: #dddddd"';
% my $text_disabled = 'style="color: #999999"';
-% if ( $payby =~ /^(CARD|DCRD)$/ && cardtype($payinfo) =~ /^(Switch|Solo)$/ ) {
+%
+% # 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";'
% }
@@ -157,7 +163,7 @@
% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'.
%
% qq!<TR><TD ALIGN="right" WIDTH="200">${r}Card number </TD>!.
-% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payinfo" VALUE="!. ( $payby =~ /^(CARD|DCRD)$/ ? $payinfo : '' ). qq!" MAXLENGTH=19 onChange="card_changed(this)" onKeyUp="card_changed(this)"></TD></TR>!.
+% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payinfo" VALUE="!. ( $payby =~ /^(CARD|DCRD)$/ ? $paymask : '' ). qq!" MAXLENGTH=19 onChange="card_changed(this)" onKeyUp="card_changed(this)"></TD></TR>!.
%
% qq!<TR><TD ALIGN="right" WIDTH="200">${r}Expiration </TD>!.
% '<TD WIDTH="408">'.
@@ -174,7 +180,7 @@
%
% qq!(<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('../docs/cvv2.html', 480, 352, 'cvv2_popup' ), CAPTION, 'CVV2 Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;">help</A>)!.
% qq!</TD>!.
-% '<TD WIDTH="408"><INPUT TYPE="text" NAME="paycvv" VALUE="'. ( $payby =~ /^(CARD|DCRD)$/ ? $cust_main->paycvv : '' ). '" SIZE=4 MAXLENGTH=4>'.
+% '<TD WIDTH="408"><INPUT TYPE="text" NAME="paycvv" VALUE="'. ( $payby =~ /^(CARD|DCRD)$/ && !$cust_main->is_encrypted($cust_main->paycvv) ? $cust_main->paycvv : '' ). '" SIZE=4 MAXLENGTH=4>'.
%
%
% qq!<TR><TD ALIGN="right" WIDTH="200"><SPAN ID="paystart_label" $text_disabled>Start date </SPAN></TD>!.
@@ -188,7 +194,7 @@
% 'end_year' => (localtime())[5] + 1900,
% 'selected_date' => (
% ( $payby =~ /^(CARD|DCRD)$/
-% && cardtype($payinfo) =~ /^(Switch|Solo)$/ )
+% && cardtype($paymask) =~ /^(Switch|Solo)$/ ) #also
% ? $cust_main->paystart_month. '-'.
% $cust_main->paystart_year
% : ''
@@ -236,7 +242,7 @@
% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'.
%
% qq!<TR><TD ALIGN="right" WIDTH="200">${r}Phone number </TD>!.
-% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payinfo" VALUE="!. ( $payby eq 'LECB' ? $cust_main->payinfo : '' ). qq!" MAXLENGTH=15 SIZE=16></TD></TR>!.
+% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payinfo" VALUE="!. ( $payby eq 'LECB' ? $cust_main->paymask : '' ). qq!" MAXLENGTH=15 SIZE=16></TD></TR>!.
%
% qq!<INPUT TYPE="hidden" NAME="exp_month" VALUE="12">!.
% qq!<INPUT TYPE="hidden" NAME="exp_year" VALUE="2037">!.
@@ -256,7 +262,7 @@
% '<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0 HEIGHT=192>'.
%
% qq!<TR><TD ALIGN="right" WIDTH="200">P.O. </TD>!.
-% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payinfo" VALUE="!. ( $payby eq 'BILL' ? $cust_main->payinfo : '' ). qq!"></TD></TR>!.
+% qq!<TD WIDTH="408"><INPUT TYPE="text" NAME="payinfo" VALUE="!. ( $payby eq 'BILL' ? $cust_main->paymask : '' ). qq!"></TD></TR>!.
%
% qq!<INPUT TYPE="hidden" NAME="exp_month" VALUE="12">!.
% qq!<INPUT TYPE="hidden" NAME="exp_year" VALUE="2037">!.
diff --git a/httemplate/edit/cust_refund.cgi b/httemplate/edit/cust_refund.cgi
index 2b3e02614..aa825af94 100755
--- a/httemplate/edit/cust_refund.cgi
+++ b/httemplate/edit/cust_refund.cgi
@@ -1,4 +1,3 @@
-<!-- mason kludge -->
%
%
%my $conf = new FS::Conf;
@@ -26,70 +25,102 @@
%
%my $p1 = popurl(1);
%
-%print header('Refund '. ucfirst(lc($payby)). ' payment', '');
-%print qq!<FONT SIZE="+1" COLOR="#ff0000">Error: !, $cgi->param('error'),
-% "</FONT>"
-% if $cgi->param('error');
-%print <<END, small_custview($custnum, $conf->config('countrydefault'));
-% <FORM ACTION="${p1}process/cust_refund.cgi" METHOD=POST>
-% <INPUT TYPE="hidden" NAME="refundnum" VALUE="">
-% <INPUT TYPE="hidden" NAME="custnum" VALUE="$custnum">
-% <INPUT TYPE="hidden" NAME="paynum" VALUE="$paynum">
-% <INPUT TYPE="hidden" NAME="_date" VALUE="$_date">
-% <INPUT TYPE="hidden" NAME="payby" VALUE="$payby">
-% <INPUT TYPE="hidden" NAME="payinfo" VALUE="">
-% <INPUT TYPE="hidden" NAME="paybatch" VALUE="">
-% <INPUT TYPE="hidden" NAME="credited" VALUE="">
-% <BR>
-%END
%
-%if ( $cust_pay ) {
+
+
+<% include('/elements/header.html', 'Refund '. ucfirst(lc($payby)). ' payment', '') %>
+% if ( $cgi->param('error') ) {
+
+ <FONT SIZE="+1" COLOR="#ff0000">Error: <% $cgi->param('error') %></FONT>
+ <BR><BR>
+% }
+
+
+<% small_custview($custnum, $conf->config('countrydefault')) %>
+
+<FORM NAME="RefundForm" ACTION="<% $p1 %>process/cust_refund.cgi" METHOD=POST onSubmit="document.RefundForm.submit.disabled=true">
+<INPUT TYPE="hidden" NAME="refundnum" VALUE="">
+<INPUT TYPE="hidden" NAME="custnum" VALUE="<% $custnum %>">
+<INPUT TYPE="hidden" NAME="paynum" VALUE="<% $paynum %>">
+<INPUT TYPE="hidden" NAME="_date" VALUE="<% $_date %>">
+<INPUT TYPE="hidden" NAME="payby" VALUE="<% $payby %>">
+<INPUT TYPE="hidden" NAME="payinfo" VALUE="">
+<INPUT TYPE="hidden" NAME="paybatch" VALUE="">
+<INPUT TYPE="hidden" NAME="credited" VALUE="">
+<BR>
+% if ( $cust_pay ) {
%
% #false laziness w/FS/FS/cust_pay.pm
% my $payby = $cust_pay->payby;
-% my $payinfo = $cust_pay->payinfo;
-% $payby =~ s/^BILL$/Check/ if $payinfo;
+% my $paymask = $cust_pay->paymask;
+% $payby =~ s/^BILL$/Check/ if $paymask;
% $payby =~ s/^CHEK$/Electronic check/;
-% $payinfo = $cust_pay->payinfo_masked if $payby eq 'CARD';
%
-% print '<BR>Payment'. ntable("#cccccc", 2).
-% '<TR><TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">$'.
-% $cust_pay->paid. '</TD></TR>'.
-% '<TR><TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff">'.
-% time2str("%D",$cust_pay->_date). '</TD></TR>'.
-% '<TR><TD ALIGN="right">Method</TD><TD BGCOLOR="#ffffff">'.
-% ucfirst(lc($payby)). ' # '. $payinfo. '</TD></TR>';
+%
+
+
+ <BR>Payment
+ <% ntable("#cccccc", 2) %>
+
+ <TR>
+ <TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">$<% $cust_pay->paid %></TD>
+ </TR>
+
+ <TR>
+ <TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff"><% time2str("%D",$cust_pay->_date) %></TD>
+ </TR>
+
+ <TR>
+ <TD ALIGN="right">Method</TD><TD BGCOLOR="#ffffff"><% ucfirst(lc($payby)) %> # <% $paymask %></TD>
+ </TR>
+%
% #false laziness w/FS/FS/cust_main::realtime_refund_bop
% if ( $cust_pay->paybatch =~ /^(\w+):(\w+)(:(\w+))?$/ ) {
% my ( $processor, $auth, $order_number ) = ( $1, $2, $4 );
-% print '<TR><TD ALIGN="right">Processor</TD><TD BGCOLOR="#ffffff">'.
-% $processor. '</TD></TR>';
-% print '<TR><TD ALIGN="right">Authorization</TD><TD BGCOLOR="#ffffff">'.
-% $auth. '</TD></TR>'
-% if length($auth);
-% print '<TR><TD ALIGN="right">Order number</TD><TD BGCOLOR="#ffffff">'.
-% $order_number. '</TD></TR>'
-% if length($order_number);
-% }
-% print '</TABLE>';
-%}
-%
-%print '<BR>Refund'. ntable("#cccccc", 2).
-% '<TR><TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff">'.
-% time2str("%D",$_date). '</TD></TR>';
-%
-%print qq!<TR><TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">\$<INPUT TYPE="text" NAME="refund" VALUE="$refund" SIZE=8 MAXLENGTH=8></TD></TR>!;
-%
-%print qq!<TR><TD ALIGN="right">Reason</TD><TD BGCOLOR="#ffffff"><INPUT TYPE="text" NAME="reason" VALUE="$reason"></TD></TR>!;
-%
-%print <<END;
-%</TABLE>
-%<BR>
-%<INPUT TYPE="submit" VALUE="Post refund">
-% </FORM>
-% </BODY>
-%</HTML>
-%END
-%
-%
+%
+
+
+ <TR>
+ <TD ALIGN="right">Processor</TD><TD BGCOLOR="#ffffff"><% $processor %></TD>
+ </TR>
+% if ( length($auth) ) {
+
+ <TR>
+ <TD ALIGN="right">Authorization</TD><TD BGCOLOR="#ffffff"><% $auth %></TD>
+ </TR>
+% }
+% if ( length($order_number) ) {
+
+ <TR>
+ <TD ALIGN="right">Order number</TD><TD BGCOLOR="#ffffff"><% $order_number %></TD>
+ </TR>
+% }
+% }
+
+ </TABLE>
+% }
+
+
+<BR>Refund
+<% ntable("#cccccc", 2) %>
+
+ <TR>
+ <TD ALIGN="right">Date</TD><TD BGCOLOR="#ffffff"><% time2str("%D",$_date) %></TD>
+ </TR>
+
+ <TR>
+ <TD ALIGN="right">Amount</TD><TD BGCOLOR="#ffffff">$<INPUT TYPE="text" NAME="refund" VALUE="<% $refund %>" SIZE=8 MAXLENGTH=8></TD>
+ </TR>
+
+ <TR>
+ <TD ALIGN="right">Reason</TD><TD BGCOLOR="#ffffff"><INPUT TYPE="text" NAME="reason" VALUE="<% $reason %>"></TD>
+ </TR>
+</TABLE>
+
+<BR>
+<INPUT TYPE="submit" NAME="submit" VALUE="Post refund">
+
+</FORM>
+
+<% include('/elements/footer.html') %>
diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi
index d5d127b2d..789f29522 100755
--- a/httemplate/edit/process/cust_main.cgi
+++ b/httemplate/edit/process/cust_main.cgi
@@ -46,6 +46,9 @@
% } fields('cust_main')
%} );
%
+% delete( $new->hashref->{'agent_custid'} )
+% unless $new->hashref->{'agent_custid'};
+%
%if ( defined($cgi->param('same')) && $cgi->param('same') eq "Y" ) {
% $new->setfield("ship_$_", '') foreach qw(
% last first company address1 address2 city county state zip
@@ -151,6 +154,9 @@
% && $new->paycvv =~ /^\s*\*+\s*$/ ) {
% $new->paycvv($old->paycvv);
% }
+% if ($new->payby =~ /CARD|DCRD|CHEK|DCHK/ && $new->payinfo =~ /xx/) {
+% $new->payinfo($old->payinfo);
+% }
% $error ||= $new->replace($old, \@invoicing_list);
%
%}
diff --git a/httemplate/misc/payment.cgi b/httemplate/misc/payment.cgi
index 4c6ae3349..081964e93 100644
--- a/httemplate/misc/payment.cgi
+++ b/httemplate/misc/payment.cgi
@@ -67,7 +67,7 @@ function OLiframeContent(src, width, height, name) {
% my $state = $cust_main->state;
% my $zip = $cust_main->zip;
% if ( $cust_main->payby =~ /^(CARD|DCRD)$/ ) {
-% $payinfo = $cust_main->payinfo;
+% $payinfo = $cust_main->paymask;
% $paycvv = $cust_main->paycvv;
% ( $month, $year ) = $cust_main->paydate_monthyear;
% $payname = $cust_main->payname if $cust_main->payname;
@@ -153,7 +153,7 @@ function OLiframeContent(src, width, height, name) {
% } elsif ( $payby eq 'CHEK' ) {
% my( $payinfo1, $payinfo2, $payname, $ss ) = ( '', '', '', '' );
% if ( $cust_main->payby =~ /^(CHEK|DCHK)$/ ) {
-% $cust_main->payinfo =~ /^(\d+)\@(\d+)$/
+% $cust_main->paymask =~ /^(\d+)\@(\d+)$/
% or die "unparsable payinfo ". $cust_main->payinfo;
% ($payinfo1, $payinfo2) = ($1, $2);
% $payname = $cust_main->payname;
diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi
index 027cd502a..d591db1e8 100644
--- a/httemplate/misc/process/payment.cgi
+++ b/httemplate/misc/process/payment.cgi
@@ -44,17 +44,24 @@
%my $paycvv = '';
%if ( $payby eq 'CHEK' ) {
%
-% $cgi->param('payinfo1') =~ /^(\d+)$/
-% or eidiot "illegal account number ". $cgi->param('payinfo1');
-% my $payinfo1 = $1;
-% $cgi->param('payinfo2') =~ /^(\d+)$/
-% or eidiot "illegal ABA/routing number ". $cgi->param('payinfo2');
-% my $payinfo2 = $1;
-% $payinfo = $payinfo1. '@'. $payinfo2;
+% if ($cgi->param('payinfo1') =~ /xx/ || $cgi->param('payinfo2') =~ /xx/ ) {
+% $payinfo = $cust_main->payinfo;
+% } else {
+% $cgi->param('payinfo1') =~ /^(\d+)$/
+% or eidiot "illegal account number ". $cgi->param('payinfo1');
+% my $payinfo1 = $1;
+% $cgi->param('payinfo2') =~ /^(\d+)$/
+% or eidiot "illegal ABA/routing number ". $cgi->param('payinfo2');
+% my $payinfo2 = $1;
+% $payinfo = $payinfo1. '@'. $payinfo2;
+% }
%
%} elsif ( $payby eq 'CARD' ) {
%
% $payinfo = $cgi->param('payinfo');
+% if ($payinfo eq $cust_main->paymask) {
+% $payinfo = $cust_main->payinfo;
+% }
% $payinfo =~ s/\D//g;
% $payinfo =~ /^(\d{13,16})$/
% or eidiot gettext('invalid_card'); # . ": ". $self->payinfo;
diff --git a/httemplate/search/cust_pay.cgi b/httemplate/search/cust_pay.cgi
index 87da1791b..98cc0e799 100755
--- a/httemplate/search/cust_pay.cgi
+++ b/httemplate/search/cust_pay.cgi
@@ -164,7 +164,7 @@
sub {
my $cust_pay = shift;
if ( $cust_pay->payby eq 'CARD' ) {
- 'Card #'. $cust_pay->payinfo_masked;
+ 'Card #'. $cust_pay->paymask;
} elsif ( $cust_pay->payby eq 'CHEK' ) {
'E-check acct#'. $cust_pay->payinfo;
} elsif ( $cust_pay->payby eq 'BILL' ) {
diff --git a/httemplate/view/cust_main/billing.html b/httemplate/view/cust_main/billing.html
index d1be8936f..1f80dc5bc 100644
--- a/httemplate/view/cust_main/billing.html
+++ b/httemplate/view/cust_main/billing.html
@@ -7,7 +7,11 @@
Billing information
-(<A HREF="<% $p %>misc/bill.cgi?<% $cust_main->custnum %>">Bill now</A>)
+% # If we can't see the unencrypted card, then bill now is an exercise in frustration
+%if ( ! $cust_main->is_encrypted($cust_main->payinfo) ) {
+ (<A HREF="<% $p %>misc/bill.cgi?<% $cust_main->custnum %>">Bill now</A>)
+% }
+
<% ntable("#cccccc") %><TR><TD><% ntable("#cccccc",2) %>
%
%( my $balance = $cust_main->balance )
@@ -31,7 +35,7 @@ Billing information
</TR>
<TR>
<TD ALIGN="right">Card number</TD>
- <TD BGCOLOR="#ffffff"><% $cust_main->payinfo_masked %></TD>
+ <TD BGCOLOR="#ffffff"><% $cust_main->paymask %></TD>
</TR>
%
%#false laziness w/elements/select-month_year.html & edit/cust_main/billing.html
diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html
index 4f46ace6d..57d11b9e8 100644
--- a/httemplate/view/cust_main/payment_history.html
+++ b/httemplate/view/cust_main/payment_history.html
@@ -18,6 +18,7 @@
% if ( ( $payby{'CARD'} || $payby{'DCRD'} )
% && $curuser->access_right('Process payment')
+% && ! $cust_main->is_encrypted($cust_main->payinfo)
% ) {
<% $s++ ? ' | ' : '' %>
<A HREF="<% $p %>misc/payment.cgi?payby=CARD;custnum=<% $custnum %>">Process credit card payment</A>
@@ -25,6 +26,7 @@
% if ( ( $payby{'CHEK'} || $payby{'DCHK'} )
% && $curuser->access_right('Process payment')
+% && ! $cust_main->is_encrypted($cust_main->payinfo)
% ) {
<% $s++ ? ' | ' : '' %>
<A HREF="<% $p %>misc/payment.cgi?payby=CHEK;custnum=<% $custnum %>">Process electronic check (ACH) payment</A>
@@ -76,7 +78,7 @@
%
% my $payinfo;
% if ( $payby eq 'CARD' ) {
-% $payinfo = $cust_pay->payinfo_masked;
+% $payinfo = $cust_pay->paymask;
% } elsif ( $payby eq 'CHEK' && $cust_pay->payinfo =~ /^(\d+)\@(\d+)$/ ) {
% $payinfo = "ABA $2, Acct# $1";
% } else {