add Isracard validation, RT13643
[Business-CreditCard.git] / CreditCard.pm
index 959430a..df40315 100644 (file)
@@ -5,7 +5,7 @@ use vars qw( @ISA $VERSION $Country );
 
 @ISA = qw( Exporter );
 
 
 @ISA = qw( Exporter );
 
-$VERSION = "0.31";
+$VERSION = "0.32_01";
 
 $Country = 'US';
 
 
 $Country = 'US';
 
@@ -42,7 +42,6 @@ Possible return values are:
   MasterCard
   Discover card
   American Express card
   MasterCard
   Discover card
   American Express card
-  Diner's Club/Carte Blanche
   enRoute
   JCB
   BankCard
   enRoute
   JCB
   BankCard
@@ -50,10 +49,14 @@ Possible return values are:
   Solo
   China Union Pay
   Laser
   Solo
   China Union Pay
   Laser
+  Isracard
   Unknown
 
 "Not a credit card" is returned on obviously invalid data values.
 
   Unknown
 
 "Not a credit card" is returned on obviously invalid data values.
 
+Versions before 0.31 may also have returned "Diner's Club/Carte Blanche" (these
+cards are now recognized as "Discover card").
+
 As of 0.30, cardtype() will accept a partial card masked with "x", "X', ".",
 "*" or "_".  Only the first 2-6 digits and the length are significant;
 whitespace and dashes are removed.  To recognize just Visa, MasterCard and
 As of 0.30, cardtype() will accept a partial card masked with "x", "X', ".",
 "*" or "_".  Only the first 2-6 digits and the length are significant;
 whitespace and dashes are removed.  To recognize just Visa, MasterCard and
@@ -74,7 +77,7 @@ charges, you need a Merchant account.  See L<Business::OnlinePayment>.
 These subroutines will also work if you provide the arguments
 as numbers instead of strings, e.g. C<validate(5276440065421319)>.  
 
 These subroutines will also work if you provide the arguments
 as numbers instead of strings, e.g. C<validate(5276440065421319)>.  
 
-=head1 CHANGES IN 0.30
+=head1 PROCESSING AGREEMENTS
 
 Credit card issuers have recently been forming agreements to process cards on
 other networks, in which one type of card is processed as another card type.
 
 Credit card issuers have recently been forming agreements to process cards on
 other networks, in which one type of card is processed as another card type.
@@ -94,7 +97,9 @@ Here are the currently known agreements:
 
 =over 4
 
 
 =over 4
 
-=item Diner's club cards (starting with 36) are now identified as "MasterCard" inside the US and Canada.
+=item Most Diner's club is now identified as Discover.  (This supercedes the earlier identification of some Diner's club cards as MasterCard inside the US and Canada.)
+
+=item JCB cards in the 3528-3589 range are identified as Discover inside the US and Canada.
 
 =item China Union Pay cards are identified as Discover cards outside China.
 
 
 =item China Union Pay cards are identified as Discover cards outside China.
 
@@ -119,13 +124,14 @@ Please don't bother Jon with emails about this module.
 
 Lee Lawrence <LeeL@aspin.co.uk>, Neale Banks <neale@lowendale.com.au> and
 Max Becker <Max.Becker@firstgate.com> contributed support for additional card
 
 Lee Lawrence <LeeL@aspin.co.uk>, Neale Banks <neale@lowendale.com.au> and
 Max Becker <Max.Becker@firstgate.com> contributed support for additional card
-types.  Lee also contributed a working test.pl.
+types.  Lee also contributed a working test.pl.  Alexandr Ciornii
+<alexchorny@gmail.com> contributed code cleanups.
 
 =head1 COPYRIGHT AND LICENSE
 
 Copyright (C) 1995,1996,1997 Jon Orwant
 Copyright (C) 2001-2006 Ivan Kohler
 
 =head1 COPYRIGHT AND LICENSE
 
 Copyright (C) 1995,1996,1997 Jon Orwant
 Copyright (C) 2001-2006 Ivan Kohler
