golang、php,laravel框架对接stripe海外支付接口的总结和流程(通俗易懂)

目录

stripe是什么?

环境

配置后台

首先让管理员把你设置成为开发者

然后进入后台

然后你要创建产品,开单周期要写每天,我这里理解成每天都会有人买的

获取产品id

获取密钥,后续代码需要用到

支付代码

唤起支付页面

测试的信用卡号

添加端点webhook

stripe后台配置

非常注意的地方

处理回调代码

golang代码(自己测试用的,go的程序员可以看看)

最后,怎么找到他们的技术支持呢?


stripe是什么?

我们国内有支付宝、微信、银联,国外就有stripe,但是他们是信用卡的。

据我探索,有以下支付方式

  1. Checkout Session 文档位置:https://docs.stripe.com/api/checkout/sessions
  2. payment links  文档位置: https://docs.stripe.com/api/payment_links/payment_links
  3. credit notes 文档位置:https://docs.stripe.com/api/credit_notes/object

注意:我们用checkout session

环境

PHP:7.2

框架:laravel 5.5以上都行

compose包:

composer require stripe/stripe-php

配置后台

我们在开始前,要清楚stripe的流程,他们的流程跟我们国内是完全不一样的。

首先让管理员把你设置成为开发者

然后进入后台

点产品目录,再点测试模式,在测试模式下,是不会产生付费的,都是虚拟的,大家可以放心

然后你要创建产品,开单周期要写每天,我这里理解成每天都会有人买的

获取产品id

获取密钥,后续代码需要用到

支付代码

#配置刚刚后台获取到的密钥
STRIPE_KEY=sk_test_5
use App\Http\Controllers\CIAesController;
use App\Http\Controllers\Controller;
use App\Model\OrdersModel;
use App\Model\ProductModel;
use App\Model\UsersModel;
use App\Model\VerifyCodesModel;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Redirect;
use Stripe\Stripe;
use Stripe\StripeClient;


    //创建商品
    public function createProduct(Request $request)
    {
        $vip_tag = $request->input('vip_tag');
//        $product_id  = 'prod_Q9V9Ypb6KFF4M4';
//        $order_id    = '29101d2d';
//        $goods_price = 1;
        try {
            $userInfo = $this->getUserInfoServer();
            if (!isset($userInfo['id']) || !$userInfo['id']) {
                throw new \Exception('当前未登录,请先登录', 9000);
            }

            if ($userInfo['type'] != 2) {
                throw new \Exception('请用邮箱登录再支付', 9000);
            }

            if ($userInfo['expiratio_date'] >= date('Y-m-d H:i:s')) {
                throw new \Exception('会员只支持购买一个');
            }
            $productInfo = ProductModel::where('vip_tag', $vip_tag)->first();
            if (!$productInfo) {
                throw new \Exception('暂无价格');
            }
            $product_id  = $productInfo->product_id;
            $order_id    = 'qw' . date('YmdHis') . time() . mt_rand(1000, 9999);
            $goods_price = $productInfo->price;
            // 创建订单
            OrdersModel::insert([
                'user_id'     => $userInfo['id'],
                'transfer_no' => $order_id,
                'amount'      => $goods_price,
                'product_id'  => $product_id,
                'status'      => 3,
            ]);
            $url = $this->create_price($product_id, $order_id, $goods_price, 0);
            return Redirect::to($url);// 重定向去支付
        } catch (\Exception $e) {
            Log::error('createProduct', [
                'msg'  => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
            ]);

            if ($e->getCode() == 9000) {
                return redirect('home/login');
            }
            return back()->withErrors([$e->getMessage()])->withInput();
        }


    }

    /***
     * 创建价格
     * @param $product_id 产品id
     * @param $order_id 业务系统的订单id
     * @param $goods_price
     * @param $is_source 订阅用到的
     * @return string|null
     * @throws \Stripe\Exception\ApiErrorException
     */
    public function create_price($product_id, $order_id, $goods_price, $is_source)
    {
        //获取订单对应的商品价格
//        $goods_price = \db('order')->where('id', $order_id)->value('pay_money');

        $_key      = env('STRIPE_KEY');// 你的私钥
        $stripe    = new StripeClient($_key);
        $price_arr = $stripe->prices->create([
            'unit_amount'  => $goods_price * 100,
            //'unit_amount' => 1*100,
            'currency'     => 'usd',
            'tax_behavior' => 'exclusive',
            //'recurring' => ['interval' => 'day'],
            'product'      => $product_id,
            'metadata'     => ['order_id' => $order_id],
        ]);
        //print_r($price_arr->id);die;
        return $this->actionStripe($price_arr->id, $order_id, $is_source);
    }

    /**
     * 创建stripe支付
     * @param $price_id 产品id
     * @param $order_id 业务系统订单id
     * @param $is_source 订阅用到的
     * @return string|null
     * @throws \Stripe\Exception\ApiErrorException
     */
    public function actionStripe($price_id, $order_id, $is_source)
    {
        $_key = env('STRIPE_KEY');
        $domain = 'xxx';// 要回调的域名

        //如果是AI订阅和AI作品打样的话
        if ($is_source == 8 || $is_source == 9) {
            $cancel_url  = '';
            $success_url = '';
        } else {
            $cancel_url  = $domain . '/home/actionNotify';
            $success_url = $domain . '/home/index';
        }
        // stripe 生成订单

        Stripe::setApiKey($_key);

        $checkout_session = \Stripe\Checkout\Session::create([
            'line_items'  => [
                [
                    'price'    => $price_id, // 产品id
                    'quantity' => 1,
                ],
            ],
            'mode'        => 'payment',
            'success_url' => $success_url,// 同步回调
                        'cancel_url'  => $cancel_url,// 异步回调
            //            'automatic_tax' => [
            //                'enabled' => false,// 设置为true就要开通税务,会提示Stripe Tax has not been activated on your account. Please visit https://stripe.com/docs/tax/set-up to get started
            //            ],
            'metadata'    => [
                'order_id' => (string)$order_id,
            ],
        ]);
        Log::info('', ['ses' => $checkout_session, 'id' => $checkout_session->id]);
        return $checkout_session->url;
    }

