kenini / amazon-payment
通过 tuurbo/amazon-payment 实现登录和通过亚马逊支付
dev-master
2020-03-19 07:27 UTC
Requires
- php: >=5.4.0
- guzzlehttp/guzzle: ^6.0
Requires (Dev)
- phpspec/phpspec: ~2.0
This package is auto-updated.
Last update: 2024-09-19 17:21:08 UTC
README
官方亚马逊包不好用,所以我制作了这个。它更轻量,设置也更简单。我在一个电子商务网站上使用这个,效果很好。
安装
通过Composer安装。
composer require kenini/amazon-payment
Laravel 4或5设置
接下来,更新app/config/app.php,在providers数组中包含此包的service provider,在aliases数组中包含facade。
'providers' => [
'Kenini\AmazonPayment\AmazonPaymentServiceProvider'
]
'aliases' => [
'AmazonPayment' => 'Kenini\AmazonPayment\AmazonPaymentFacade'
]
添加到app/config/services.php配置文件。
<?php return [ ... 'amazonpayment' => [ 'sandbox_mode' => true, 'store_name' => 'ACME Inc', 'statement_name' => 'AcmeInc 555-555-5555', 'client_id' => '', 'seller_id' => '', 'access_key' => '', 'secret_key' => '', ] ];
本地设置
<?php $config = [ 'sandbox_mode' => true, 'client_id' => '', 'seller_id' => '', 'access_key' => '', 'secret_key' => '', 'store_name' => 'ACME Inc', 'statement_name' => 'AcmeInc 555-555-5555' ]; $amazonPayment = new Kenini\AmazonPayment\AmazonPayment( new Kenini\AmazonPayment\AmazonPaymentClient( new GuzzleHttp\Client, $config ), $config ); try { $response = $amazonPayment->setOrderDetails(...); } catch (\Exception $e) { // catch errors }
两种场景
以下每个步骤代表您网站上的一个页面。
// User logs in. // User already logged in, amazon auto redirects to Checkout.
1. Login ---------> Cart ----------> Checkout
// User isn't logged in, amazon asks them to login, then redirects to Checkout.
2. Cart ----------> Checkout
示例用法(场景1)
用户点击亚马逊登录按钮时被重定向到亚马逊,然后到您的登录页面。
登录视图示例
<script type="text/javascript"> var amazonClientId = '...'; var amazonSellerId = '...'; window.onAmazonLoginReady = function(){ amazon.Login.setClientId(amazonClientId); }; </script> <script type="text/javascript" src="<?= AmazonPayment::script() ?>"></script> <script type="text/javascript"> var authRequest; OffAmazonPayments.Button("AmazonPayButton", amazonSellerId, { type: "LwA", authorization: function() { loginOptions = { scope: "profile payments:widget payments:shipping_address" }; authRequest = amazon.Login.authorize(loginOptions); }, onSignIn: function(orderReference) { <!-- redirect page ex: http://example.com/login --> authRequest.onComplete('/login?amazon_id=' + orderReference.getAmazonOrderReferenceId()); }, onError: function(error) { alert(error.getErrorCode() + ": " + error.getErrorMessage()); } }); </script>
登录控制器:GET -> http://example.com/login
<?php if (Input::has('amazon_id') && Input::has('access_token')) { try { AmazonPayment::login(Input::get('access_token')); $amazon = AmazonPayment::getLoginDetails(Input::get('access_token')); // check if user has already logged in with Amazon $user = User::where('amazon_id', $amazon['user_id'])->first(); // Update and login Amazon user if ($user) { $validator = Validator::make([ 'email' => $amazon['email'], ], [ 'email' => 'unique:user,email,'.$user->id, ]); $user->last_login = new Datetime; // update their current amazon email if ($validator->passes()) { $user->email = $amazon['email']; } $user->save(); Auth::loginUsingId($user->id); return Redirect::intended('/account'); } // if they dont have an amazon linked account, // check if there amazon email is already taken $user = \User::where('email', $amazon['email'])->first(); // email address is already taken // this is optional if you only except amazon logins if ($user) { // redirect to a page to link their amazon account // to their non-amazon account that they already have on your site. // example... $credentials = Crypt::encrypt(json_encode([ 'amazon_id' => $amazon['user_id'], 'amazon_email' => $amazon['email'], ])); // redirect and then decrypt the data and make them put in the their non-amazon password to merge their amazon account. return Redirect::to('/register/connect-amazon/'.$credentials); } } catch (\Exception $e) { Session::forget('amazon'); return Redirect::to('/login') ->with('failure_message', 'There was an error trying to login with your Amazon account.'); } // If no user already exists, create a new amazon user account $user = new \User; $user->amazon_id = $amazon['user_id']; $user->email = $amazon['email']; $user->name = $amazon['name']; $user->signup_at = 'normal amazon account'; $user->save(); Auth::user()->loginUsingId($user->id); return Redirect::intended('/account'); }
继续到场景2进行亚马逊结账...
示例用法(场景2)
用户点击亚马逊支付按钮时被重定向到亚马逊,然后回到您的结账页面。
购物车:GET -> http://example.com/cart
<script type="text/javascript"> var amazonClientId = '...'; var amazonSellerId = '...'; window.onAmazonLoginReady = function() { amazon.Login.setClientId(amazonClientId); }; </script> <script type="text/javascript" src="<?= AmazonPayment::script() ?>"></script> <script type="text/javascript"> var authRequest; OffAmazonPayments.Button("AmazonPayButton", amazonSellerId, { type: "PwA", color: "Gold", size: "medium", useAmazonAddressBook: true, agreementType: 'BillingAgreement', authorization: function() { var loginOptions = {scope: 'profile payments:widget payments:shipping_address'}; <!-- redirect page ex: http://example.com/amazon/checkout --> authRequest = amazon.Login.authorize(loginOptions, "/amazon/checkout"); }, onError: function(error) { alert(error.getErrorCode() + ": " + error.getMessage()); } }); </script> <!-- Amazon Pay button is displayed here --> <div id="AmazonPayButton"></div>
用户在亚马逊登录后,亚马逊将他们重定向回您的网站。
亚马逊结账控制器:GET -> http://example.com/amazon/checkout
<?php // get access token $accessToken = $_GET['access_token']; try { // get user details, use them if needed $amazonUser = AmazonPayment::getLoginDetails($accessToken); } catch (\Exception $e) { // Redirect back to cart page if error return Redirect::to('/cart') ->with('failure_message', 'Failed to connect to your Amazon account. Please try again.'); } // Laravel Auth example: // login user if their Amazon user_id is found in your users table // Obviously for this to work, you would have created the user entry at some other point in your app, maybe the account register page or something $user = User::where('amazon_id', $amazonUser['user_id'])->first(); // If user is found, log them in if ($user) { Auth::loginUsingId($user->id); } return View::make(...);
亚马逊结账视图示例
<script type="text/javascript"> var authRequest, referenceId; var amazonClientId = '...'; var amazonSellerId = '...'; </script> <script type="text/javascript"> window.onAmazonLoginReady = function() { amazon.Login.setClientId(amazonClientId); }; </script> <script type="text/javascript" src="<?= AmazonPayment::script() ?>"></script> <script type="text/javascript"> new OffAmazonPayments.Widgets.AddressBook({ sellerId: amazonSellerId, displayMode: 'Edit', design: { size: { width: 600, height: 250 } }, onOrderReferenceCreate: function(orderReference) { referenceId = orderReference.getAmazonOrderReferenceId(); // add the referenceId to a hidden input to be posted when the user submits their order $('#reference_id').val(referenceId); }, onAddressSelect: function(){ // disable "submit order" button until payment has been loaded or added via widget $('#submit-order').prop('disable', true); // calculate shipping, by passing `referenceId` via ajax to your server // and using the `getOrderDetails()` call below to calculate shipping, taxes, etc... // AmazonPayment::getOrderDetails([ // 'referenceId' => $_POST['referenceId'] // ]); $.ajax({ url: '/checkout/calculate_shipping', type: 'post', data: { referenceId: referenceId } }) .success(function(response){ // do something with the response... // like display shipping or taxes to the customer }); // init payment widget new OffAmazonPayments.Widgets.Wallet({ sellerId: amazonSellerId, amazonOrderReferenceId: referenceId, displayMode: 'Edit', design: { size: { width: 600, height: 250 } }, onPaymentSelect: function(orderReference){ // enable "submit order" button $('#submit-order').prop('disable', false); } }).bind("AmazonWalletWidget"); }, onError: function(error) { // window.location = '/amazon/checkout?session_expired=true'; // alert(error.getErrorCode() + ": " + error.getMessage()); } }).bind("AmazonAddressWidget"); </script> <!-- Address widget will be displayed here --> <div id="AmazonAddressWidget"></div> <!-- Payment widget will be displayed here --> <div id="AmazonWalletWidget"></div> <!-- put these is your checkout form to be posted when the user submits their order --> <input type="hidden" name="access_token" value="<?= $_GET['access_token'] ?>"> <input type="hidden" name="reference_id" id="reference_id">
用户提交订单后创建用户的订单。
亚马逊结账控制器:POST -> http://example.com/checkout
<?php // If using Laravel "Input::get('...')" can be used in place of "$_POST['...']" // get access token $accessToken = $_POST['access_token']; // get amazon order id $amazonReferenceId = $_POST['reference_id']; try { // get user details $amazonUser = AmazonPayment::getLoginDetails($accessToken); } catch (\Exception $e) { // Redirect back to cart page if error return Redirect::to('/cart') ->with('failure_message', 'Failed to connect to your Amazon account. Please try again.'); } // (optional) Wrap your Order transaction with the below code to revert the order if the amazon payment fails. // DB::beginTransaction(); // create customers order $order = new Order; $order->email = $amazonUser['email']; $order->amazon_id = $amazonReferenceId; $order->grand_total = 109.99; $order->etc... $order->save(); try { // set amazon order details AmazonPayment::setOrderDetails([ 'referenceId' => $amazonReferenceId, 'amount' => 109.99, 'orderId' => $order->id, // optional note from customer 'note' => $_POST['note'] ]); // comfirm the amazon order AmazonPayment::confirmOrder([ 'referenceId' => $amazonReferenceId, ]); // get amazon order details and // save the response to your customers order $amazon = AmazonPayment::getOrderDetails([ 'referenceId' => $amazonReferenceId, ]); $address = $amazon['details']['Destination']['PhysicalDestination']; // Update the order address, city, etc... $order->shipping_city = $address['City']; $order->shipping_state = $address['StateOrRegion']; $order->save(); // log error. // tell customer something went wrong. // maybe delete `$order->delete()` or rollback `DB::rollback();` your websites internal order in the database since it wasn't approved by Amazon } catch (\Kenini\AmazonPayment\Exceptions\OrderReferenceNotModifiableException $e) { // DB::rollback(); return Redirect::to('/secure/cart')->with('warning_message', 'Your order has already been placed and is not modifiable online. Please call '.config('site.company.phone').' to make changes.'); } catch (\Exception $e) { // DB::rollback(); return Redirect::to('/secure/cart')->with('warning_message', 'There was an error with your order. Please try again.'); } // DB::commit(); // other checkout stuff...
AmazonPayment::getOrderDetails()的示例响应
{ "details": { "AmazonOrderReferenceId": "SXX-XXXXXXX-XXXXXXX", "ExpirationTimestamp": "2015-01-29T22:35:40.555Z", "OrderTotal": { "Amount": "4637.43", "CurrencyCode": "USD" }, "Destination": { "DestinationType": "Physical", "PhysicalDestination": { "PostalCode": "60602", "CountryCode": "US", "StateOrRegion": "IL", "City": "Chicago" } }, "OrderReferenceStatus": { "State": "Draft" }, "ReleaseEnvironment": "Sandbox", "SellerOrderAttributes": { "StoreName": "ACME Inc", "SellerOrderId": "12345" }, "CreationTimestamp": "2014-08-02T22:35:40.555Z" }, "requestId": "12345678-557f-6ae2-a2ab-ef6db5a325a2" }
可用方法
<?php AmazonPayment::setOrderDetails() AmazonPayment::getOrderDetails() AmazonPayment::confirmOrder() AmazonPayment::authorize() AmazonPayment::authorizeAndCapture() AmazonPayment::capture() AmazonPayment::closeOrder() AmazonPayment::cancelOrder() AmazonPayment::refund() AmazonPayment::login() AmazonPayment::getLoginDetails() AmazonPayment::script()
亚马逊文档:http://docs.developer.amazonservices.com/en_US/apa_guide/APAGuide_Introduction.html