encryption fixes from huntsberg & jayce
authorivan <ivan>
Thu, 14 Dec 2006 06:00:46 +0000 (06:00 +0000)
committerivan <ivan>
Thu, 14 Dec 2006 06:00:46 +0000 (06:00 +0000)
18 files changed:
FS/FS/ClientAPI/MyAccount.pm
FS/FS/Record.pm
FS/FS/Schema.pm
FS/FS/cust_main.pm
FS/FS/cust_pay.pm
FS/FS/cust_pay_void.pm
FS/FS/cust_refund.pm
FS/FS/payinfo_Mixin.pm [new file with mode: 0644]
FS/MANIFEST
FS/t/payinfo_Mixin.t [new file with mode: 0644]
httemplate/edit/cust_main/billing.html
httemplate/edit/cust_refund.cgi
httemplate/edit/process/cust_main.cgi
httemplate/misc/payment.cgi
httemplate/misc/process/payment.cgi
httemplate/search/cust_pay.cgi
httemplate/view/cust_main/billing.html
httemplate/view/cust_main/payment_history.html

index ff5b775..de36472 100644 (file)
@@ -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'});
index 8f11fdb..29f2dc6 100644 (file)
@@ -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;
index a97c396..691edd7 100644 (file)
@@ -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, '', '', 
       ],
index 7127775..80b1a5b 100644 (file)
@@ -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.
index bc5fbab..a86bbc2 100644 (file)
@@ -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
 
index 946d69f..9a0e582 100644 (file)
@@ -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
index 8c672b8..a3a0e5e 100644 (file)
@@ -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 (file)
index 0000000..b1790c6
--- /dev/null
@@ -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;
+
index aeb0128..906cc9c 100644 (file)
@@ -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 (file)
index 0000000..3567c8e
--- /dev/null
@@ -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";
index 78a2002..ae56307 100644 (file)
 
   <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) %>">
   </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";'
 %  }
 %      '<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">'.
 %
 %          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>!.
 %                    '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 
 %                          : ''
 %      '<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">!.
 %      '<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">!.
index 2b3e026..aa825af 100755 (executable)
@@ -1,4 +1,3 @@
-<!-- mason kludge -->
 %
 %
 %my $conf = new FS::Conf;
 %
 %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') %>
 
index d5d127b..789f295 100755 (executable)
@@ -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
 %       && $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);
 %  
 %}
index 4c6ae33..081964e 100644 (file)
@@ -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;
index 027cd50..d591db1 100644 (file)
 %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;
index 87da179..98cc0e7 100755 (executable)
                    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' ) {
index d1be893..1f80dc5 100644 (file)
@@ -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
index 4f46ace..57d11b9 100644 (file)
@@ -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 {