唤起支付页面

当你调用完支付代码,会重定向到stripe支付界面

测试的信用卡号

因为我们是测试环境,这时候支付要用他们提供的测试信用卡号,那么这个卡号在哪里拿的呢?

点链接文档: https://docs.stripe.com/testing

stripe提供了好多信用卡给我们做测试的

添加端点webhook

这时候,我们创建完订单,如果用户支付完成,怎么回调呢?就比如我们支付宝、微信这些支付,都是要回调业务系统的订单号的

我们在上面的代码中,通过metadata来传递了订单号了,那么怎么接受他呢?没错,就是异步回调,stripe的异步回调叫做webhook

stripe后台配置

异步回调地址:http://xxxxx.com/home/actionNotify

非常注意的地方

一定要注意了我们用的是Checkout:Session方式

所以在添加webhook的时候,要选择checkout的,否则你会接受不到metadata元数据,这里面的订单号order_id

处理回调代码


    public function actionNotify(Request $request)
    {
        Log::info('asdas', ['all' => $request->all()]);
        $data = $request->input('data', []);
        $type = $request->input('type', '');

        $payload = @file_get_contents('php://input');
        try {
            if (!isset($data['object']) || !$data['object']) {
                throw new \Exception('参数有误');
            }
            $event = \Stripe\Event::constructFrom(
                json_decode($payload, true)
            );

            switch ($event->type) {
                case 'checkout.session.completed':
                    $succeeded = $event->data->object;
                    $content = "=========".date('Y-m-d H:i:s',time())."==========\r\n";
                    $content .= json_encode($succeeded);
                    Log::info('content=======' . var_export($content, true));

                    if ($succeeded->status == 'complete') {
                        $order_id = $succeeded->metadata->order_id;
                        // 处理支付成功逻辑
                        $orderInfo = OrdersModel::where('status', 3)->where('transfer_no', $order_id)->first();
                        try {
                            if (!$orderInfo) {
                                throw new \Exception('暂无订单');
                            }
                            $userInfo = UsersModel::where('status', 1)->where('id', $orderInfo->user_id)->first();
                            if (!$userInfo) {
                                throw new \Exception('没有此用户');
                            }
                            $productInfo = ProductModel::where('status', 1)
                                ->where('product_id', $orderInfo->product_id)
                                ->first();

                            if (!$productInfo) {
                                throw new \Exception('没有这个产品');
                            }

                            DB::beginTransaction();
                            $productInfo->period = $productInfo->period + 1;
                            $expiratio_date = date('Y-m-d', strtotime("+ $productInfo->period day"));
                            $userBool       = UsersModel::where('id', $userInfo->id)->update([
                                'expiratio_date'    => $expiratio_date,
                                'day_search_number' => $productInfo->day_search_number + $userInfo->day_search_number,
                                'vip_tag'           => $productInfo->vip_tag,
                            ]);
                            if (!$userBool) {
                                throw new \Exception('修改用户表失败');
                            }
                            $orderBool = OrdersModel::where('id', $orderInfo->id)->update(['status' => 1]);
                            if (!$orderBool) {
                                throw new \Exception('修改订单表失败');
                            }
                            DB::commit();
                        } catch (\Exception $e) {
                            DB::rollBack();
                            Log::error('增加权限失败', [
                                'msg'       => $e->getMessage(),
                                'line'      => $e->getLine(),
                                'file'      => $e->getFile(),
                                'orderInfo' => $orderInfo,
                            ]);
                        }
                    }
                    break;
                case 'checkout.session.async_payment_failed':
                    Log::info('pay is failed');
                    break;
                default:
                    echo 'Received unknown event type ' . $event->type;
                    break;
            }

        } catch(\UnexpectedValueException $e) {
            // Invalid payload
            http_response_code(400);

            Log::error('actionNotify', [
                'msg'  => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'all'  => $request->all(),
            ]);
            return false;
        }
    }

