communigate provisioning phase 2: add svc_domain.trailer -> communigate TrailerText...
[freeside.git] / FS / FS / payinfo_Mixin.pm
index b1790c6..99cca6a 100644 (file)
@@ -2,6 +2,7 @@ package FS::payinfo_Mixin;
 
 use strict;
 use Business::CreditCard;
+use FS::payby;
 
 =head1 NAME
 
@@ -21,11 +22,9 @@ 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
+Pretty printing
 
-=head1 fields
+=head1 FIELDS
 
 =over 4
 
@@ -37,12 +36,12 @@ For Customers (cust_main):
 'CARD' (credit card - automatic), 'DCRD' (credit card - on-demand),
 'CHEK' (electronic check - automatic), 'DCHK' (electronic check - on-demand),
 'LECB' (Phone bill billing), 'BILL' (billing), 'COMP' (free), or
-'PREPAY' (special billing type: applies a credit - see L<FS::prepay_credit> and sets billing type to I<BILL>)
+'PREPAY' (special billing type: applies a credit and sets billing type to I<BILL> - see L<FS::prepay_credit>)
 
 For Refunds (cust_refund):
 'CARD' (credit cards), 'CHEK' (electronic check/ACH),
 'LECB' (Phone bill billing), 'BILL' (billing), 'CASH' (cash),
-'WEST' (Western Union), 'MCRD' (Manual credit card), 'CBAK' Chargeback, or 'COMP' (free),
+'WEST' (Western Union), 'MCRD' (Manual credit card), 'CBAK' Chargeback, or 'COMP' (free)
 
 
 For Payments (cust_pay):
@@ -52,15 +51,16 @@ For Payments (cust_pay):
 'COMP' (free) is depricated as a payment type in cust_pay
 
 =cut 
-sub payby {
-  my($self,$payby) = @_;
-  if ( defined($payby) ) {
-    $self->setfield('payby', $payby);
-  } 
-  return $self->getfield('payby')
-}
 
+# was this supposed to do something?
+#sub payby {
+#  my($self,$payby) = @_;
+#  if ( defined($payby) ) {
+#    $self->setfield('payby', $payby);
+#  } 
+#  return $self->getfield('payby')
+#}
 
 =item payinfo
 
@@ -99,6 +99,7 @@ sub paycvv {
     }
   } else {
 #    warn "This doesn't work for other tables besides cust_main
+    '';
   } 
 }
 
