此文主要通俗易懂的讲述,支付流程开发中,数据库设计,订单的生成,支付平台调用,订单自动取消,这些主要流程。
准备工作
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', ''),
![](https://img.haomeiwen.com/i4445477/c74e6ee65535df21.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管理器即可。不会用的朋友看这里
![](https://img.haomeiwen.com/i4445477/c52abe7b0b33ac5b.png)
![](https://img.haomeiwen.com/i4445477/f48b56aa8bacbcde.png)
![](https://img.haomeiwen.com/i4445477/4adf6bd3946527df.gif)
这样还没完,因为这次开发的是APP,支付回调后要发推送消息给APP,告知支付完成,或者订单取消。不然的话得实时的调后台API查看订单状态,不够人性化。
推送功能,我用的是阿里云推送服务,下回再讲。
网友评论