PHP 支付过程 沙箱模拟支付

支付宝沙箱支付调用

下单减库存

//下单减库存
    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());
        }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值