简体   繁体   English

Laravel:将Braintree与收银员整合在一起

[英]Laravel: Integrate Braintree with Cashier

Just curious, 只是好奇,

Does someone has successfully integrated Braintree using laravel/cashier-braintree ? 有人使用laravel/cashier-braintree成功整合了Braintree吗?

I'm stuck at the beginning with: 我一开始就陷入困境:
$user->newSubscription('main', 'monthly')->create($creditCardToken);

Following the documentation, I guess to need something like that: $data = [ 'firstName' => $request->first_name, 'lastName' => $request->last_name, ]; $creditCardToken = Auth::id(); $planId = [Plan Id defined in Braintree] $user->newSubscription('main', $planId)->create($creditCardToken, $data); 在文档之后,我想需要类似的东西: $data = [ 'firstName' => $request->first_name, 'lastName' => $request->last_name, ]; $creditCardToken = Auth::id(); $planId = [Plan Id defined in Braintree] $user->newSubscription('main', $planId)->create($creditCardToken, $data); $data = [ 'firstName' => $request->first_name, 'lastName' => $request->last_name, ]; $creditCardToken = Auth::id(); $planId = [Plan Id defined in Braintree] $user->newSubscription('main', $planId)->create($creditCardToken, $data);

In the offical documentation I dont have to specify any credit card info, it's deprecated. 官方文档中,我不必指定任何信用卡信息,它已被弃用。

"Unable to create Braintree customer: Unknown payment_method_nonce.\\n Expiration date is required.\\n Credit card number is required.\\n Credit card must include number, payment_method_nonce, or venmo_sdk_payment_method_code."

Whoops! 哎呦! So let's add this anyway: $data = [ 'firstName' => $request->first_name, 'lastName' => $request->last_name, 'creditCard' => [ 'number' => $request->number, 'expirationMonth' => $request->month, 'expirationYear' => $request->year, 'cvv' => $request->cvv, 'billingAddress' => [ 'firstName' => 'Jen', 'lastName' => 'Smith', 'company' => 'Braintree', 'streetAddress' => '123 Address', 'locality' => 'City', 'region' => 'State', 'postalCode' => '12345', ], ], ]; 所以让我们添加这个: $data = [ 'firstName' => $request->first_name, 'lastName' => $request->last_name, 'creditCard' => [ 'number' => $request->number, 'expirationMonth' => $request->month, 'expirationYear' => $request->year, 'cvv' => $request->cvv, 'billingAddress' => [ 'firstName' => 'Jen', 'lastName' => 'Smith', 'company' => 'Braintree', 'streetAddress' => '123 Address', 'locality' => 'City', 'region' => 'State', 'postalCode' => '12345', ], ], ];

And now, all I get is : 而现在,我得到的只是:
"Unable to create Braintree customer: Unknown payment_method_nonce."

There is some usefull informations in the official Braintree_Customer::create() . 官方Braintree_Customer :: create()中有一些有用的信息。 And, in fact, you can easily implement Braintree without cachier like in braintree_php_guide . 而且,事实上,你可以很容易地实现布伦特里没有方言cachierbraintree_php_guide

So what ? 所以呢 ? Do I have to drop Cachier ? 我是否必须放弃Cachier

Cashier with braintree is already working (for me at least). 有braintree的收银员已经在工作(至少对我而言)。 The start was a little confusing for me as well. 开始对我来说有点混乱。

The idea behind that is, that the user sends his critical credit card data directly to braintree and not to you. 其背后的想法是,用户将他的关键信用卡数据直接发送给braintree而不是您。 So you need a form, that sends its data to Braintree (via javascript). 因此,您需要一个表单,将其数据发送到Braintree(通过javascript)。 After that you receive a token back (the payment_method_nonce ). 之后,您将收到一个令牌( payment_method_nonce )。 You have to use this token afterwards to bill the user. 之后您必须使用此令牌向用户收费。

So I implemented it the following way in Laravel 5.2. 所以我在Laravel 5.2中以下面的方式实现了它。 It is a little bit more complicated on the implementation, as I wanted to use bootstrap format. 实现起来有点复杂,因为我想使用bootstrap格式。 You can accomplish this easier (with less flexibility) by using the older javascript v2 SDK . 通过使用旧的javascript v2 SDK,您可以更轻松地完成此任务(灵活性较低)。

My implementation: 我的实施:

/app/Http/routes.php /app/Http/routes.php

Route::get      ('upgrade', 'AccountController@getUpgrade')->name('account.upgrade');
Route::post     ('upgrade', 'AccountController@postUpgrade');

/app/Providers/AppServiceProvider.php /app/Providers/AppServiceProvider.php

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        \Braintree_Configuration::environment(env('BRAINTREE_ENV'));
        \Braintree_Configuration::merchantId(env('BRAINTREE_MERCHANT_ID'));
        \Braintree_Configuration::publicKey(env('BRAINTREE_PUBLIC_KEY'));
        \Braintree_Configuration::privateKey(env('BRAINTREE_PRIVATE_KEY'));

        \Laravel\Cashier\Cashier::useCurrency('eur', '€');

        // ....
    }
    // ...
}

/app/Http/Controllers/AccountController.php /app/Http/Controllers/AccountController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class AccountController extends Controller
{
    // ..

    public function getUpgrade()
    {
        return view('account.upgrade');
    }

    public function postUpgrade(Request $request)
    {
        $plan = 'myservice-yearly';

        $nonce = $request->input('payment-method-nonce');

        // optional user data
        $user = $request->user();
        $user_data = [
            'id' =>     'myservice_'.$user->id,
            'email' =>  $user->email,
        ];

        // optional subscription data
        $subscription_data = [];

        $user->newSubscription('main', $plan)
            ->create($nonce, $user_data, $subscription_data);

        return 'thank-you';
    }
}

