braintree / braintree_php

Braintree PHP library
https://developer.paypal.com/braintree/docs/start/overview
MIT License
547 stars 224 forks source link

Sandbox Payment method nonce fails on subscription()->create() #317

Closed ChrisHSandN closed 2 years ago

ChrisHSandN commented 2 years ago

General information

Issue description

The test payment method nonces detailed here https://developer.paypal.com/braintree/docs/reference/general/testing/php#payment-method-nonces do not work within a call to subscription()->create()

Passing it directly results in "Payment method nonce is invalid"

$result = $gateway->subscription()->create([
    'planId' => 'freq_12m',
    'paymentMethodNonce' => 'fake-valid-nonce',
]);

var_dump($result->message); //Payment method nonce is invalid.

It does lookup correctly when passed to paymentMethodNonce()->find()

$result = $gateway->paymentMethodNonce()->find(
    'fake-valid-nonce',
);
var_dump($result->nonce); // 'fake-valid-nonce'

The only partial workaround I have found is the roundabout method of using it to create a PaymentMethod, then using this to create a PaymentMethodNonce. However this only works for the valid nonce, invalid ones will fail at the paymentMethod->create() stage.

$paymentMethod = $gateway->paymentMethod()->create([
    'customerId' => 'framework_1',
    'paymentMethodNonce' => 'fake-valid-nonce',
]);

$paymentMethodNonce = $gateway->paymentMethodNonce()->create(
    $paymentMethod->paymentMethod->token,
);

$result = $gateway->subscription()->create([
    'planId' => 'freq_12m',
    'paymentMethodNonce' => $paymentMethodNonce->paymentMethodNonce->nonce,
]);

var_dump($result->success); //true

I am aware I could use a payment token however, I am in a SCA compliant country and need to use (and test) with "3DS enriched nonce" in all calls to Transaction::sale() and Subscription::create().

crookedneighbor commented 2 years ago

The problem is that the nonce used in Subscription::create() must refer to a vaulted nonce. fake-valid-nonce represents a visa card that is single use, not stored in your vault.

So the only nonces that will work with this subscription are ones created with PaymentMethodNonce::create() (which you would then pass to the 3ds lookup) or previously saved payment methods loaded from Drop-in.

ChrisHSandN commented 2 years ago

Thanks @crookedneighbor - it doesn't mater what Braintree SDK I post about, you are always there with a very useful answer! It is really appreciated 👍

For anyone finding this and looking for a solution:

  1. Now I know they need to be vaulted, I tried vaulting the invalid nonces using paymentMethod()->create() with verifyCard : false. Sadly, no luck. I'm sure there is a technical reason, but the subscription will always get created successfully, with a transaction submitted_for_settlement.
  2. The 1 way I have found to simulate a failed subscription is to use the paymentMethid()->create('fake-valid-nonce') + paymentMethodNonce()->create() and then pass one of the invalid transaction amounts as the create('amount' => '2000.00').
  3. Mentioning https://github.com/braintree/braintree_php/issues/288 to link these cards together.