diff --git a/lib/Experian/IDAuth.pm b/lib/Experian/IDAuth.pm index 3a51812..42426e1 100644 --- a/lib/Experian/IDAuth.pm +++ b/lib/Experian/IDAuth.pm @@ -2,7 +2,7 @@ package Experian::IDAuth; use strict; use warnings; -our $VERSION = '1.8'; +our $VERSION = '2.0.0'; use Locale::Country; use Path::Tiny; @@ -358,7 +358,7 @@ sub _get_result_proveid { return unless $credit_reference and $kyc_summary; - my $decision = {}; + my $decision = { matches => []}; # check if client has died or fraud my $cr_deceased = $credit_reference->findvalue('DeceasedMatch') || 0; @@ -376,13 +376,11 @@ sub _get_result_proveid { or $cr_deceased == 1 ) { $decision->{deceased} = 1; - return $decision; } $report_summary{Fraud} ||= 0; if ( $report_summary{Fraud} == 1 ) { $decision->{fraud} = 1; - return $decision; } # check if client is age verified @@ -392,12 +390,14 @@ sub _get_result_proveid { if ( $kyc_dob or $cr_total ) { $decision->{age_verified} = 1; } - else { - return $decision; - } # check if client is in any suspicious list - # we don't care about: NoOfCCJ, COAMatch + # we don't care about: COAMatch + # + # Add NoOfCCJ separately since we don't fail that one. + + $decision->{CCJ} = 1 if $credit_reference->findvalue('NoOfCCJ'); + my @matches = map { $_->[0] } grep { $_->[1] > 0 } @@ -405,20 +405,19 @@ sub _get_result_proveid { qw(BOEMatch PEPMatch OFACMatch CIFASMatch); if (@matches) { - if ( grep { /^(BOEMatch|PEPMatch|OFACMatch|CIFASMatch)$/ } @matches ) { + my @hard_fails = grep { my $f = $_; + grep { "${f}Match" eq $_ } @matches } + qw(BOE PEP OFAC CIFAS); + $decision->{$_} = 1 for @hard_fails; + $decision->{deny} = 1 if @hard_fails; - # BOEMatch PEPMatch OFAC and CIFAS are hard failures and need manual verification - delete $decision->{age_verified}; - $decision->{deny} = 1; - } $decision->{matches} = \@matches; - return $decision; } # if client is in Directors list, we should not fully authenticate him if ( $report_summary{Directors} ) { - $decision->{matches} = ['Directors']; - return $decision; + $decision->{director} = 1; + $decision->{matches} = [ @{$decision->{matches}}, 'Directors' ]; } # check if client can be fully authenticated @@ -587,7 +586,7 @@ Experian::IDAuth - Experian's ID Authenticate service =head1 VERSION -Version 1.8 +Version 2.0.0 =head1 DESCRIPTION @@ -641,15 +640,20 @@ Then use this module. die; } - if ($prove_id_result->{fully_authenticated}) { - # client successfully authenticated - } if ($prove_id_result->{age_verified}) { # client's age is verified } if ($prove_id_result->{deceased} || $prove_id_result->{fraud}) { # client flagged as deceased or fraud } + if ($prove_id_result->{deny}) { + # client on any of PEP, OFAC, or BOE list + # you can check $prove_id_result->{PEP} etc if you want more detail + } + if ($prove_id_result->{fully_authenticated}) { + # client successfully authenticated, + # DOES NOT MEAN NO CONCERNS + } # CheckID is a more simpler version and can be used if ProveID_KYC fails my $check_id = My::Experian->new( @@ -665,6 +669,26 @@ Then use this module. # client successfully authenticated } +=head1 CHANGES FROM 1.X + +The 2.x series of this module provides some significant changes from 1.x. + +With 1.x, fully_authenticated could only suggest that there were no concerns +and that the client was fully authenticated. Now, we set this in addition to +any failure fields. For this reason it is important to handle failures +first and then check this response attribute. Note that the response attribute +also now shows the full list (not the first) set of possible concerns. + +Therefore: + +=over + +=item One cannot assume that fully_authenticated means "success" and + +=item Reasons for failure are no longer exclusive. + +=back + =head1 AUTHOR binary.com, C diff --git a/t/decision.t b/t/decision.t index d66cf4a..0906a5c 100644 --- a/t/decision.t +++ b/t/decision.t @@ -1485,34 +1485,44 @@ my $fraud =< EOD -eq_or_diff( - examine($fully1), - { - age_verified => 1, - fully_authenticated => 1, - }, - "Fully1 fully authenticated" -); -eq_or_diff( - examine($fully2), - { - age_verified => 1, - fully_authenticated => 1, - }, - "Fully2 fully authenticated" -); -eq_or_diff(examine($not_authenticated), {}, "Not authenticated as expected"); -eq_or_diff( - examine($not_deceased), - { - age_verified => 1, - fully_authenticated => 1, - }, - "Deceased with low certainty level was fully authenticated" -); -eq_or_diff(examine($deceased), {deceased => 1}, "Found deceased in report summary"); -eq_or_diff(examine($cr_deceased), {deceased => 1}, "Found deceased in credit reference"); -eq_or_diff(examine($fraud), {fraud => 1}, "Found fraud in report summary"); +my $result = examine($fully1); +is($result->{age_verified}, 1, "Fully 1, age verified"); +is($result->{fully_authenticated}, 1, 'Fully 1, Fully authenticated'); +ok(not(exists $result->{deny}), 'Fully 1, not denied'); + +$result = examine($fully2); +is($result->{age_verified}, 1, "Fully 2, age verified"); +is($result->{fully_authenticated}, 1, 'Fully 2, Fully authenticated'); +ok(not(exists $result->{deny}), 'Fully 2, not denied'); + +$result = examine($not_authenticated); +ok(not(exists $result->{deny}), 'not authenticated, not denied'); +ok(not(exists $result->{age_verified}), 'not authenticated, not age verified'); +ok(not(exists $result->{fully_authenticated}), 'not authenticated'); + +$result = examine($not_deceased), +is($result->{age_verified}, 1, "Not deceased, age verified"); +is($result->{fully_authenticated}, 1, 'Not deceased, Fully authenticated'); +ok(not(exists $result->{deceased}), 'Not deceased, not deceased'); +ok(not(exists $result->{deny}), 'Not deceased, not denied'); + +$result = examine($deceased); +is($result->{age_verified}, 1, "deceased, age verified"); +is($result->{fully_authenticated}, 1, 'deceased, Fully authenticated'); +is($result->{deceased}, 1, 'deceased, deceased'); +ok(not(exists $result->{deny}), 'deceased, not denied'); + +$result = examine($cr_deceased); +is($result->{age_verified}, 1, "cr deceased, age verified"); +is($result->{fully_authenticated}, 1, 'cr deceased, Fully authenticated'); +is($result->{deceased}, 1, 'cr deceased, deceased'); +ok(not(exists $result->{deny}), 'cr deceased, not denied'); + +$result = examine($fraud); +is($result->{age_verified}, 1, "fraud, age verified"); +is($result->{fully_authenticated}, 1, 'fraud, Fully authenticated'); +is($result->{fraud}, 1, 'fraud, fraud'); +ok(not(exists $result->{deny}), 'fraud, not denied'); # this one has 2 in KYCSummary, so should be fully authenticated my $age_only_1 =< EOD -eq_or_diff( - examine($age_only_1), - { - age_verified => 1, - fully_authenticated => 1, - }, - "Two in KYC Summary so fully authenticated" -); +$result = examine($age_only_1), +is($result->{age_verified}, 1, "Age only 1, age verified"); +is($result->{fully_authenticated}, 1, 'Age only 1, Fully authenticated'); +ok(not(exists $result->{deceased}), 'Age only 1, not deceased'); +ok(not(exists $result->{deny}), 'Age only 1, not denied'); -eq_or_diff( - examine($age_only_2), - { - deny => 1, - matches => ['PEPMatch'], - }, - " if PEP is set, then fail verification" -); +$result = examine($age_only_2), +is($result->{age_verified}, 1, "Age only 2, age verified"); +is($result->{fully_authenticated}, 1, 'Age only 2, Fully authenticated'); +ok(not(exists $result->{deceased}), 'Age only 2, not deceased'); +is($result->{deny}, 1, 'Age only 2, denied'); +is($result->{PEP}, 1, 'Age only 2, PEP flagged'); -eq_or_diff( - examine($age_only_3), - { - deny => 1, - matches => ['BOEMatch'], - }, - " if BOEMatch is set, then fail verification" -); +$result = examine($age_only_3), +is($result->{age_verified}, 1, "Age only 3, age verified"); +is($result->{fully_authenticated}, 1, 'Age only 3, Fully authenticated'); +ok(not(exists $result->{deceased}), 'Age only 3, not deceased'); +is($result->{deny}, 1, 'Age only 3, denied'); +is($result->{BOE}, 1, 'Age only 3, BOE flagged'); -eq_or_diff( - examine($age_only_4), - { - deny => 1, - matches => ['OFACMatch'], - }, - " if OFACMatch is set, then fail verification" -); +$result = examine($age_only_4), +is($result->{age_verified}, 1, "Age only 4, age verified"); +is($result->{fully_authenticated}, 1, 'Age only 4, Fully authenticated'); +ok(not(exists $result->{deceased}), 'Age only 4, not deceased'); +is($result->{deny}, 1, 'Age only 4, denied'); +is($result->{OFAC}, 1, 'Age only 4, OFAC flagged'); -eq_or_diff( - examine($age_only_5), - { - age_verified => 1, - fully_authenticated => 1, - }, - " ignore COAMatch if set, fully authenticate if possible" -); +#Change of address handling +$result = examine($age_only_5), +is($result->{age_verified}, 1, "Age only 5, age verified"); +is($result->{fully_authenticated}, 1, 'Age only 5, Fully authenticated'); +ok(not(exists $result->{deceased}), 'Age only 5, not deceased'); +ok(not(exists $result->{deny}), 'Age only 5, not denied'); -eq_or_diff( - examine($age_only_6), - { - deny => 1, - matches => ['CIFASMatch'], - }, - " if CIFASMatch is set, then fail verification" -); +$result = examine($age_only_6), +is($result->{age_verified}, 1, "Age only 6, age verified"); +is($result->{fully_authenticated}, 1, 'Age only 6, Fully authenticated'); +ok(not(exists $result->{deceased}), 'Age only 6, not deceased'); +is($result->{deny}, 1, 'Age only 6, denied'); +is($result->{CIFAS}, 1, 'Age only 6, CIFAS flagged'); -eq_or_diff( - examine($age_only_7), - { - age_verified => 1, - fully_authenticated => 1, - }, - " ignore CCJs if set, fully authenticate if possible" -); +$result = examine($age_only_7), +is($result->{age_verified}, 1, "Age only 7, age verified"); +is($result->{fully_authenticated}, 1, 'Age only 7, Fully authenticated'); +is($result->{CCJ}, 1, 'Age only 7, Has court judgements'); +ok(not(exists $result->{deceased}), 'Age only 7, not deceased'); +ok(not(exists $result->{deny}), 'Age only 7, not denied'); -eq_or_diff( - examine($age_only_8), - { - age_verified => 1, - matches => ['Directors'], - }, - " if Director, then age_verified only" -); +$result = examine($age_only_8), +is($result->{age_verified}, 1, "Age only 8, age verified"); +is($result->{fully_authenticated}, 1, 'Age only 8, Fully authenticated'); +is($result->{director}, 1, 'Age only 8, Is Director'); +ok(not(exists $result->{deceased}), 'Age only 8, not deceased'); +ok(not(exists $result->{deny}), 'Age only 8, not denied'); -eq_or_diff(examine($age_only_9), {age_verified => 1,}, "If KYC Summary is 1, then age_verified"); +$result = examine($age_only_9), +is($result->{age_verified}, 1, "Age only 9, age verified"); +ok(not(exists $result->{fully_authenticated}), 'Age only 9, not authenticated'); +ok(not(exists $result->{deceased}), 'Age only 9, not deceased'); +ok(not(exists $result->{deny}), 'Age only 9, not denied'); -eq_or_diff( - examine($age_only_10), - { - age_verified => 1, - fully_authenticated => 1, - }, - "If Total number of verifications in Credit reference is 2, then fully_authenticated" -); +$result = examine($age_only_10), +is($result->{age_verified}, 1, "Age only 10, age verified"); +is($result->{fully_authenticated}, 1, 'Age only 10, Fully authenticated'); +ok(not(exists $result->{deceased}), 'Age only 10, not deceased'); +ok(not(exists $result->{deny}), 'Age only 10, not denied'); Test::NoWarnings::had_no_warnings(); done_testing; diff --git a/t/xml_report.t b/t/xml_report.t index 1c9c5aa..ed905e6 100644 --- a/t/xml_report.t +++ b/t/xml_report.t @@ -10,8 +10,10 @@ use Data::Dumper; use lib 'lib'; use_ok( 'Experian::IDAuth' ); -# clean up -system "rm -rf /tmp/proveid/"; +my $tmp = $ENV{TEMP} || '/tmp'; # portability between windows and linux + +unlink $_ for <"$tmp/proveid/*">; +rmdir "$tmp/proveid/*"; my $module = Test::MockModule->new('SOAP::Lite'); my $xml;