위챗 소프로그램 개발 기교 모음(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;
    }

좋은 웹페이지 즐겨찾기