Revent
Revent

Reputation: 2109

In Braintree is it possible to verify duplicate payment method for just one customer instead of entire vault?

For the Braintree_PaymentMethod::create() function, one of the options is:

'failOnDuplicatePaymentMethod', bool

If this option is passed and the payment method has already been added to the Vault, the request will fail. This option will not work with PayPal payment methods.

This appears to be a global compare. i.e. if the credit card information exists in the vault regardless of customer id this will fail.

Is there a way to check for duplicates on a particular customer?

Upvotes: 9

Views: 5227

Answers (5)

nav3916872
nav3916872

Reputation: 998

Available for cards now as stated here . Not applicable for Paypal , Gpay and other payment methods. But this requires us to send the braintree customerID along.

Upvotes: 0

Simon_Weaver
Simon_Weaver

Reputation: 145950

Here is a .NET version. Not 100% complete, but a good starter for someone with the same situation. If you find any issues or suggestions please just edit this answer.

        try
        {
            // final token value (unique across merchant account)
            string token;

            // PaymentCreate request
            var request = new PaymentMethodRequest
            {
                CustomerId = braintreeID,
                PaymentMethodNonce = nonce,
                Options = new PaymentMethodOptionsRequest()
            };

            // try to create the payment without allowing duplicates
            request.Options.FailOnDuplicatePaymentMethod = true;
            var result = await gateway.PaymentMethod.CreateAsync(request);

            // handle duplicate credit card (assume CC type in this block)
            if (result.Errors.DeepAll().Any(x => x.Code == ValidationErrorCode.CREDIT_CARD_DUPLICATE_CARD_EXISTS))
            {
                // duplicate card - so try again (could be in another vault - ffs)

                // get all customer's existing payment methods (BEFORE adding new one)
                // don't waste time doing this unless we know we have a dupe
                var vault = await gateway.Customer.FindAsync(braintreeID);


                // fortunately we can use the same nonce if it fails
                request.Options.FailOnDuplicatePaymentMethod = false;

                result = await gateway.PaymentMethod.CreateAsync(request);
                var newCard = (result.Target as CreditCard);

                // consider a card a duplicate if the expiration date is the same + unique identifier is the same
                // add on billing address fields here too if needed
                var existing = vault.CreditCards.Where(x => x.UniqueNumberIdentifier == newCard.UniqueNumberIdentifier).ToArray();
                var existingWithSameExpiration = existing.Where(x => x.ExpirationDate == newCard.ExpirationDate);

                if (existingWithSameExpiration.Count() > 1)
                {
                    throw new Exception("Something went wrong! Need to decide how to handle this!");
                }
                else
                {
                    // delete the NEW card 
                    await gateway.PaymentMethod.DeleteAsync(newCard.Token);

                    // use token from existing card
                    token = existingWithSameExpiration.Single().Token;
                }
            }
            else
            {
                // use token (could be any payment method)
                token = result.Target.Token;
            }

            // added successfully, and we know it's unique
            return token;
        }
        catch (BraintreeException ex)
        {
            throw;  
        }
        catch (Exception ex)
        {
            throw;
        }

Upvotes: 1

Mahak Choudhary
Mahak Choudhary

Reputation: 1384

@Raymond Berg, I made soem changes in your code, Here is the updated code:
1. Used foreach instead of in_array
2. Also delete the added card If found duplicate

$customer = Braintree_Customer::find('your_customer');
$unique_ids = array_map(extractUniqueId,$customer->creditCards);

$result = Braintree_PaymentMethod::create(array(
    'customerId' => 'your_customer',
    'paymentMethodNonce' => 'fake-valid-discover-nonce',
));

if ($result->success) {
    $cardAlreadyExist = false;
$currentPaymentMethod = $this->extractUniqueId($result->paymentMethod);
//The in_array function was not working so I used foreach to check if     card identifier exist or not
    foreach ($unique_ids as $key => $uid) {
        if( $currentPaymentMethod  == $uid->uniqueNumberIdentifier)
        {
            $cardAlreadyExist = true;
//Here you have to delete the currently added card
            $payment_token = $result->paymentMethod->token;
            Braintree_PaymentMethod::delete($payment_token);
        }
}


    if($cardAlreadyExist) {
        echo "Do your duplicate logic";
    } else {
        echo "Continue with your unique logic";
    }

}

Upvotes: 1

Raymond Berg
Raymond Berg

Reputation: 870

Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.

You and Evan are correct: this is the only pre-built way of failing on duplicate creates regardless of customer create. You could achieve what you are trying to do with your own automation, however.

To do this, simply collect the credit card unique ids that already exist from the customer object. Then when you create the new payment method, compare it with the existing cards:

function extractUniqueId($creditCard){ 
    return $creditCard->uniqueNumberIdentifier;
}

$customer = Braintree_Customer::find('your_customer');
$unique_ids = array_map(extractUniqueId,$customer->creditCards);

$result = Braintree_PaymentMethod::create(array(
    'customerId' => 'your_customer',
    'paymentMethodNonce' => 'fake-valid-discover-nonce',
));

if ($result->success) {
    if(in_array(extractUniqueId($result->paymentMethod), $unique_ids)) {
        echo "Do your duplicate logic";
    } else {
        echo "Continue with your unique logic";
    }
} 

Depending on what you want to do, you could delete the new payment method or whatever else you need.

Upvotes: 14

Evan
Evan

Reputation: 457

Checked with Braintree support--still not available out of the box:

If you use failOnDuplicatePaymentMethod any request to add duplicate payment method information into the Vault will fail.

We currently don’t have the functionality to prevent a customer from adding a duplicate card to their profile, while allowing duplicate cards to still be added under multiple profiles. If this is something you are interested in you will have to build out your own logic.

Upvotes: 1

Related Questions