支付宝沙箱支付调用
下单减库存
//下单减库存
public function index()
{
//开启事物
DB::beginTransaction();
try {
$stock = DB::table('seckill_goods')
->value('stock');
//如果商品还有库存
if ($stock > 0) {
DB::table('seckill_goods')
->where('id', 1)
->update(['stock' => $stock - 1]);
//创建订单
DB::commit();
return '秒杀成功';
}
//返回秒杀结果
return '秒杀失败';
} catch (\Exception $exception) {
DB::rollBack();
Log::info($exception->getMessage());
}
}
支付减库存(单例模式)
/**
* 支付减库存
* @return void
*/
public function payStock()
{
// echo 11;die;
//开启事物
DB::beginTransaction();
//接收支付宝回调过来的参数
//就是订单的信息
try {
//根据订单号去订单表查询订单详情,详情里面是不是就有你参与哪个秒杀活动及秒杀商品id
//先得到库存
$stock = DB::table('seckill_goods')
->value('stock');
var_dump($stock);
//如果秒杀的商品还有库存
if ($stock > 0) {
//把秒杀商品为1的库存-1
DB::table('seckill_goods')
->where('id', 1)
->update(['stock' => $stock - 1]);
//修改订单状态
//记录秒杀记录表
// DB::commit();
echo "success";
} else {
//支付成功但是库存不足
//虽然钱花了,但是订单还是未支付
}
} catch (\Exception $exception) {
DB::rollBack();
Log::info($exception->getMessage());
}
}
单例模式↑↓
<?php
namespace App\Server;
use Illuminate\Support\Facades\Redis;
class RedisSever
{
//类的属性可以供类里面的所有方法访问
//private(只供本类里面的方法使用) protected(受保护的) public(公共的)
private static $instance;
private $redis;
/**
* __construct 构造函数
* 只用有人调用之类,首先走到这个方法里
*/
private function __construct()
{
$redis = new \Redis();
$redis->connect('127.0.0.1','6379');
$redis->select(7);
$this->redis = $redis;
}
/**
* 公众的静态方法,对外提供实列
* @return void
*/
public static function getInstance()
{
if (self::$instance) {
return self::$instance;
} else {
self::$instance = new self();
return self::$instance;
}
}
/**
* 防止类外复制这个类的实例
* @return void
*/
private function __clone()
{
}
public function exists($key)
{
return $this->redis->exists($key);
}
public function rPush($key,$value)
{
return $this->redis->rPush($key,$value);
}
public function lPop($key)
{
return $this->redis->lPop($key);
}
public function sAdd($key,$data)
{
return $this->redis->sAdd($key,$data);
}
public function sIsMember($key,$data)
{
return $this->redis->sIsMember($key,$data);
}
public function watch($key)
{
$this->redis->watch($key);
}
public function multi()
{
$this->redis->multi();
}
public function lLen($key)
{
return $this->redis->lLen($key);
}
public function exec()
{
return $this->redis->exec();
}
}
库存预热,
/**
* 库存预热
*/
public function preheatStock()
{
//接收参数,要知道预热秒杀活动/秒杀商品的id
$seckillGoodsId = 1;
//先判断redis有没有这个key (这个redis以什么类型存储比较合适 redis-list(特性 先进先出 他就是把并行操作专成了串行操作))
//redis中存储必须唯一
$redisSeckillGoodsId = 'seckill_goods_list_' . $seckillGoodsId;
//如果没有这个key就先去数据库查一下秒杀商品的库存
if (!RedisSever::getInstance()->exists($redisSeckillGoodsId)) {
$stock = DB::table('seckill_goods')
->value('stock');
//把秒杀商品的库存存入到redis-list里
for ($i = 0; $i < $stock; $i++) {
RedisSever::getInstance()->rPush($redisSeckillGoodsId, 1);
}
}
//就返回结果集
return '商品库存预热成功';
}
预扣库存
/**
* 预扣库存
* @return void
*/
public function redisStock()
{
//秒杀商品ID
$seckillGoodsId = 1;
$activityId = 1;
$userID = 20;
//购买数量
$num = 1;
//通过商品的id重新查一下商品的价格
$originPrice = DB::table('seckill_goods')
->where('id', $seckillGoodsId)
->value('price');
//总金额
$totalPrice = ($originPrice * 100) * $num / 100;
$currentTime = date("Y-m-d H:i:s", time());
try {
//秒杀商品的库存
$redisSeckillGoodsId = 'seckill_goods_list_' . $seckillGoodsId;
//用来存放秒杀成功的用户
$redisSeckillGoodsSet = 'seckill_goods_set_' . $seckillGoodsId;
//判断用户有没有参与过秒杀
if (RedisSever::getInstance()->sIsMember($redisSeckillGoodsSet, $userID)) {
return response()->json([
'code' => 200,
'data' => null,
'msg' => '你已经参与过了,不能在参与了'
]);
}
//开启redis事物
RedisSever::getInstance()->watch($redisSeckillGoodsId);
// RedisServer::getInstance()->multi();
//判断redis是否还有库存
$redisStock = RedisSever::getInstance()->lLen($redisSeckillGoodsId);
if ($redisStock > 0) {
//如果库存大于0,弹出库存
RedisSever::getInstance()->lPop($redisSeckillGoodsId);
//创建订单(或者在生成一个队列用来异步创建订单)
$orderData = [
'order_no' => date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT),
'user_id' => $userID,
'activity_id' => $activityId,
'sckill_goods_id' => $seckillGoodsId,
'original_price' => $originPrice,
'total_price' => $totalPrice,
'status' => 0,
'pay_method' => 0,
'address' => json_encode([
'username' => "赵某某",
'phone' => "13939376629",
'address' => "河南省郑州市西四环",
]),
'num' => $num,
'created_at' => $currentTime,
'updated_at' => $currentTime,
];
DB::table('order')->insert($orderData);
//异步记录秒杀记录表
//在生成一个延迟队列,用于库存归还
//如果已经参与过该商品的秒杀,就不能在次秒杀,怎么办 redis set集合(无序且唯一)
RedisSever::getInstance()->sAdd($redisSeckillGoodsSet, $userID);
RedisSever::getInstance()->exec();
return response()->json([
'code' => 200,
'data' => $orderData,
'msg' => '秒杀成功'
]);
} else {
return response()->json([
'code' => 200,
'data' => null,
'msg' => '没有库存了'
]);
}
return response()->json([
'code' => 200,
'data' => null,
'msg' => '秒杀失败'
]);
} catch (\Exception $exception) {
Log::info($exception->getMessage());
}
}
调用沙箱模式
<?php
use Yansongda\Pay\Pay;
use Yansongda\Pay\Log;
class AliPayController extends Controller
{
protected $config = [
'app_id' => '',
'notify_url' => 'http://*********.cn',
'return_url' => 'http://*********.cn',
'ali_public_key' =>'',
// 加密方式: **RSA2**
'private_key' =>'',
'log' => [ // optional
'file' => './logs/alipay.log',
'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
'type' => 'single', // optional, 可选 daily.
'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
],
'http' => [ // optional
'timeout' => 5.0,
'connect_timeout' => 5.0,
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
'mode' => 'dev', // optional,设置此参数,将进入沙箱模式
];
protected $refundConfig = [
'app_id' => '',
'notify_url' => 'http://*********.cn',
'return_url' => 'http://*********.cn',
'ali_public_key' =>',
// 加密方式: **RSA2**
'private_key' =>'',
'log' => [ // optional
'file' => './logs/alipay.log',
'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug
'type' => 'single', // optional, 可选 daily.
'max_file' => 30, // optional, 当 type 为 daily 时有效,默认 30 天
],
'http' => [ // optional
'timeout' => 5.0,
'connect_timeout' => 5.0,
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
],
'mode' => 'dev', // optional,设置此参数,将进入沙箱模式
];
}
同步回调
/**
* 同步回调
* @return void
*/
public function return()
{
return view('good');
}
异步回调
/**
* 异步必须是外网可以访问ip或域名
* 异步回调
* @return mixed
*/
public function notify(Request $request)
{
//异步回调用来处理订单的状态
$params = $request->all();
DB::beginTransaction();
try {
$currentTime = date('Y-m-d H:i:s', time());
//支付成功,更改订单状态
if ($params['trade_status'] == "TRADE_SUCCESS") {
//根据订单号去更改订单状态
DB::table('order')
->where('order_no', $params['out_trade_no'])
->update([
'trade_no' => $params['trade_no'],
'status' => 1,
'pay_method' => 1,
'updated_at' => $currentTime
]);
//先根据订单号查询订单表的秒杀商品id
$sckillGoodsId = DB::table('order')
->where('order_no', $params['out_trade_no'])
->value('sckill_goods_id');
//查询秒杀商品的库存
$stock = DB::table('seckill_goods')
->where('id', $sckillGoodsId)
->value('stock');
//更新库存
if ($stock > 0) {
DB::table('seckill_goods')
->where('id', $sckillGoodsId)
->update([
'stock' => $stock - 1
]);
}
//比如短信的短信或者微信公众号推送模版消息
//App站内信
//App极光推送
DB::commit();
//告诉支付宝支付成功,如果不给支付宝返回success,支付宝会在25小时给你发送5次异步请求
echo 'success';
}
DB::rollBack();
} catch (\Exception $e) {
DB::rollBack();
\Illuminate\Support\Facades\Log::info($e->getMessage());
}
}
public function getCache()
{
//异步回调用来处理订单的状态
$res = Cache::get('ali');
print_r($res);
echo '-----';
$a = Cache::get('a');
print_r($a);
echo '-----';
$b = Cache::get('b');
print_r($b);
echo '-----';
$c = Cache::get('c');
print_r($c);
die;
}
退款并使用微信公众号推送
/**
* 退款
* @return void
*/
public function refund()
{
//退款 首先获取到订单号和价格
$order = [
'out_trade_no' => '2023041152561',
'refund_amount' => '1499',
];
//try处理异常报错信息
try {
//网关报错,退款需要应用公钥
$alipay = Pay::alipay($this->refundConfig);
$result = $alipay->refund($order);
//退款成功,订单状态改为已退款,
DB::table('order')
->where('order_no', $order['out_trade_no'])
->update([
'status' => 6
]);
$params = [
"touser" => '',
"template_id" => '',
"data" => [
"order_no" => [
"value" => $order['out_trade_no']
],
"total_price" => [
"value" => $result->send_back_fee
]
]
];
//并且推送微信模版消息
(new WechatController())->pushMasterPlate($params);
return response()->json([
'code' => 200,
'data' => null,
'msg' => '退款成功'
]);
} catch (\Exception $exception) {
\Illuminate\Support\Facades\Log::info($exception->getMessage());
}
}