/resources/views/account/upgrade.blade.php /resources/views/account/upgrade.blade.php

<h1>Upgrade</h1>

<button class="btn btn-primary" id="paypal_button"><i class="fa fa-paypal"></i> Mit PayPal zahlen</button>
<hr>
{!! Form::open(['route' => 'account.upgrade', 'class'=>'panel-body', 'id'=> 'paymentform']) !!}
    <div class="row">
        <div class="form-group col-xs-4">
            <label class="control-label">credit card number</label>
            <!--  Hosted Fields div container -->
            <div class="form-control" id="card-number"></div>
            <span class="helper-text"></span>
        </div>
    </div>
    <div class="row">
        <div class="form-group col-xs-4">
            <div class="row">
                <label class="control-label col-xs-12">expiration date</label>
                <div class="col-xs-6">
                    <!--  Hosted Fields div container -->
                    <div class="form-control" id="expiration-month"></div>
                </div>
                <div class="col-xs-6">
                    <!--  Hosted Fields div container -->
                    <div class="form-control" id="expiration-year"></div>
                </div>
            </div>
        </div>
    </div>

    <label class="control-label">security code (CCV)</label>
    <div class="row">
        <div class="form-group col-xs-2">
            <!--  Hosted Fields div container -->
            <div class="form-control" id="cvv"></div>
        </div>
    </div>

    <button type="button" class="btn btn-primary">Pay with <span id="card-type">credit card</span></button>

    <input type="hidden" name="payment-method-nonce" value="">
{!! Form::close() !!}

<!-- Load the Client component. -->
<script src="https://js.braintreegateway.com/web/3.4.0/js/client.min.js"></script>

<!-- Load additional components if desired. -->
<script src="https://js.braintreegateway.com/web/3.4.0/js/hosted-fields.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.4.0/js/paypal.min.js"></script>

<script>
    $(function(){
        braintree.client.create({
            authorization: '{{ Braintree\ClientToken::generate() }}'
        }, function (err, clientInstance) {
            if (err) {
                console.error(err);
                return;
            }

            braintree.paypal.create({
                client: clientInstance
            }, function (err, paypalInstance) {
                $('#paypal_button').click(function () {
                    // Tokenize here!
                    paypalInstance.tokenize({
                        flow: 'vault', // Required
                        billingAgreementDescription: 'MyService Premium'
                    }, function (err, payload) {
                        console.log(payload);
                        $('input[name="payment-method-nonce"]').val(payload.nonce);
                        $('#paymentform').submit();
                    });
                });
            });

            braintree.hostedFields.create({
                client: clientInstance,
                styles: {
                    'input': {
                        'font-size': '14px',
                        'font-family': 'helvetica, tahoma, calibri, sans-serif',
                        'color': '#3a3a3a'
                    },
                    ':focus': {
                        'color': 'black'
                    }
                },
                fields: {
                    number: {
                        selector: '#card-number',
                        placeholder: '4111 1111 1111 1111'
                    },
                    cvv: {
                        selector: '#cvv',
                        placeholder: '123'
                    },
                    expirationMonth: {
                        selector: '#expiration-month',
                        placeholder: 'MM'
                    },
                    expirationYear: {
                        selector: '#expiration-year',
                        placeholder: 'JJ'
                    }
                }
            }, function (err, hostedFieldsInstance) {
                if (err) {
                    console.error(err);
                    return;
                }

                hostedFieldsInstance.on('validityChange', function (event) {
                    var field = event.fields[event.emittedBy];

                    if (field.isValid) {
                        if (event.emittedBy === 'expirationMonth' || event.emittedBy === 'expirationYear') {
                            if (!event.fields.expirationMonth.isValid || !event.fields.expirationYear.isValid) {
                                return;
                            }
                        } else if (event.emittedBy === 'number') {
                            $('#card-number').next('span').text('');
                        }

                        // Apply styling for a valid field
                        $(field.container).parents('.form-group').addClass('has-success');
                    } else if (field.isPotentiallyValid) {
                        // Remove styling  from potentially valid fields
                        $(field.container).parents('.form-group').removeClass('has-warning');
                        $(field.container).parents('.form-group').removeClass('has-success');
                        if (event.emittedBy === 'number') {
                            $('#card-number').next('span').text('');
                        }
                    } else {
                        // Add styling to invalid fields
                        $(field.container).parents('.form-group').addClass('has-warning');
                        // Add helper text for an invalid card number
                        if (event.emittedBy === 'number') {
                            $('#card-number').next('span').text('Looks like this card number has an error.');
                        }
                    }
                });

                hostedFieldsInstance.on('cardTypeChange', function (event) {
                    // Handle a field's change, such as a change in validity or credit card type
                    if (event.cards.length === 1) {
                        $('#card-type').text(event.cards[0].niceType);
                    } else {
                        $('#card-type').text('Card');
                    }
                });

                $('#paymentform').submit(function (event) {
                    var value = $('input[name="payment-method-nonce"]').val();
                    console.log(event);
                    console.log('nonce=' + value);

                    if (value == '') {
                        //console.log('preventing');
                        event.preventDefault();
                        hostedFieldsInstance.tokenize(function (err, payload) {
                            if (err) {
                                console.error(err);
                                return;
                            }

                            // This is where you would submit payload.nonce to your server
                            $('input[name="payment-method-nonce"]').val(payload.nonce);
                            $('#paymentform').submit();
                        });
                    } /*else {
                        console.log('should submit');
                    }*/
                });
            });
        });
    });
</script>

See also: 也可以看看:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM