微信小程序开发技巧集锦(5):发起支付

大致步骤:

客户端发起请求 》服务器检测订单是否有效、库存 》 生成签名 》返回给微信客户端 》发起支付 》 支付回调 》处理回调 》

》更新支付状态

 

1、检测订单有效性

private function checkOrderValid()
    {
        //检测订单号是否存在
        $order = OrderModel::where('id','=',$this->orderID)->find();

        if (!$order){
            throw new OrderException();
        }

        //检测订单号是否和用户匹配
        if (!TokenService::isValidOperate($order->user_id)){
            throw new TokenException(['msg'=>'订单与用户不匹配','errorCode'=>10003]);
        }

        //检测订单是否已经被支付过
        if ($order->status != OrderStatusEnum::UNPAID){
            throw new OrderException(['msg'=>'订单已经支付','errorCode'=>80003,'code'=>400]);
        }
        
        //通过
        $this->orderNo = $order->order_no;
        return true;

    }



public static function isValidOperate($checkedUID)
    {
        if (!$checkedUID){
            throw new Exception('检查用户uid是否存在');
        }

        $currentOperateUID = self::getCurrentUid();

        if($currentOperateUID == $checkedUID){
            return true;
        }
        return false;
    }

2、检测库存

$orderService = new OrderService();

        //检测库存
        $status = $orderService->checkOrderStock($this->orderID);
        if (!$status['pass']){
            return $status;//不通过
        }


public function checkOrderStock($orderID)
    {
        $oProducts = OrderProduct::where('order_id','=',$orderID)->select();

        $this->oProducts = $oProducts;

        $this->products = $this->getProductsByOrder($oProducts);

        $status = $this->getOrderStatus();

        return $status;
    }

private function getProductsByOrder($oProducts)
    {
        $oPIDs = [];
        foreach ($oProducts as $oProduct) {
            array_push($oPIDs,$oProduct['product_id']);
        }

        $products = Product::all($oPIDs)
            ->visible(['id','price','stock','name','main_img_url'])
            ->toArray();

        return $products;
    }
private function getOrderStatus()
    {
        $status = [
            'pass' => true,
            'orderPrice' => 0,//订单总价格
            'totalCount' => 0,//所有商品数量
            'pStatusArray' => [],//保存商品信息
        ];

        foreach ($this->oProducts as $oProduct) {
            $pStatus = $this->getProductStatus($oProduct['product_id'],$oProduct['count'],$this->products);
            if (!$pStatus['haveStock']){
                $status['pass'] = false;
            }
            $status['orderPrice'] += $pStatus['totalPrice'];
            $status['totalCount'] += $pStatus['count'];
            array_push($status['pStatusArray'],$pStatus);
        }

        return $status;
    }



    private function getProductStatus($oPID,$oCount,$products)
    {
        $pIndex = -1;

        //一个订单内某一个商品的信息
        $pStatus = [
            'id' => null,
            'haveStock' => false,
            'count' => 0,
            'name' => '',
            'totalPrice' => 0, //某一个商品的总价格
        ];



        for ($i = 0; $i'id为'.$oPID.'商品不存在,创建订单失败']);
        }else{
            $product = $products[$pIndex];
            $pStatus['id'] = $product['id'];
            $pStatus['name'] = $product['name'];
            $pStatus['count'] = $oCount;
            $pStatus['totalPrice'] = $product['price'] * $oCount;
            if ($product['stock'] - $oCount >= 0){
                $pStatus['haveStock'] = true;
            }
        }

        return $pStatus;
    }

3、发起支付

private function makeWxPreOrder($totalPrice)
    {
        $openid = TokenService::getCurrentTokenVar('openid');
        if (!$openid){
            throw new TokenException();
        }

        $wxOrderData = new \WxPayUnifiedOrder();

        $wxOrderData->SetOut_trade_no($this->orderNo);
        $wxOrderData->SetTrade_type('JSAPI');
        $wxOrderData->SetTotal_fee($totalPrice*100);
        $wxOrderData->SetBody('零食商贩');
        $wxOrderData->SetOpenid($openid);
        $wxOrderData->SetNotify_url(config('secure.pay_back_url'));


        return $this->getPaySignature($wxOrderData);


    }


    private function getPaySignature($wxOrderData)
    {

        $config = new \WxPayConfig();

        $wxOrder = \WxPayApi::unifiedOrder($config,$wxOrderData);

        if ($wxOrder['return_code']!='SUCCESS'||$wxOrder['result_code']!='SUCCESS'){
            Log::record($wxOrder,'error');
            Log::record('获取预支付订单失败','error');
        }

        $this->recordPreOrder($wxOrder);

        $signature = $this->sing($wxOrder);

        return $signature;
    }

    private function sing($wxOrder)
    {
        $jsApiPayData = new \WxPayJsApiPay();
        $jsApiPayData->SetAppid(config('wx.app_id'));
        $jsApiPayData->SetTimeStamp((string)time());
        $rand = md5(time().mt_rand(0,1000));
        $jsApiPayData->SetNonceStr($rand);
        $jsApiPayData->SetPackage($wxOrder['prepay_id='.'prepay_id']);
        $jsApiPayData->SetSignType('md5');

        $sign = $jsApiPayData->MakeSign();

        $rawValues = $jsApiPayData->GetValues();
        $rawValues['paySign'] = $sign;
        unset($rawValues['appId']);
        return $rawValues;
    }


    private function recordPreOrder($wxOrder)
    {
        OrderModel::where('id','=',$this->orderID)
        ->update(['prepay_id'=>$wxOrder['prepay_id']]);
    }

4、客户端支付后,微信服务器会将支付结果异步回调给我们服务器的通知地址。做出相应处理

public function NotifyProcess($data,&$msg)
    {

        if($data['result_code'] == 'SUCCESS'){
            $orderNo = $data['out_trade_no'];

            Db::startTrans();
            try{
                $order = OrderModel::where('order_no','=',$orderNo)
                    ->lock(true)
                    ->find();
                if ($order->status == OrderStatusEnum::UNPAID){

                    //如果处理较慢,则微信会发过来第二个请求,会造成库存量减小多次的情况
                    $service = new OrderService();
                    $stockStatus = $service->checkOrderStock($order->id);
                    if ($stockStatus['pass']){
                        $this->updateOrderStatus($order->id,true);
                        $this->reduceStock($stockStatus);
                    }else{
                        $this->updateOrderStatus($order->id,false);
                    }
                }

                Db::commit();
                return true;

            }catch (Exception $ex){
                Db::rollback();
                Log::error($ex);
                return false;
            }
        }else{
            return true;
        }
    }


//更新订单状态
    private function updateOrderStatus($orderID,$success)
    {
        // $success 为1 即代表:库存够;否则不够
        $status =   $success ? OrderStatusEnum::PAID : OrderStatusEnum::PAID_BUT_OUT_OF;

        OrderModel::where('id','=',$orderID)->update(['status',$status]);

        return true;

    }

//减少库存

    private function reduceStock($stockStatus)
    {
        foreach ($stockStatus['pStatusArray'] as $singlePStatus) {
            Product::where('id','=',$singlePStatus['id'])->setDec('stock',$singlePStatus['count']);
        }

        return true;
    }

 

你可能感兴趣的:(微信小程序开发技巧集锦)