From 050e311ccb5ef9747a87632842081b99453aba4b Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Thu, 14 Jul 2016 23:32:19 -0700 Subject: [PATCH] store credit card type in cust_payby and transaction records, #71291, schema support --- FS/FS/Schema.pm | 7 +++++-- FS/FS/Upgrade.pm | 3 +++ FS/FS/cust_pay.pm | 10 ++++++++++ FS/FS/cust_pay_void.pm | 4 ++++ FS/FS/cust_refund.pm | 7 +++++++ FS/FS/payinfo_Mixin.pm | 35 ++++++++++++++++++++++++++++++++++- 6 files changed, 63 insertions(+), 3 deletions(-) diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index 45ff03766..f3fca2ea9 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -1755,6 +1755,7 @@ sub tables_hashref { # index into payby table # eventually 'payinfo', 'varchar', 'NULL', 512, '', '', #see cust_main above + 'cardtype', 'varchar', 'NULL', $char_d, '', '', 'paymask', 'varchar', 'NULL', $char_d, '', '', 'paydate', 'varchar', 'NULL', 10, '', '', 'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes. @@ -1793,7 +1794,8 @@ sub tables_hashref { # index into payby table # eventually 'payinfo', 'varchar', 'NULL', 512, '', '', #see cust_main above - 'paymask', 'varchar', 'NULL', $char_d, '', '', + 'cardtype', 'varchar', 'NULL', $char_d, '', '', + 'paymask', 'varchar', 'NULL', $char_d, '', '', #'paydate' ? 'paybatch', 'varchar', 'NULL', $char_d, '', '', #for auditing purposes. 'closed', 'char', 'NULL', 1, '', '', @@ -2144,7 +2146,8 @@ sub tables_hashref { # be index into payby # table eventually 'payinfo', 'varchar', 'NULL', 512, '', '', #see cust_main above - 'paymask', 'varchar', 'NULL', $char_d, '', '', + 'cardtype', 'varchar', 'NULL', $char_d, '', '', + 'paymask', 'varchar', 'NULL', $char_d, '', '', 'paybatch', 'varchar', 'NULL', $char_d, '', '', 'closed', 'char', 'NULL', 1, '', '', 'source_paynum', 'int', 'NULL', '', '', '', # link to cust_payby, to prevent unapply of gateway-generated refunds diff --git a/FS/FS/Upgrade.pm b/FS/FS/Upgrade.pm index 377a0b17f..26cd42a10 100644 --- a/FS/FS/Upgrade.pm +++ b/FS/FS/Upgrade.pm @@ -391,6 +391,9 @@ sub upgrade_data { 'cust_refund' => [], 'banned_pay' => [], + #cardtype + 'cust_payby' => [], + #default namespace 'payment_gateway' => [], diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index 587454eb9..6676317a8 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -96,6 +96,10 @@ Payment Type (See L for valid values) Payment Information (See L for data format) +=item cardtype + +Credit card type, if appropriate; autodetected. + =item paymask Masked payinfo (See L for how this works) @@ -1242,6 +1246,12 @@ sub _upgrade_data { #class method process_upgrade_paybatch(); } } + + ### + # set cardtype + ### + $class->upgrade_set_cardtype; + } sub process_upgrade_paybatch { diff --git a/FS/FS/cust_pay_void.pm b/FS/FS/cust_pay_void.pm index 614a88fcc..0609ea825 100644 --- a/FS/FS/cust_pay_void.pm +++ b/FS/FS/cust_pay_void.pm @@ -76,6 +76,10 @@ Payment Type (See L for valid values) card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively +=item cardtype + +Credit card type, if appropriate. + =item paybatch text field for tracking card processing diff --git a/FS/FS/cust_refund.pm b/FS/FS/cust_refund.pm index 179151009..17bd13d10 100644 --- a/FS/FS/cust_refund.pm +++ b/FS/FS/cust_refund.pm @@ -83,6 +83,10 @@ Payment Type (See L for valid payby values) Payment Information (See L for data format) +=item cardtype + +Detected credit card type, if appropriate; autodetected. + =item paymask Masked payinfo (See L for how this works) @@ -516,6 +520,9 @@ sub _upgrade_data { # class method my ($class, %opts) = @_; $class->_upgrade_reasonnum(%opts); $class->_upgrade_otaker(%opts); + + local $ignore_empty_reasonnum = 1; + $class->upgrade_set_cardtype; } =back diff --git a/FS/FS/payinfo_Mixin.pm b/FS/FS/payinfo_Mixin.pm index 023aacdec..81e04a429 100644 --- a/FS/FS/payinfo_Mixin.pm +++ b/FS/FS/payinfo_Mixin.pm @@ -4,6 +4,9 @@ use strict; use Business::CreditCard; use FS::payby; use FS::Record qw(qsearch); +use FS::UID qw(driver_name); +use FS::Cursor; +use Time::Local qw(timelocal); use vars qw($ignore_masked_payinfo); @@ -196,6 +199,8 @@ sub payinfo_check { if ( $self->payby eq 'CARD' && ! $self->is_encrypted($self->payinfo) ) { my $payinfo = $self->payinfo; + my $cardtype = cardtype($payinfo); + $self->set('cardtype', $cardtype); if ( $ignore_masked_payinfo and $self->mask_payinfo eq $self->payinfo ) { # allow it } else { @@ -207,12 +212,18 @@ sub payinfo_check { $self->payinfo($1); validate($self->payinfo) or return "Illegal credit card number"; return "Unknown card type" if $self->payinfo !~ /^99\d{14}$/ #token - && cardtype($self->payinfo) eq "Unknown"; + && $cardtype eq "Unknown"; } else { $self->payinfo('N/A'); #??? } } } else { + if ( $self->payby eq 'CARD' and $self->paymask ) { + # if we can't decrypt the card, at least detect the cardtype + $self->set('cardtype', cardtype($self->paymask)); + } else { + $self->set('cardtype', ''); + } if ( $self->is_encrypted($self->payinfo) ) { #something better? all it would cause is a decryption error anyway? my $error = $self->ut_anything('payinfo'); @@ -307,6 +318,28 @@ sub payinfo_used { return 0; } +=item upgrade_set_cardtype + +Find all records with a credit card payment type and no cardtype, and +replace them in order to set their cardtype. + +=cut + +sub upgrade_set_cardtype { + my $class = shift; + # assign cardtypes to CARD/DCRDs that need them; check_payinfo_cardtype + # will do this. ignore any problems with the cards. + local $ignore_masked_payinfo = 1; + my $search = FS::Cursor->new({ + table => $class->table, + extra_sql => q[ WHERE payby IN('CARD','DCRD') AND cardtype IS NULL ], + }); + while (my $record = $search->fetch) { + my $error = $record->replace; + die $error if $error; + } +} + =back =head1 BUGS -- 2.11.0