美文网首页PHP开发PHP经验分享Laravel
Laravel 订单支付的开发与设计

Laravel 订单支付的开发与设计

作者: ONEDAYLOG | 来源:发表于2020-05-01 21:08 被阅读0次

此文主要通俗易懂的讲述,支付流程开发中,数据库设计,订单的生成,支付平台调用,订单自动取消,这些主要流程。

准备工作
1.申请好支付宝支付(支付宝商户号>>>支付宝开放平台),支付宝申请很快
2.申请开通微信支付(需要微信服务号>>>微信开放平台>>>微信商户平台),申请很慢,开放平台还需要提供app官网介绍
3.Laravel 安装 yansongda/laravel-pay 用起来非常方便
4.后台搭建不多说了,前面有写过

数据库设计

goods商品表,用于记录商品信息

        Schema::create('goods', function (Blueprint $table) {
            $table->increments('id');
            $table->string('goods_shop_id')->default(null)->comment("商户名称");
            $table->string('goods_name')->default(null)->comment("商品名称");
            $table->string('goods_img')->default(null)->comment("商品图片");
            $table->decimal('goods_price')->default(null)->comment("商品价格");
            ...........
            $table->timestamps();
        });

order 订单表,用于记录订单基本信息

        Schema::create('order', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->default(null)->comment("用户id");
            $table->bigInteger('order_no')->default(null)->comment("订单号");
            $table->decimal('payment')->default(null)->comment("实付金额");
            $table->integer('payment_type')->default(1)->comment("支付类型,1-在线支付");
            $table->integer('status')->default(10)->comment("订单状态:0-已取消-10-未付款-5-已付款");
            $table->timestamp('platform_time')->nullable()->default(null)->comment("支付时间");
            $table->timestamp('end_time')->nullable()->default(null)->comment("交易完成时间");
            $table->timestamp('close_time')->nullable()->default(null)->comment("交易关闭时间");
            $table->timestamps();
        });

pay_info 支付表,用于记录支付信息

        Schema::create('pay_info', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->default(null)->comment("用户id");
            $table->bigInteger('order_no')->default(null)->comment("订单号");
            $table->integer('pay_platform')->default(null)->comment("支付平台:1-支付宝,0-微信支付");
            $table->string('platform_number')->default(null)->comment("对应平台的订单号");
            $table->string('platform_status')->default(null)->comment("支付状态");
            $table->timestamps();
        });