-Copyright (C) 2007 Freeside Internet Services, Inc.
+Copyright (C) 2007-2011 Freeside Internet Services, Inc.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself, either Perl version 5.8.8 or,
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself, either Perl version 5.8.8 or,
@@ -153,8 +159,14 @@ sub cardtype {
     return "Not a credit card" if $number =~ /[^\dx]/io;
 
     #$number =~ s/\D//g;
     return "Not a credit card" if $number =~ /[^\dx]/io;
 
     #$number =~ s/\D//g;
-
-    return "Not a credit card" unless length($number) >= 13 && 0+$number;
+    {
+      local $^W=0; #no warning at next line
+      return "Not a credit card"
+        unless ( length($number) >= 13
+                 || length($number) == 8 || length($number) == 9 #Isracard
+               )
+            && 0+$number;
+    }
 
     return "Switch"
       if $number =~ /^49(03(0[2-9]|3[5-9])|11(0[1-2]|7[4-9]|8[1-2])|36[0-9]{2})[\dx]{10}([\dx]{2,3})?$/o
 
     return "Switch"
       if $number =~ /^49(03(0[2-9]|3[5-9])|11(0[1-2]|7[4-9]|8[1-2])|36[0-9]{2})[\dx]{10}([\dx]{2,3})?$/o
@@ -165,18 +177,24 @@ sub cardtype {
 
     return "MasterCard"
       if   $number =~ /^5[1-5][\dx]{14}$/o
 
     return "MasterCard"
       if   $number =~ /^5[1-5][\dx]{14}$/o
-      || ( $number =~ /^36[\dx]{12}/ && $Country =~ /^(US|CA)$/oi );
+      ;# || ( $number =~ /^36[\dx]{12}/ && $Country =~ /^(US|CA)$/oi );
 
     return "Discover card"
 
     return "Discover card"
-      if   $number =~ /^6011[\dx]{12}$/o
+      if   $number =~ /^30[0-5][\dx]{11}([\dx]{2})?$/o  #diner's: 300-305
+      ||   $number =~ /^3095[\dx]{10}([\dx]{2})?$/o     #diner's: 3095
+      ||   $number =~ /^3[68][\dx]{12}([\dx]{2})?$/o    #diner's: 36
+      ||   $number =~ /^6011[\dx]{12}$/o
+      ||   $number =~ /^64[4-9][\dx]{13}$/o
       ||   $number =~ /^65[\dx]{14}$/o
       ||   $number =~ /^65[\dx]{14}$/o
-      || ( $number =~ /^622[\dx]{13}$/o && $Country !~ /^(CN)$/oi );
+      || ( $number =~ /^62[24-68][\dx]{13}$/o && uc($Country) ne 'CN' ) #CUP
+      || ( $number =~ /^35(2[89]|[3-8][\dx])[\dx]{10}$/o && uc($Country) eq 'US' );
 
     return "American Express card" if $number =~ /^3[47][\dx]{13}$/o;
 
 
     return "American Express card" if $number =~ /^3[47][\dx]{13}$/o;
 
-    return "Diner's Club/Carte Blanche"
-      if $number =~ /^3(0[0-5]|[68][\dx])[\dx]{11}$/o;
+    #return "Diner's Club/Carte Blanche"
+    #  if $number =~ /^3(0[0-59]|[68][\dx])[\dx]{11}$/o;
 
 
+    #"Diners Club enRoute"
     return "enRoute" if $number =~ /^2(014|149)[\dx]{11}$/o;
 
     return "JCB" if $number =~ /^(3[\dx]{4}|2131|1800)[\dx]{11}$/o;
     return "enRoute" if $number =~ /^2(014|149)[\dx]{11}$/o;
 
     return "JCB" if $number =~ /^(3[\dx]{4}|2131|1800)[\dx]{11}$/o;
@@ -187,16 +205,22 @@ sub cardtype {
       if $number =~ /^6(3(34[5-9][0-9])|767[0-9]{2})[\dx]{10}([\dx]{2,3})?$/o;
 
     return "China Union Pay"
       if $number =~ /^6(3(34[5-9][0-9])|767[0-9]{2})[\dx]{10}([\dx]{2,3})?$/o;
 
     return "China Union Pay"
-      if $number =~ /^622[\dx]{13}$/o;
+      if $number =~ /^62[24-68][\dx]{13}$/o;
 
     return "Laser"
       if $number =~ /^6(304|7(06|09|71))[\dx]{12,15}$/o;
 
 
     return "Laser"
       if $number =~ /^6(304|7(06|09|71))[\dx]{12,15}$/o;
 
+    return "Isracard"
+      if $number =~ /^[\dx]{8,9}$/;
+
     return "Unknown";
 }
 
 sub generate_last_digit {
     my ($number) = @_;
     return "Unknown";
 }
 
 sub generate_last_digit {
     my ($number) = @_;
+
+    die "invalid operation" if length($number) == 8 || length($number) == 9;
+
     my ($i, $sum, $weight);
 
     $number =~ s/\D//g;
     my ($i, $sum, $weight);
 
     $number =~ s/\D//g;
@@ -211,12 +235,22 @@ sub generate_last_digit {
 
 sub validate {
     my ($number) = @_;
 
 sub validate {
     my ($number) = @_;
+
     my ($i, $sum, $weight);
     
     return 0 if $number =~ /[^\d\s]/;
 
     $number =~ s/\D//g;
 
     my ($i, $sum, $weight);
     
     return 0 if $number =~ /[^\d\s]/;
 
     $number =~ s/\D//g;
 
+    if ( $number =~ /^[\dx]{8,9}$/ ) { # Isracard
+        $number = "0$number" if length($number) == 8;
+        for($i=1;$i<length($number);$i++){
+            $sum += substr($number,9-$i,1) * $i;
+        }
+        return 1 if $sum%11 == 0;
+        return 0;
+    }
+
     return 0 unless length($number) >= 13 && 0+$number;
 
     for ($i = 0; $i < length($number) - 1; $i++) {
     return 0 unless length($number) >= 13 && 0+$number;
 
     for ($i = 0; $i < length($number) - 1; $i++) {