@@ -107,46 +108,71 @@ sub paycvv {
 =cut
 
 sub paymask {
-  my($self,$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
+  if ( defined($paymask) && $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
+      # 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()
+=back
+
+=head1 METHODS
+
+=over 4
 
-This method converts the payment info (credit card, bank account, etc.) into a masked string.
+=item mask_payinfo [ PAYBY, PAYINFO ]
+
+This method converts the payment info (credit card, bank account, etc.) into a
+masked string.
+
+Optionally, an arbitrary payby and payinfo can be passed.
 
 =cut
 
 sub mask_payinfo {
   my $self = shift;
-  my $paymask;
-  my $payinfo = $self->payinfo;
-  my $payby = $self->payby;
+  my $payby   = scalar(@_) ? shift : $self->payby;
+  my $payinfo = scalar(@_) ? shift : $self->payinfo;
+
   # Check to see if it's encrypted...
-  if ($self->is_encrypted($payinfo)) {
+  my $paymask;
+  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)
+    if ($payby eq 'CARD' || $payby eq 'DCRD' || $payby eq 'MCRD') {
+      # Credit Cards
+      my $conf = new FS::Conf;
+      my $mask_method = $conf->config('card_masking_method') || 'first6last4';
+      $mask_method =~ /^first(\d+)last(\d+)$/
+        or die "can't parse card_masking_method $mask_method";
+      my($first, $last) = ($1, $2);
+
+      $paymask = substr($payinfo,0,$first).
+                 'x'x(length($payinfo)-$first-$last).
+                 substr($payinfo,(length($payinfo)-$last));
+    } 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;
+      $paymask = 'x'x(length($account)-2).
+                 substr($account,(length($account)-2))."@".$aba;
     } else { # Tie up loose ends
       $paymask = $payinfo;
     }
@@ -154,15 +180,10 @@ sub mask_payinfo {
   return $paymask;
 }
 
-=back
-
-
-=head1 METHODS
-
-=over 4
-
 =item payinfo_check
 
+Checks payby and payinfo.
+
 For Customers (cust_main):
 'CARD' (credit card - automatic), 'DCRD' (credit card - on-demand),
 'CHEK' (electronic check - automatic), 'DCHK' (electronic check - on-demand),
@@ -182,35 +203,13 @@ For Payments (cust_pay):
 
 =cut
 
-
-
-
-
 sub payinfo_check {
   my $self = shift;
 
-  # Make sure it's a valid payby
-  $self->payby =~ /^(CARD|DCRD|CHEK|DCHK|LECB|BILL|COMP|PREPAY|CASH|WEST|MCRD|PREP|CBAK)$/
-    or return "Illegal payby (overall payinfo_check)";
-  $self->payby($1);
-
-
-  # Okay some aren't valid depending on table
-  if ($self->table eq 'cust_main') {
-    if ($self->payby =~ /^(CASH|WEST|MCRD|PREP|CBAK)$/) {
-      return "Illegal payby (cust_main)";
-    }
-  } elsif ($self->table eq 'cust_refund') {
-    if ($self->payby =~ /^(DCRD|DCHK|PREPAY|PREP)$/) {
-      return "Illegal payby (cust_refund)";
-    }
-  } elsif ($self->table eq 'cust_pay') {
-    if ($self->payby =~ /^(DCRD|DCHK|PREPAY|CBAK)$/) {
-      return "Illegal payby (cust_pay)";
-    }
-  }
+  FS::payby->can_payby($self->table, $self->payby)
+    or return "Illegal payby: ". $self->payby;
 
-  if ( $self->payby eq 'CARD' ) {
+  if ( $self->payby eq 'CARD' && ! $self->is_encrypted($self->payinfo) ) {
     my $payinfo = $self->payinfo;
     $payinfo =~ s/\D//g;
     $self->payinfo($payinfo);
@@ -218,26 +217,72 @@ sub payinfo_check {
       $self->payinfo =~ /^(\d{13,16})$/
         or return "Illegal (mistyped?) credit card number (payinfo)";
       $self->payinfo($1);
-      Business::CreditCard::validate($self->payinfo) or return "Illegal credit card number";
-      return "Unknown card type" if Business::CreditCard::cardtype($self->payinfo) eq "Unknown";
+      validate($self->payinfo) or return "Illegal credit card number";
+      return "Unknown card type" if cardtype($self->payinfo) eq "Unknown";
     } else {
-      $self->payinfo('N/A');
+      $self->payinfo('N/A'); #???
     }
   } else {
-    my $error = $self->ut_textn('payinfo');
-    return $error if $error;
+    if ( $self->is_encrypted($self->payinfo) ) {
+      #something better?  all it would cause is a decryption error anyway?
+      my $error = $self->ut_anything('payinfo');
+      return $error if $error;
+    } else {
+      my $error = $self->ut_textn('payinfo');
+      return $error if $error;
+    }
   }
+
+  '';
+
 }
 
+=item payby_payinfo_pretty
+
+Returns payment method and information (suitably masked, if applicable) as
+a human-readable string, such as:
+
+  Card #54xxxxxxxxxxxx32
+
+or
+
+  Check #119006
+
+=cut
+
+sub payby_payinfo_pretty {
+  my $self = shift;
+  if ( $self->payby eq 'CARD' ) {
+    'Card #'. $self->paymask;
+  } elsif ( $self->payby eq 'CHEK' ) {
+    'E-check acct#'. $self->payinfo;
+  } elsif ( $self->payby eq 'BILL' ) {
+    'Check #'. $self->payinfo;
+  } elsif ( $self->payby eq 'PREP' ) {
+    'Prepaid card #'. $self->payinfo;
+  } elsif ( $self->payby eq 'CASH' ) {
+    'Cash '. $self->payinfo;
+  } elsif ( $self->payby eq 'WEST' ) {
+    'Western Union'; #. $self->payinfo;
+  } elsif ( $self->payby eq 'MCRD' ) {
+    'Manual credit card'; #. $self->payinfo;
+  } else {
+    $self->payby. ' '. $self->payinfo;
+  }
+}
 
+=back
 
 =head1 BUGS
 
-Have to add the future items...
+Future items?
+  Encryption - In the Future (Pull from Record.pm)
+  Bad Card Stuff - In the Future (Integrate Banned Pay)
+  Currency - In the Future
 
 =head1 SEE ALSO
 
-L<FS::Record>
+L<FS::payby>, L<FS::Record>
 
 =cut