order_item订单详情表,为什么还要建立这么一个表呢,因为商品价格,是会波动的,这里需要记录一下,购买当时的一些基本商品信息,自行扩充吧

        Schema::create('order_item', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->default(null)->comment("用户id");
            $table->bigInteger('order_no')->default(null)->comment("订单号");
            $table->integer('goods_id')->default(null)->comment("商品id");
//            $table->string('goods_shop_id')->default(null)->comment("商户名称");
//            $table->string('goods_name')->default(null)->comment("商品名称");
//            $table->string('goods_img')->default(null)->comment("商品图片");
//            $table->decimal('goods_unit_price')->default(null)->comment("商品价格");
            $table->integer('quantity')->default(null)->comment("数量");
            $table->decimal('total_price')->default(null)->comment("总价");
            $table->timestamps();

支付对接配置(微信支付真的太慢了,我申请了半个月都没过)

yansongda/laravel-pay 安装好后配置一下config/pay.php

        // 支付宝分配的 APPID
        'app_id' => env('ALI_APP_ID', ''),
        // 支付宝异步通知地址
        'notify_url' => env('APP_URL', '') . "/api/ali_notify",
        // 支付成功后同步通知地址
        'return_url' => env('APP_URL', '') . "/api/ali_return",
        // 阿里公共密钥,验证签名时使用
        'ali_public_key' => env('ALI_PUBLIC_KEY', ''),
        // 自己的私钥,签名时使用
        'private_key' => env('ALI_PRIVATE_KEY', ''),
image.png

配置好了可以先用客户端调试工具使用教程先测试一下是否成功

订单生成

生成订单次要的就不写了

//生成唯一的订单号
function getsn(){
    $osn = date('Ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
    return $osn;
}

        $order_no = getsn();

        $orderitem = new OrderItem();
        $orderitem->user_id = $user->id;
        $orderitem->order_no = $order_no;
        $orderitem->good_id = $good->id;
        $orderitem->quantity = (int)$request->gold_num;
        $orderitem->total_price = $coin->coin_price * (int)$request->gold_num;

        $payinfo = new PayInfo();
        $payinfo->user_id = $user->id;
        $payinfo->order_no = $order_no;
        $payinfo->pay_platform = $request->pay_type;

        $order = new Order();
        $order->user_id = $user->id;
        $order->order_no = $order_no;
        $order->payment = $coin->coin_price * (int)$request->gold_num;
        $order->payment_type = 1;
        $order->status = 10;

        DB::transaction(function () use ($payinfo, $orderitem, $order) {
            $orderitem->save();
            $payinfo->save();
            $order->save();
            //30分钟自动取消取消订单
            DelayOrder::dispatch($order->id);
        }, 5);

        if ($request->pay_type == 1) {
            $order = [
                'out_trade_no' => $order_no,
                'total_amount' => $coin->coin_price * (int)$request->gold_num,
                'subject' => " 购买 " . $good->good_name . (int)$request->gold_num . "个",
            ];

            return Pay::alipay()->app($order);
        } else {
            return $this->error('微信支付接口尚未完成');
        }

验签同步回调

    /**
     * 2.8.1 支付宝同步回调
     */
    public function ali_return()
    {
        $data = Pay::alipay()->verify();
    }

异步回调,业务逻辑写在这里

public function ali_notify()
    {
        $alipay = Pay::alipay();
        try {
            $data = $alipay->verify(); // 是的,验签就这么简单!

            if ($data->app_id != env('ALI_APP_ID')) {
                $this->error('非法交易:ALI_APP_ID不一致');
            }
            if ($data->trade_status != "TRADE_SUCCESS") {
                $this->error('非法交易:交易不成功');
            }
            $orderitem = Order::where('order_no', $data->out_trade_no)
                ->whereNull('platform_time')
                ->whereNull('close_time')
                ->first();
            if (!$orderitem) {
                $this->error('非法交易:没有该订单');
            }

            if ($data->total_amount != $orderitem->payment) {
                $this->error('非法交易:金额不一致');
            }

//业务逻辑,无非就是修改数据库字段
            $this->payment_callback($data->out_trade_no, $data->trade_status, $data->trade_no);

        } catch (\Exception $e) {
            // $e->getMessage();
            $this->error($e->getMessage());
        }
    }

订单自动取消

redis 的默认连接是有超时调用,这个方法我没有成功。
直接使用laravel的Queue的delay 延迟任务,也是基于Redis 的超时调用,只不过已经封装好了,多好用。

1.Redis 官方文档有写,直接配置,记得服务器上安装Redis,宝塔上非常的方便
2.config/database.php中 redis的'read_write_timeout' => env('REDIS_RW_TIMEOUT', -1),不然Redis会自动断开连接
3.修改 config/queue.php'default' => env('QUEUE_CONNECTION', 'redis'),意思就是改成Redis了
4.创建一个延时队列

php artisan make:job DelayOrder
<?php

namespace App\Jobs;
use App\Model\Order;
use App\Model\Set;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\DB;
class DelayOrder implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    protected $id='';
    protected $redis='';
    protected  $key = 'order_list';
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($id)
    {
        $this->id = $id;
        $set = Set::find(1);
        //我是后台可以设置时间的
        $this->delay(Carbon::now()->addMinute((int)$set->order_close));
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $order = Order::find($this->id);
        if ($order->status == 10) {
            $order->status = 2;
            $order->end_time = time();
            $order->close_time = time();
            $order->save();
        }
    }
}

实时写入订单号监控

DelayOrder::dispatch($order->id);

启用列队

php artisan queue:work

你会发现你的命令太卡住了,OMG,这怎么行。用Supervisor 来确保队列处理器不会停止运行。
因为我是用宝塔面板,所以直接安装Supervisor管理器即可。不会用的朋友看这里

列队任务.png
日志.png
订单后台查看.gif
这样还没完,因为这次开发的是APP,支付回调后要发推送消息给APP,告知支付完成,或者订单取消。不然的话得实时的调后台API查看订单状态,不够人性化。

推送功能,我用的是阿里云推送服务,下回再讲。

相关文章

网友评论

    本文标题:Laravel 订单支付的开发与设计

    本文链接:https://www.haomeiwen.com/subject/monqghtx.html