golang代码(自己测试用的,go的程序员可以看看)

package controller

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/stripe/stripe-go"
	"github.com/stripe/stripe-go/checkout/session"
	"log"
	"os"
)

func Stripe(c *gin.Context)  {
	stripe.Key = "sk_test_sxxxxxxx"

	lineItem := &stripe.CheckoutSessionLineItemParams{
		Quantity:     stripe.Int64(1),            // 数量
		Amount: stripe.Int64(100),
		Currency: stripe.String("usd"),
		Name: stripe.String("测试商品"),
		// 可以添加其他可选字段,比如 Description、Images 等
	}
	lineItems := []*stripe.CheckoutSessionLineItemParams{lineItem}

	params := &stripe.CheckoutSessionParams{
		SuccessURL: stripe.String("http://www.example.com/success"),
		CancelURL:  stripe.String("https://xxxxx.com/api/enterprise/wechat/mhCallback"),
		PaymentMethodTypes: stripe.StringSlice([]string{
			"card",
		}),
		Mode: stripe.String("payment"),
		LineItems: lineItems,
	}
	params.Metadata = map[string]string{
		"order_id":"123",
	}


	// 创建付款Session
	s, err := session.New(params)
	if err != nil {
		log.Fatalf("Error creating Checkout Session: %v", err)
	}
	// 输出付款链接
	url := "https://checkout.stripe.com/c/pay/" + s.ID + "#fidkdWxOYHwnPyd1blpxYHZxWjA0VUJsMWhXdnxuN2p9SEBxYkltRkpGcn9GT2NAQHxcXDVGakFDYE9pdDFda3dXXHNwSUpDbzdkT2tmPGZmcEpIaURPU0JJdk89Yk13Nl9ddlVMV1c2TDM2NTUxclRuaEtydicpJ2N3amhWYHdzaaanP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBabHFgaCcpJ2BrZGdpYFVpZGZgbWppYWB3dic%2FcXxxYHgl"
	fmt.Fprintf(os.Stdout, "付款链接: %v\n", url)
return
}

最后,怎么找到他们的技术支持呢?

全程英文交流

文档位置:https://support.stripe.com/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值