<?php

namespace Order;
use Our\ApiConst;
use Our\RedisHelper;


/**
 * 订单确认工具类
 * User: liuyuzhen
 * Date: 2018/7/1
 * Time: 10:19
 * Description:
 */
class OrderConfirmUtil {

    private $memberId = array();

    //下单用户信息
    private $member = array();

    //收货人地址信息
    private $address = array();

    //前台传输来的数据
    private $postData = array();

    private $postFormatData = array();

    private $cartIds = array();

    private $storeIds = array();

    private $storeCartIds = array();

    private $couponIds = array();

    private $storeCouponIds = array();

    private $saleGoodsIds = array(); //参与销售活动结算的goodsId 列表

    private $storeMemos = array();

    private $cartCacheDeleteFlag = false;

    private $pushMessageOrders = array();

    private $couponCacheFlag = false;

    /**
     * 添加订单
     * @param $data
     * @param $memberId
     * @param $currentAddress
     * @param string $formId 小程序微信支付支付表单id
     * @return array
     * @throws \Exception
     * User: King <358887571@qq.com>
     * Date: 2018/12/25 0025
     * Time: 下午 3:01
     */
    public  function addOrder($data, $memberId, $currentAddress, $formId = ''){
        $storeCartData = $this->checkPostData($data,$memberId,$currentAddress);
        //return $storeCartData;
        if(CURRENTVERSION==\Our\NameConst::versionDefault){
            $storeCartData = $this->checkDeliveryTypeAndPayway($storeCartData);
        }else{
            $storeCartData = $this->checkDeliveryTypeAndPaywayNew($storeCartData);
        }
        return $this->saveOrderInfo($storeCartData, $formId);
    }


    /**
     * 验证传入数据的完成性
     * @param $data
     * @param $memberId
     * @param $currentAddress
     * @return array
     * @throws \Error\OurExceptionModelfav
     * @throws \Exception
     */
    public function checkPostData($data,$memberId,$currentAddress){
        $dbName = \Our\DbNameConst::masterDBConnectName;
        $this->memberId = $memberId;
        $this->member = \DAO\MemberModel::getInstance()->getInfo($this->memberId);
        $this ->address = $this->checkCurrentAddress($currentAddress,$this->memberId);
        //if($this ->address['addressId'] == )
        $this->postData = json_decode($data['param'],true);
        if(!$this->postData){
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::emptyParamForOrder);
        }
        if(isset($this->postData['storeId'])&&$this->postData['storeId']){//组合销售或者单品的立即购买
            if(CURRENTVERSION==\Our\NameConst::versionDefault){
                $this->checkOneStoreData($this->postData);
            }else{
                $this->checkOneStoreDataNew($this->postData);
            }
            if((isset($this->postData['blId'])&&$this->postData['blId']>\Our\ApiConst::zero)&&(isset($this->postData['goodsId'])&&$this->postData['goodsId']>\Our\ApiConst::zero)){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongBlIdAndGoodsIdForOrder);
            }else if(!(isset($this->postData['goodsId'])&&$this->postData['goodsId']>\Our\ApiConst::zero)&&!(isset($this->postData['blId'])&&$this->postData['blId']>\Our\ApiConst::zero)){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::emptyGoodsIdOrBlIdForOrder);
            }
            if(!(isset($this->postData['goodsNum'])&&$this->postData['goodsNum']>\Our\ApiConst::zero)){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::emptyGoodsNumForBuyNowOrder);
            }
            $pBundlingService = \Business\Goods\GroupSaleServiceModel::getInstance();
            $cartList = $pBundlingService->getFormatBuyNowListForOrder($this->postData,$this->memberId,$dbName);
			$gcIds = isset($cartList['gcIds'])?$cartList['gcIds']:array();
            $storeCartData = array('cartList'=>$cartList['list'],'storeIds'=>array_keys($cartList['list']),'goodsIds'=>$cartList['goodsIds'],'goodsCommonIds'=>$cartList['goodsCommonIds'],'blIds'=>$cartList['blIds'],'gcIds'=>$gcIds);
            $this->storeIds= array_keys($cartList['list']);
            $this->storeMemos[$this->postData['storeId']] = isset($this->postData['storeMemo'])?$this->postData['storeMemo']:\Our\NameConst::emptyString;
		}else{
            $this->cartCacheDeleteFlag = true;
            foreach($this->postData as $temp){
                if(CURRENTVERSION==\Our\NameConst::versionDefault){
                    $this->checkOneStoreData($temp);
                }else{
                    $this->checkOneStoreDataNew($temp);
                }
                if(!$temp['cartIds']){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::emptyCartIdsForOrder);
                }
                if($this->cartIds){
                    $this->cartIds = array_merge($this->cartIds,$temp['cartIds']);
                }else{
                    $this->cartIds = $temp['cartIds'];
                }
                $this->storeIds[]= $temp['storeId'];
                $this->storeCartIds[$temp['storeId']] =$temp['cartIds'];
                $this->postFormatData[$temp['storeId']] = $temp;
                $this->storeMemos[$temp['storeId']] = isset($temp['storeMemo'])?$temp['storeMemo']:\Our\NameConst::emptyString;
            }
            if($this->couponIds){
                if(count($this->couponIds)!= count(array_unique($this->couponIds))){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::sameCoupnIdsForOrder);
                }
            }
            $cartDao = \DAO\Cart\CartModel::getInstance($dbName);
            $storeCartList = $cartDao->getStoreCartListByCartIds($this->cartIds,$this->memberId);
            $cartList = $storeCartList['cartList'];
            $tempStoreIds = array_keys($cartList);
            sort($tempStoreIds);
            sort($this->storeIds);
            if($tempStoreIds!=$this->storeIds){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongStoreIdsForOrder);
            }
            foreach($cartList as $key=>$storeCarts){
                $tempStoreCartIds = array_column($storeCarts['storeCarts'],'cart_id');
                sort($tempStoreCartIds);
                sort($this->storeCartIds[$key]);
                if($tempStoreCartIds!=$this->storeCartIds[$key]){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongCartStoreForOrder);
                }
            }
            $pBundlingService = \Business\Goods\GroupSaleServiceModel::getInstance();
            $cartList = $pBundlingService->getFormatCartListForOrder($storeCartList,$this->memberId,true,$dbName);
			$gcIds = isset($cartList['gcIds'])?$cartList['gcIds']:array();
			$storeCartData = array('cartList'=>$cartList['list'],'storeIds'=>array_keys($cartList['list']),'goodsIds'=>$storeCartList['goodsIds'],'goodsCommonIds'=>$storeCartList['goodsCommonIds'],'blIds'=>$storeCartList['blIds'],'gcIds'=>$gcIds);

        }
        if ($this->storeCouponIds&&$this->couponIds) {
            $storeCartData = $this->checkCouponForOrder($storeCartData, $this->memberId);
        }
        return $storeCartData;

    }

    public function checkOneStoreData($temp){
        if(!$this->address){
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::noAddressForOrder);
        }
        if(!$temp['storeId']){
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::emptyStoreIdForOrder);
        }

        if(!(isset($temp['payway']))&&in_array($temp['payway'],array(\Our\ApiConst::payOnline,\Our\ApiConst::payOffline,\Our\ApiConst::payAog))){//验证支付方式
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongPaywayForOrder);

        }
        if(!(isset($temp['deliveryType']))&&in_array($temp['deliveryType'],array(\Our\ApiConst::deliveryBuyer,\Our\ApiConst::deliveryStore,\Our\ApiConst::deliveryExpress))){
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongDeliveryTypeForOrder);
        }
        if($temp['deliveryType']== \Our\ApiConst::deliveryStore){//当配送方式为商家配送时
            if(!($temp['deliveryInterval']&&$temp['deliveryTime'])){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongTimeParamForStoreDelivery);
            }
        }
        if(!isset($temp['deliveryFee'])){
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::emptyDeliveryFeeForOrder);
        }
        if(isset($temp['couponId'])&&$temp['couponId']>\Our\ApiConst::zero){//商品如果有使用优惠券
            if(intval($temp['couponId'])<=\Our\ApiConst::zero){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongCouponIdForOrder);
            }else{
                $this->couponIds[] = $temp['couponId'];
                $this->storeCouponIds[$temp['storeId']] = $temp['couponId'];
            }
        }
    }

    /**
     * 配送方式只包含商家配送和自提的参数检验
     * @param $temp
     * @throws \Error\OurExceptionModel
     * @throws \Exception
     */
    public function checkOneStoreDataNew($temp){
        if($temp['deliveryType']==\Our\ApiConst::deliveryStore){
            if(!$this->address){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::noAddressForOrder);
            }
        }
        if(!$temp['storeId']){
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::emptyStoreIdForOrder);
        }

        if(!(isset($temp['payway']))&&in_array($temp['payway'],array(\Our\ApiConst::payOnline,\Our\ApiConst::payOffline,\Our\ApiConst::payAog))){//验证支付方式
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongPaywayForOrder);

        }
        if(!(isset($temp['deliveryType']))&&in_array($temp['deliveryType'],array(\Our\ApiConst::deliveryBuyer,\Our\ApiConst::deliveryStore))){
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongDeliveryTypeForOrder);
        }
        if(!($temp['deliveryTime'])){
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::emptyDeliveryTime);
        }
        $minute = intval(date('i',$temp['deliveryTime']));
        if(!($minute==0||$minute==30)){
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongDeliveryTime);
        }
        if($temp['deliveryType']==\Our\ApiConst::deliveryBuyer){
            if(!isset($temp['buyerMobile'])){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::emptyBuyerMobile);
            }
            if(!\Our\Common::checkMobilePhone($temp['buyerMobile'])){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongBuyerMobile);
            }
        }
        if(!isset($temp['deliveryFee'])){
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::emptyDeliveryFeeForOrder);
        }
        if(isset($temp['couponId'])&&$temp['couponId']>\Our\ApiConst::zero){//商品如果有使用优惠券
            if(intval($temp['couponId'])<=\Our\ApiConst::zero){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongCouponIdForOrder);
            }else{
                $this->couponIds[] = $temp['couponId'];
                $this->storeCouponIds[$temp['storeId']] = $temp['couponId'];
            }
        }
    }

    /**
     * 检查配送方式
     * @param $storeCartData
     * @return mixed
     */
    public function checkDeliveryTypeAndPayway($storeCartData){
        $cartService = \Business\Cart\CartServiceModel::getInstance();
        $storeCartData = $cartService->getDeliveryTypeForCart($this->address,$storeCartData);
        $currentTime = time();
        $todayTime = strtotime(date('Y-m-d',time()));
        $tomorrowTime = $todayTime + \Our\ApiConst::oneDaySecond;
        foreach($storeCartData['cartList'] as $storeId=>$tempStore){
            $temp = $tempStore['deliverySetting'];
            if(isset($this->postData['storeId'])&&$this->postData['storeId']){
                $requestData = $this->postData;
            }else{
                $requestData = $this->postFormatData[$storeId];
            }

            if($requestData['deliveryType'] == \Our\ApiConst::deliveryStore){//商家配送
                if($temp['sellerDistribution']!=\Our\ApiConst::one){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::noStoreDeliveryTypeForOrder);
                }
                if($requestData['deliveryTime']>=$todayTime&&$requestData['deliveryTime']<$tomorrowTime){
                    $tempList = $temp['deliverTimeList'];
                    $tempListStr = json_encode($tempList);
                    $newTempList= json_decode($tempListStr,true);
                    $intervalPrices = array_column($newTempList,'price','interval');
                    $deliveryFee = $intervalPrices[$requestData['deliveryInterval']];
                    $deliveryTime = $currentTime + $requestData['deliveryInterval'];
                }else if($requestData['deliveryTime']>=$tomorrowTime&&$requestData['deliveryTime']<($tomorrowTime+\Our\ApiConst::oneDaySecond)){
                    $tempList = $temp['deliverTimeList'];
                    $tempListStr = json_encode($tempList);
                    $newTempList= json_decode($tempListStr,true);
                    $tomorrowPrices = array_column($newTempList,'price','time');
                    $deliveryFee = $tomorrowPrices[$requestData['deliveryTime']];
                    $deliveryTime = $requestData['deliveryTime'];
                }else{
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongDeliveryTimeRangeForOrder);
                }
            }else if($requestData['deliveryType'] == \Our\ApiConst::deliveryBuyer){
                if($temp['buyerDistribution']!=\Our\ApiConst::one){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::noBuyerDeliveryTypeForOrder);
                }
                if($requestData['deliveryFee'] != \Our\ApiConst::zero){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::noDeliveryFeeForBuyerType);
                }
                $deliveryFee = \Our\ApiConst::zero;
            }else if($requestData['deliveryType'] == \Our\ApiConst::deliveryExpress){
                if($temp['expressDistribution']!=\Our\ApiConst::one){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::noExpressDeliveryForOrder);
                }
                if($tempStore['goodsFreight']==\Our\ApiConst::zero&&!($tempStore['is_transport']&&$tempStore['transport_id']>\Our\ApiConst::zero&&isset($temp['shippingFee']))){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::noExpressDeliveryForOrder1);
                }
                $deliveryFee = $temp['shippingFee'];
                $delivery['buyerMobile'] = $requestData['buyerMobile'];
            }

            if($deliveryFee!=$requestData['deliveryFee']){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongStoreDeliveryFeeForOrder);
            }
            $delivery['deliveryFee'] = $deliveryFee;
            $delivery['deliveryType'] = $requestData['deliveryType'];
            $delivery['deliveryTime'] = isset($deliveryTime)?$deliveryTime:\Our\ApiConst::zero;
            $storeCartData['cartList'][$storeId]['delivery'] = $delivery;
            if(($requestData['payway'] == \Our\ApiConst::payOnline&&$temp['onelinePay']==\Our\ApiConst::one)||
                ($requestData['payway'] == \Our\ApiConst::payOffline&&$temp['offlinePay']==\Our\ApiConst::one)||
                (($requestData['payway'] == \Our\ApiConst::payAog&&$temp['aogPay']==\Our\ApiConst::one))){
                $storeCartData['cartList'][$storeId]['payway'] = $requestData['payway'];
            }else{
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongPaywayForStoreForOrder);
            }
            $reliefAmount = isset($tempStore['reliefAmount'])?$tempStore['reliefAmount']:\Our\ApiConst::zero;
            $orderGoodsAmount = $tempStore['storeTotalPrice'] - $reliefAmount;
            if($orderGoodsAmount<=\Our\ApiConst::zero){
                $orderGoodsAmount = \Our\ApiConst::zero;
            }
            $orderAmount = $orderGoodsAmount + $deliveryFee ;
            if($orderAmount!=$requestData['totalFee']){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongTotalFeeForOrder);
            }
            $storeCartData['cartList'][$storeId]['orderAmount'] = $orderAmount;
        }
        return $storeCartData;
    }


    /**
     * 检查配送方式
     * @param $storeCartData
     * @return mixed
     */
    public function checkDeliveryTypeAndPaywayNew($storeCartData){
        $cartService = \Business\Cart\CartServiceModel::getInstance();
        $storeCartData = $cartService->getDeliveryTypeForCartNew($this->address,$storeCartData,\Our\DbNameConst::masterDBConnectName,true);
        $currentTime = time();
        $todayTime = strtotime(date('Y-m-d',time()));
        $tomorrowTime = $todayTime + \Our\ApiConst::oneDaySecond;

        foreach($storeCartData['cartList'] as $storeId=>$tempStore){
            $temp = $tempStore['deliverySetting'];
            if(isset($this->postData['storeId'])&&$this->postData['storeId']){
                $requestData = $this->postData;
            }else{
                $requestData = $this->postFormatData[$storeId];
            }
            $deliveryTime = $requestData['deliveryTime'];
            if($requestData['deliveryType'] == \Our\ApiConst::deliveryStore){//商家配送
                if($temp['sellerDistribution']!=\Our\ApiConst::one){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::noStoreDeliveryTypeForOrder);
                }
                if($temp['leftAmount']>0){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::leftAmountError);
                }
                if($requestData['deliveryTime']>=$todayTime&&$requestData['deliveryTime']<$todayTime*3){
                    $tempList = array_column($temp['deliverTimeList'],'list','time');
                    $currentDay= strtotime(date('Y-m-d',$requestData['deliveryTime']));
                    $currentList = $tempList[$currentDay];
                    $feeArray = array_column($currentList,'price','time');
                    $deliveryFee = $feeArray[$requestData['deliveryTime']];
                }else{
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongDeliveryTimeRangeForOrder);
                }
            }else if($requestData['deliveryType'] == \Our\ApiConst::deliveryBuyer){
                if($temp['buyerDistribution']!=\Our\ApiConst::one){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::noBuyerDeliveryTypeForOrder);
                }
                if($requestData['deliveryFee'] != \Our\ApiConst::zero){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::noDeliveryFeeForBuyerType);
                }
                if($requestData['deliveryTime']>=$todayTime&&$requestData['deliveryTime']<$todayTime*3){
                    $tempList = array($temp['selfDeliveryTimeList'],'list','time');
                    $currentDay= strtotime(date('Y-m-d',$requestData['deliveryTime']));
                    $currentList = $tempList[$currentDay];
                    $feeArray = array_column($currentList,'price','time');
                    $deliveryFee = $feeArray[$requestData['deliveryTime']];
                }else{
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongBuyerTimeRangeForOrder);
                }
                $deliveryFee = \Our\ApiConst::zero;
            }
            if($deliveryFee!=$requestData['deliveryFee']){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongStoreDeliveryFeeForOrder);
            }
            $delivery = array();
            $delivery['buyerMobile'] = isset($requestData['buyerMobile'])?$requestData['buyerMobile']:\Our\NameConst::emptyString;
            $delivery['deliveryFee'] = $deliveryFee;
            $delivery['deliveryType'] = $requestData['deliveryType'];
            $delivery['deliveryTime'] = isset($deliveryTime)?$deliveryTime:\Our\ApiConst::zero;
            $delivery['needShippingFee'] = isset($temp['other'])?$temp['other']:\Our\ApiConst::zero;
            $storeCartData['cartList'][$storeId]['delivery'] = $delivery;
            if(($requestData['payway'] == \Our\ApiConst::payOnline&&$temp['onelinePay']==\Our\ApiConst::one)||
                ($requestData['payway'] == \Our\ApiConst::payOffline&&$temp['offlinePay']==\Our\ApiConst::one)||
                (($requestData['payway'] == \Our\ApiConst::payAog&&$temp['aogPay']==\Our\ApiConst::one))){
                $storeCartData['cartList'][$storeId]['payway'] = $requestData['payway'];
            }else{
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongPaywayForStoreForOrder);
            }
            $reliefAmount = isset($tempStore['reliefAmount'])?$tempStore['reliefAmount']:\Our\ApiConst::zero;
            $orderGoodsAmount = $tempStore['storeTotalPrice'] - $reliefAmount;
            if($orderGoodsAmount<=\Our\ApiConst::zero){
                $orderGoodsAmount = \Our\ApiConst::zero;
            }
            $orderAmount = $orderGoodsAmount + $deliveryFee;
            if($orderAmount!=$requestData['totalFee']){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongTotalFeeForOrder);
            }
            $storeCartData['cartList'][$storeId]['orderAmount'] = $orderAmount;
        }
        return $storeCartData;
    }


    /**
     * 根据旧的paySn生成新的paySn
     * @param $paySn
     * @param $memberId
     */
    public function makeNewPaySnForOrderWithOldPaySn($paySn,$memberId){
        $dbName = \Our\DbNameConst::masterDBConnectName;
        $orderDao = \DAO\Order\OrderModel::getInstance($dbName);
        $newPaySn = $this->makePaySn($memberId);
        $orderDao->db->doTransaction();
        $orderPay['pay_sn'] = $newPaySn;
        $orderPay['buyer_id'] = $memberId;
        $orderPay['api_pay_state'] = \Our\ApiConst::zero;
        $orderPayModel = \DAO\Order\OrderPayModel::getInstance($dbName);
        $orderPayResult = $orderPayModel->insert($orderPay);
        if(!$orderPayResult){
            $orderDao->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::saveOrderPayFailed);
        }
        $orderUpdate['pay_sn']= $paySn;
        $orderUpdate['order_state'] = \Our\ApiConst::orderStateWaitPay;
        $orderResult = $orderDao->update($orderUpdate, array('pay_sn'=>$newPaySn));
        if(!$orderResult){
            $orderDao->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::orderUpdatePaySnFailed);
        }
        $orderIds = $orderDao->getListByCon($orderUpdate,'order_id');
        foreach($orderIds as $orderIdArr){
            $orderDao->deleteFindByOrderIdCache($orderIdArr['order_id']);
        }
        $orderDao->db->doCommit();
        return $newPaySn;
    }


    /**
     * 根据旧的paySn生成新的paySn
     * @param $paySn
     * @param $memberId
     */
    public function makeNewPaySnForOrderWithOrderId($orderId,$memberId){
        $dbName = \Our\DbNameConst::masterDBConnectName;
        $orderDao = \DAO\Order\OrderModel::getInstance();
        $orderDao->setDb($dbName);
        $orderDao->db->doTransaction();
        $paySn = $this->makePaySn($memberId);
        $orderPay['pay_sn'] = $paySn;
        $orderPay['buyer_id'] = $memberId;
        $orderPay['api_pay_state'] = \Our\ApiConst::zero;
        $orderPayModel = \DAO\Order\OrderPayModel::getInstance($dbName);
        $orderPayResult = $orderPayModel->insert($orderPay);
        if (!$orderPayResult) {
            $orderDao->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::newPaySnInsertFailed);
        }
        $orderResult = $orderDao->update(array('order_id' => $orderId), array('pay_sn' => $paySn));
        if (!$orderResult) {
            $orderDao->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::updateOrderForPayFailed);
        }
        $orderDao->deleteFindByOrderIdCache($orderId);
        $orderDao->db->doCommit();
        return $paySn;
    }

    public function saveOrderInfo($storeCartData, $formId = ''){
        $dbName = \Our\DbNameConst::masterDBConnectName;
        $orderModel  = \DAO\Order\OrderModel::getInstance($dbName);
        $orderModel->setDb($dbName);
        $memberCouponDao = \DAO\Coupon\MemberCouponModel::getInstance($dbName);
        $orderCommonDao = \DAO\Order\OrderCommonModel::getInstance($dbName);
        $orderGoodsDao = \DAO\Order\OrderGoodsModel::getInstance($dbName);
        $addressDao = \DAO\AddressModel::getInstance($dbName);
        $orderLogDao = \DAO\Order\OrderLogModel::getInstance($dbName);
        $orderModel->db->doTransaction();
        $paySn = $this->makePaySn($this->memberId);
        $orderPay['pay_sn'] = $paySn;
        $orderPay['buyer_id'] = $this->memberId;
        $orderPay['api_pay_state'] = \Our\ApiConst::zero;
        $orderPayModel = \DAO\Order\OrderPayModel::getInstance($dbName);
        $orderPayResult = $orderPayModel->insert($orderPay);
        if(!$orderPayResult){
            $orderModel->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::saveOrderPayFailed);
        }
        list($reciverInfo,$reciverName) = $this->getReciverAddr($this->address);
        $orderCommonList = array();
        $orderGoodsList = array();
        $orderLogList = array();
        $needPayFlag = \Our\ApiConst::zero;
        $giftCoupons = array();
        $this->pushMessageOrders = array();
        $storeDao = \DAO\StoreModel::getInstance(\Our\DbNameConst::masterDBConnectName);
        $goods_datas = array();    //商品列表
        foreach($storeCartData['cartList'] as $storeId=>$storeCarts){
            $order= array();
            $order['order_sn'] = $this->makeOrderSn($orderPayResult);
            $order['pay_sn'] = $paySn;
            $order['store_id'] = $storeId;
            $order['store_name'] = $storeCarts['storeName'];
            $order['buyer_id'] = $this->memberId;
            $order['buyer_name'] = addslashes($this->member['memberName']);
            if(CURRENTVERSION==\Our\NameConst::versionDefault){
                $order['buyer_email'] = $this->member['memberEmail'];
            }else{
                if($storeCarts['delivery']['deliveryType'] == \Our\ApiConst::deliveryBuyer){
                    $order['buyer_email'] = $storeCarts['delivery']['buyerMobile'];
                }else{
                    $order['buyer_email'] = $this->address['mob_phone'];
                }
            }
            $order['form_id'] = $formId;
            $order['add_time'] = TIMESTAMP;
            $order['payment_type'] = $storeCarts['payway'];
            $order['order_amount'] = $storeCarts['orderAmount'];
            $order['origin_amount'] = $storeCarts['orderAmount'];
            if($order['payment_type'] == 1 &&$storeCarts['orderAmount']>0){
                $needPayFlag = \Our\ApiConst::one;
                $order['order_state'] = \Our\ApiConst::orderStateWaitPay ;
            }else{
                $order['order_state'] = \Our\ApiConst::orderStateWaitConfirm;
            }
            $order['order_state'] = ($order['payment_type'] == 1 &&$storeCarts['orderAmount']>0) ? \Our\ApiConst::orderStateWaitPay : \Our\ApiConst::orderStateWaitConfirm;
            $logMsg = \Our\DescribeConst::addOrderLog;
            if($order['order_state'] == \Our\ApiConst::orderStateWaitConfirm){
                //$order['payment_time'] = TIMESTAMP;
                $logMsg = \Our\DescribeConst::addNoPayOrderLog;
            }
            $order['shipping_fee'] = $storeCarts['delivery']['deliveryFee'];
            $order['need_shipping_fee'] = isset($storeCarts['delivery']['needShippingFee'])?$storeCarts['delivery']['needShippingFee']:\Our\ApiConst::zero;
            $order['goods_amount'] = $storeCarts['storeTotalPrice'];
            $order['shipping_type'] = $storeCarts['delivery']['deliveryType'];
            if($storeCarts['delivery']['deliveryType'] == \Our\ApiConst::deliveryStore){
                $order['delivery_distance'] = $storeCarts['storeDistance'];
                $order['delivery_time'] = $storeCarts['delivery']['deliveryTime'];
            }else if($storeCarts['delivery']['deliveryType'] == \Our\ApiConst::deliveryBuyer){
                $order['delivery_time'] = $storeCarts['delivery']['deliveryTime'];
            }
            if(isset($storeCarts['couponId'])){
                $order['coupon_id'] = $storeCarts['couponId'];
                $refundCondition  = serialize(array('coupon'=>$storeCartData['newCouponList'][$storeCarts['couponId']],'storeCarts'=>$storeCarts));
                $order['refund_condition'] = $refundCondition;
            }

            $orderId = $orderModel->insert($order);
            if(!$orderId){
                $orderModel->db->doRollback();
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::saveOrderPayFailed);
            }
            if($order['order_state'] == \Our\ApiConst::orderStateWaitConfirm){
                $tempPushOrder = array();
                $tempPushOrder['orderId'] = $orderId;
                $tempPushOrder['orderSn'] = $order['order_sn'];
                $tempPushOrder['storeId'] = $storeId;
                $this->pushMessageOrders[] = $tempPushOrder;
            }
            $orderLog = array();
            $orderLog['order_id'] = $orderId;
            $orderLog['log_msg'] = \Our\DescribeConst::addOrderLog;
            $orderLog['log_time']  = TIMESTAMP;
            $orderLog['log_role'] = \Our\DescribeConst::buyer;
            $orderLog['log_user'] = addslashes($this->member['memberName']);
            $orderLog['log_msg'] = $logMsg;
            $orderLog['log_orderstate'] = $order['order_state'];
            $orderLogList[] = $orderLog;
            if(isset($storeCarts['couponId'])&&$storeCarts['couponId']){
                $updateCoupon = array();
                $updateCoupon['coupon_state'] = \Our\ApiConst::couponUsed;
                $updateCoupon['order_id'] = $orderId;
                $updateCoupon['user_time'] = TIMESTAMP;
                $memberCouponResult = $memberCouponDao->update($updateCoupon,array('coupon_id'=>$storeCarts['couponId'],'member_id'=>$this->memberId));
                if(!$memberCouponResult){
                    $orderModel->db->doRollback();
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::updateMemberCouponFailed);
                }
                if($storeCarts['giftCoupon']){
                    $giftCoupons[]=$storeCarts['giftCoupon'];
                }
                $this->couponCacheFlag = true;
            }
            $resultAddress = $addressDao->updateOrderAddress($this->address['address_id'],$this->memberId);
            if(!$resultAddress){
                $orderModel->db->doRollback();
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::updateAddressFailedForOrder);
            }
            $store = $storeDao->get($storeId,false);
            $orderCommon = array();
            $orderCommon['order_id'] = $orderId;
            $orderCommon['store_id'] = $storeId;
            $orderCommon['order_message'] = isset($this->storeMemos[$storeId])?$this->storeMemos[$storeId]:\Our\NameConst::emptyString;
            if($storeCarts['delivery']['deliveryType'] == \Our\ApiConst::deliveryBuyer){
                list($buyerStoreInfo,$buyerName) = $this->getStoreInfoAndBuyerInfo($store,array('buyerMobile'=>$storeCarts['delivery']['buyerMobile'],'member_name'=>$this->member['memberName']));
                $orderCommon['reciver_info'] = $buyerStoreInfo;
                $orderCommon['reciver_name'] = addslashes($buyerName);
            }else{
                $orderCommon['reciver_info'] = $reciverInfo;
                $orderCommon['reciver_name'] = addslashes($reciverName);
            }
            $orderCommon['reciver_city_id'] = ($storeCarts['delivery']['deliveryType'] == \Our\ApiConst::deliveryBuyer)?\Our\ApiConst::zero:$this->address['city_id'];
            $orderCommonList[] = $orderCommon;
            //$orderCommonDao->insert($orderCommon);
            foreach($storeCarts['storeCarts'] as $storeCart){
                $orderGoods = array();
                $orderGoods['order_id'] = $orderId;
                $orderGoods['goods_id'] = $storeCart['goodsId'];
                $orderGoods['goods_name'] = $storeCart['goodsName'];
                $goods_datas[] = $orderGoodsDao['goods_name'];
                $orderGoods['goods_num'] = $storeCart['goodsNum'];
                $orderGoods['goods_image'] = $storeCart['goodsImagePath'];
                $orderGoods['snapshot_id'] = (isset($storeCarts['snapshot_id'])&&$storeCarts['snapshot_id'])?$storeCarts['snapshot_id']:\our\ApiConst::zero;
                $orderGoods['goods_spec'] = $storeCart['goods_spec'];


                $orderGoods['store_id'] = $storeId;
                $orderGoods['buyer_id'] = $this->memberId;
                $orderGoods['gc_id'] = $storeCart['gc_id'];
                $orderGoods['gc_id_1'] = $storeCart['gcId'];
                $orderGoods['gc_id_2'] = $storeCart['gc_id_2'];
                $orderGoods['gc_id_3'] = $storeCart['gc_id_3'];
                $orderGoods['sale_act_id'] = $storeCart['sale_act_id'];
                $orderGoods['sale_id'] = $storeCart['sale_id'];

                if(isset($storeCart['goodsOriginalPrice'])&&$storeCart['goodsOriginalPrice']>\Our\ApiConst::zero){
                    $orderGoods['goods_price'] = $storeCart['goodsOriginalPrice'];
                }
                $orderGoods['goods_pay_price'] = $storeCart['goodsPrice'];
                if($storeCart['type']==\Our\ApiConst::addBundingToCart){
                    $orderGoods['goods_group'] = serialize($storeCart['goodsList']);
                    $orderGoods['goods_price'] = $storeCart['goodsPrice'];
                    $orderGoods['goods_commonid'] = \Our\ApiConst::zero;
                    $orderGoods['goods_spec'] = '';
                }else{
                    $orderGoods['goods_price'] = \Goods\GoodsUtil::getInstance()->getRealPrice($storeCart['goodsId'],$this->memberId);
                    $orderGoods['goods_commonid'] = $storeCart['goodsCommonId'];
                    if($orderGoods['sale_act_id']&&$orderGoods['sale_id']){//当前商品有参与销售活动结算时
                        $this->saleGoodsIds[] = $storeCart['goodsId'];
                    }
                    $orderGoods['goods_group'] = '';
                }

                $orderGoods['gmt_create'] = TIMESTAMP;
                $orderGoods['gmt_update'] = TIMESTAMP;

                $orderGoodsList[] = $orderGoods;
            }
        }
        $resultStorage = $this->updateGoodsStorage($storeCartData['cartList']);
        if(!$resultStorage){
            $orderModel->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::updateGoodsStorageForOrder);
        }
        if($giftCoupons&&count($giftCoupons)>\Our\ApiConst::zero){
            $couponService = \Business\Coupon\CouponServiceModel::getInstance();
            $couponResult = $couponService->receiveCouponBatch($giftCoupons,$this->memberId,$orderId);
            if(!$couponResult){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::receiveCouponFailedForOrder);
            }
        }
        $resultOrderCommon = $orderCommonDao->insertAll($orderCommonList);
        if(!$resultOrderCommon){
            $orderModel->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::saveOrderCommonFailed);
        }
        $resultOrderLog = $orderLogDao->insertAll($orderLogList);
        if(!$resultOrderLog){

            $orderModel->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::saveOrderCommonFailed);
        }
        $resultOrderGoods = $orderGoodsDao->insertAll($orderGoodsList);
        if(!$resultOrderGoods){
            $orderModel->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::saveOrderGoodsFailed);
        }
        $resultCart = $this->updateCart();
        if(!$resultCart){
            $orderModel->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::delCartFaileForAddOrder);
        }
        $resultFavoritesStore = $this->saveFavoritesStores();
        if(!$resultFavoritesStore){
            $orderModel->db->doRollback();
            \Error\ErrorModel::throwException(\Error\CodeConfigModel::failedUpdateFavoritesStoreForOrder);
        }
        $orderModel->db->doCommit();
        //订单通过小程序表单提交过来
        /*if($formId && ($access_token = $this->getLitAccesstoken())) {
            $settingDAO = \DAO\SettingModel::getInstance();
            $msg_tpl = $settingDAO->getListCache(array('wxapp_order_create_tpl'))['wxapp_order_create_tpl'];
            $goods_str = '';
            if(count($goods_datas)>1) {
                $goods_str .= $goods_datas[0].'等' .count($goods_datas).'个商品';
            } else {
                $goods_str .= $goods_datas[0];
            }
            $req_data = array('touser'=>$this->member['member_wxopenid'], 'template_id'=> $msg_tpl, 'form_id'=>$formId,
                'data'=>array(
                    array('keyword1'=>array('value'=>'下单成功')),
                    array('keyword2'=>array('value'=>$order['order_sn'])),
                    array('keyword3'=>array('value'=>number_format($order['order_amount']/100, 2)).'元'),
                    array('keyword4'=>array('value'=>$order['store_name'])),
                    array('keyword5'=>array('value'=>$goods_str)),
                ));
            $url = 'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=';
            $result = $this->sendurl($url, $access_token, $req_data, 'post');
        }*/
        $this->opCacheInfo();
        $this->pushMessage();
        return array('needPayFlag'=>$needPayFlag,'paySn'=>$paySn);
    }

    /**
     * 获取小程序表单
     * User: King <358887571@qq.com>
     * Date: 2018/12/27 0027
     * Time: 下午 3:15
     */
    private function getLitAccesstoken(){
        $model_wx  = \DAO\MbWxModel::getInstance();
        $weixin = $model_wx->getOne('id,lit_appid,lit_appsecret,lit_accesstoken,lit_expirestime', 'id=1');
        $access_token = '';
        if (!$weixin['lit_expirestime'] || $weixin['lit_expirestime'] < time()) {
            $access_info = json_decode(file_get_contents('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $weixin['lit_appid'] . '&secret=' . $weixin['lit_appsecret']), true);
            if (isset($access_info['access_token'])) {
                $access_token = $access_info['access_token'];

                $update_data = array();
                $update_data['lit_accesstoken'] = $access_info['access_token'];
                $update_data['lit_expirestime'] = TIMESTAMP + $access_info['expires_in'] - 1800;

                $where = array('id' => $weixin['id']);
                $result = $model_wx->update($update_data, $where);
            }
        } else {
            $access_token = $weixin['lit_accesstoken'];
        }
        return $access_token;
    }

    /**
     * curl请求
     * @param $url
     * @param $access_token
     * @param $data
     * @param $method
     */
    private function sendurl($url, $access_token = '', $data = '', $method = 'get', $header = '') {
        //
        if(strtolower($method)=='post') {
            $curl = curl_init();
            curl_setopt($curl,CURLOPT_URL,$url.$access_token);
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        } else {
            $curl = curl_init($url.$access_token);
        }

        if($header){
            //设置头部信息
            curl_setopt($curl,CURLOPT_HTTPHEADER,$header);
        }
        //$curl = curl_init($url.$access_token);
        curl_setopt($curl,CURLOPT_FAILONERROR,1);
        //设置允许页面重定向
        curl_setopt($curl,CURLOPT_FOLLOWLOCATION,1);
        //设置返回值赋给变量
        curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
        //设置操作时间
        curl_setopt($curl,CURLOPT_TIMEOUT,5);
        if($method=='post'){
            if(!$data) $data='';
            //			使用post 请求
            curl_setopt($curl,CURLOPT_POST,1);
            //			设置请求参数
            curl_setopt($curl,CURLOPT_POSTFIELDS,$data);
        }



        //开始事务
        $r = curl_exec($curl);
        curl_close($curl);
        return $r;
    }

    public function pushMessage(){
        if($this->pushMessageOrders){
            $orderService=\Business\Order\OrderServiceModel::getInstance();
            foreach($this->pushMessageOrders as $tempOrder){
                $orderService->pushRecieveOrder($tempOrder);
            }
        }
    }
    public function opCacheInfo(){
        if($this->cartCacheDeleteFlag){
            $this->delCartCache();
        }
        if($this->couponCacheFlag){
            $this->delCouponCahce();
        }
        $this->deleteCacheInfo();
        $this->pushSaleGoods();
    }

    public function delCouponCahce(){
        $memberCouponDao = \DAO\Coupon\MemberCouponModel::getInstance();
        $couponService  = \Business\Coupon\CouponServiceModel::getInstance();
        \Our\RedisHelper::delCachedFunction(\Redis\Db13\MemberCouponRedisModel::getInstance(),array(&$memberCouponDao, 'getList'),array(),array($this->memberId));
        foreach($this->storeIds as $tempStoreId){
            \Our\RedisHelper::delCachedFunction(\Redis\Db13\CouponRedisModel::getInstance(), array(&$couponService, 'getStoreCouponsById'),array(),array($tempStoreId."_".$this->memberId));
        }
    }

    public function delCartCache(){
        $cartRedis = \Redis\Db7\CartRedisModel::getInstance();
        $memberCartKey = \Our\NameConst::memberCartStorePrefix.$this->memberId;
        $cartRedis->tableDel($memberCartKey);
        foreach($this->storeIds as $tempStoreId){
            $memberStoreCartsKey = \Our\NameConst::memberStoreCartsPrefix.$this->memberId.\Our\NameConst::underline.$tempStoreId;
            $cartRedis->tableDel($memberStoreCartsKey);
        }
    }

    public function pushSaleGoods(){
        if($this->saleGoodsIds){
            $saleGoodsDao = \DAO\SaleGoodsModel::getInstance();
            foreach($this->saleGoodsIds as $tempGoodsId){
                $saleGoodsDao->addOrderGoodsList($tempGoodsId);
            }
        }
    }

    /**
     * 删除相关缓存信息
     */
    public function deleteCacheInfo($tempMemberId = null){
        if(!$tempMemberId){
            $tempMemberId = $this->memberId;
        }
        if(!$tempMemberId){
            return ;
        }
        //删除统计缓存
        $memberDao = \DAO\MemberModel::getInstance(\Our\DbNameConst::masterDBConnectName);
        $memberDao->deleteTotalCache($tempMemberId);
    }

    public function saveFavoritesStores(){
        $favoritesStoreDao = \DAO\FavoritesStoreModel::getInstance(\Our\DbNameConst::masterDBConnectName);
        $where['member_id'] = $this->memberId;
        $where['store_id'] = array('in',$this->storeIds);
        $list = $favoritesStoreDao->selectList($where,'store_id');
        if($list){
            $existStoreIds = array_column($list,'store_id');
            $leftStoreIds = array_diff($this->storeIds,$existStoreIds);
        }else{
            $leftStoreIds = $this->storeIds;
        }
        if($leftStoreIds){
            $insertFavoritesStores = array();
            $tempFav = array('fav_from'=>\Our\ApiConst::favFromBuy,'member_id'=>$this->memberId,'fav_time'=>TIMESTAMP);
            foreach($leftStoreIds as $storeId){
                $favoritesStore = $tempFav;
                $favoritesStore['store_id'] = $storeId;
                $insertFavoritesStores[] = $favoritesStore;
            }
            $insertBatchResult = $favoritesStoreDao->insertBatch($insertFavoritesStores);
            return $insertBatchResult;
        }
        return true;
    }

    public function updateCart(){
        if($this->cartIds&&count($this->cartIds)>\Our\ApiConst::zero){ //从购物车下单才需要删除购物车
            $cartDao = \DAO\Cart\CartModel::getInstance(\Our\DbNameConst::masterDBConnectName);
            $sql = \Our\Common::format(' cart_id in ({0})',implode(',',$this->cartIds));
            $resultCart = $cartDao->del($sql);
            if($resultCart){
                foreach($this->storeIds as $tempStoreId){
                    $memberStoreCartsKey = \Our\NameConst::memberStoreCartsPrefix.$this->memberId.\Our\NameConst::underline.$tempStoreId;
                    $cartRedis = \Redis\Db7\CartRedisModel::getInstance();
                    $cartRedis->tableDel($memberStoreCartsKey);
                }
            }
            return $resultCart;
        }
        return true;
    }

    /**
     * 更新商品对应库存(更新数据库库存同时更新redis缓存)
     *  updateSaleNumFlag 是否需要增减销量
     * @param $storeCarts
     */
    public function  updateGoodsStorage($storeCartsList,$op = \Our\ApiConst::minus,$updateSaleNumFlag= true ){
        $goodsCommonIds = array();
        $goodsIds = array();
        $blIds = array();
        $goodsNewList = array();
        $pbundlingInstance = \DAO\PBundlingModel::getInstance();
        foreach($storeCartsList as $storeId=>$storeCarts){
            $blUpdateFlag = false;
            foreach($storeCarts['storeCarts'] as $storeCart){
                if($storeCart['type']==\Our\ApiConst::addGoodsToCart){
                    if(isset($goodsCommonIds[$storeCart['goodsCommonId']]['goodsCommonId'])){
                        $goodsCommonIds[$storeCart['goodsCommonId']]['goodsNum'] += $storeCart['goodsNum'];
                    }else{
                        $goodsCommonIds[$storeCart['goodsCommonId']]['goodsCommonId'] = $storeCart['goodsCommonId'];
                        $goodsCommonIds[$storeCart['goodsCommonId']]['goodsNum'] = $storeCart['goodsNum'];
                    }
                    if(isset($goodsIds[$storeCart['goodsCommonId']][$storeCart['goodsId']]['goodsId'])){
                        $goodsIds[$storeCart['goodsCommonId']][$storeCart['goodsId']]['goodsNum'] += $storeCart['goodsNum'];
                        $goodsIds[$storeCart['goodsCommonId']][$storeCart['goodsId']]['goodsNum'] += $storeCart['goodsNum'];
                    }else{
                        $goodsIds[$storeCart['goodsCommonId']][$storeCart['goodsId']]['goodsId'] = $storeCart['goodsId'];
                        $goodsIds[$storeCart['goodsCommonId']][$storeCart['goodsId']]['goodsNum'] = $storeCart['goodsNum'];
                    }
                    $goodsNewList[$storeCart['goodsId']] = $goodsIds[$storeCart['goodsCommonId']][$storeCart['goodsId']];
                }else if($storeCart['type'] == \Our\ApiConst::addBundingToCart){
                    $blIds[$storeCart['goodsId']]['blId'] = $storeCart['goodsId'];
                    $blIds[$storeCart['goodsId']]['blStorage'] = $storeCart['goodsNum'];
                    $goodsList = $storeCart['goodsList'];
                    $blUpdateFlag = true;
                    foreach ($goodsList as $item) {
                        //$goodsCommonIds[] = $item['goodsCommonId'];
                        //$goodsIds[$storeCart['goodsCommonId']][] = $item['goodsId'];
                        if(isset($goodsCommonIds[$item['goodsCommonId']]['goodsCommonId'])){
                            $goodsCommonIds[$item['goodsCommonId']]['goodsNum'] += $item['num']*$storeCart['goodsNum'];
                        }else{
                            $goodsCommonIds[$item['goodsCommonId']]['goodsCommonId'] = $item['goodsCommonId'];
                            $goodsCommonIds[$item['goodsCommonId']]['goodsNum'] = $item['num']*$storeCart['goodsNum'];
                        }
                        if(isset($goodsIds[$item['goodsCommonId']][$item['goodsId']]['goodsId'])){
                            $goodsIds[$item['goodsCommonId']][$item['goodsId']]['goodsNum'] += $item['num']*$storeCart['goodsNum'];
                        }else{
                            $goodsIds[$item['goodsCommonId']][$item['goodsId']]['goodsId'] = $item['goodsId'];
                            $goodsIds[$item['goodsCommonId']][$item['goodsId']]['goodsNum'] =  $item['num']*$storeCart['goodsNum'];
                        }
                        $goodsNewList[$item['goodsId']] = $goodsIds[$item['goodsCommonId']][$item['goodsId']];
                    }
                    \Our\RedisHelper::delCachedFunction(\Redis\Db4\PBundlingRedisModel::getInstance(),array(&$pbundlingInstance, 'getList'),array(),array('*'.$storeCart['goodsId'].'*'));
                }
            }
            if($updateSaleNumFlag){
                $storeTopSaleGoodsDao = \DAO\Goods\StoreTopSaleGoodsModel::getInstance();
                $storeTopSaleGoodsDao->pushChangeSaleStore($storeId);
            }
            //删除购物车缓存

            $cartRedis = \Redis\Db7\CartRedisModel::getInstance();
            $memberCartKey = \Our\NameConst::memberStoreCartsPrefix.'*_'.$storeId;
            $cartRedis->tableDelAll($cartRedis->tableKeys($memberCartKey));
            if($blUpdateFlag){
                \Our\RedisHelper::delCachedFunction(\Redis\Db4\PBundlingRedisModel::getInstance(),array(&$pbundlingInstance, 'getList'),array(),array($storeId));
            }
        }
        $this->updateGoodsStorageToDBAndCache($goodsCommonIds,$goodsIds,$blIds,$goodsNewList,$op,$updateSaleNumFlag);
        return true;
    }

    /**
     * @param $goodsCommons
     * @param $goodsList
     * @param $blGoodsList
     * @param $goodsNewList
     * @param int $op
     * @param bool $updateSaleNumFlag
     * @return bool
     * @throws \Error\OurExceptionModel
     * @throws \Exception
     */
    public function updateGoodsStorageToDBAndCache($goodsCommons,$goodsList,$blGoodsList,$goodsNewList,$op=\Our\ApiConst::minus,$updateSaleNumFlag=true){
        if($blGoodsList){
            $dbName = \Our\DbNameConst::masterDBConnectName;
            $pBundlingDao = \DAO\PBundlingModel::getInstance($dbName);
            $pBundlingResult = $pBundlingDao->updateBlStorage($blGoodsList);
            if(!$pBundlingResult){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::blGoodsStorageToDBFailedForOrder);
            }
        }
        if($goodsCommons&&$goodsList){
            $dbName = \Our\DbNameConst::masterDBConnectName;
            $goodsDao = \DAO\GoodsModel::getInstance($dbName);
            $goodsCommonDao = \DAO\GoodsCommonModel::getInstance($dbName);
            $resultGoodsCommon = $goodsCommonDao->updateGoodsStorage($goodsCommons,$op,$updateSaleNumFlag);

            $resultGoods = $goodsDao->updateGoodsStorage($goodsNewList,$op);

            if(!($resultGoodsCommon&&$resultGoods)){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::goodsStorageToDBFailedForOrder);
            }
        }

        if($blGoodsList){
            foreach($blGoodsList as $key=>$blGoods){
                $pBundlingCacheResult = $pBundlingDao->opBlGoodsStorage($key,$blGoods['blStorage']);//组合销售库存删减
                if($pBundlingCacheResult===false){
                    \Error\ErrorModel::throwException(\Error\CodeConfigModel::blGoodsStorageToCacheFailedForOrder);
                }
            }
        }
        if($goodsCommons&&$goodsList){
            $resultGoodsCache = $goodsDao->opOnlineStorageGoodsByGoodsCommonIds($goodsList,$op,$updateSaleNumFlag);
            if(!$resultGoodsCache){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::goodsStorageToCacheFailedForOrder);
            }
        }
        return true;
    }
    /**
     * 生成支付单编号(两位随机 + 从2000-01-01 00:00:00 到现在的秒数+微秒+会员ID%1000)，该值会传给第三方支付接口
     * 长度 =2位 + 10位 + 3位 + 3位  = 18位
     * 1000个会员同一微秒提订单，重复机率为1/100
     * @return string
     */
    public function makePaySn($member_id) {
        return mt_rand(10,99)
        . sprintf('%010d',time() - 946656000)
        . sprintf('%03d', (float) microtime() * 1000)
        . sprintf('%03d', (int) $member_id % 1000);
    }

    /**
     * 订单编号生成规则，n(n>=1)个订单表对应一个支付表，
     * 生成订单编号(年取1位 + $pay_id取13位 + 第N个子订单取2位)
     * 1000个会员同一微秒提订单，重复机率为1/100
     * @param $pay_id 支付表自增ID
     * @return string
     */
    public function makeOrderSn($pay_id) {
        //记录生成子订单的个数，如果生成多个子订单，该值会累加
        static $num;
        $num = rand(0,99);
        return (date('y',time()) % 9+1) . sprintf('%013d', $pay_id) . sprintf('%02d', $num);
    }

    /**
     * 检查优惠券是否可用
     * @param $storeCartData
     * @param $memberId
     * @return mixed
     */
    public function checkCouponForOrder($storeCartData,$memberId){
        $goodsIds = $storeCartData['goodsIds'];
        $goodsCommonIds = $storeCartData['goodsCommonIds'];
        $gcIds = $storeCartData['gcIds'];
        if(!($goodsIds&&$goodsCommonIds&&$gcIds)){ //如果当前没有goodsIds 和 goodsCommonIds传进来表示当前商品列表没有优惠券可用
            $storeCartData['couponList'] = array();
            return $storeCartData;
        }

        //第一步:获取购物车可展示优惠券信息
        $memberCouponDao = \DAO\Coupon\MemberCouponModel::getInstance(\Our\DbNameConst::masterDBConnectName);
        $whereSql = ' coupon_state ='.\Our\ApiConst::couponUnused.' and member_id ='.$memberId.' and out_time > '.time();
        $memberCouponArray = $memberCouponDao->getList($whereSql,'coupon_id');
        if(!$memberCouponArray){
            $storeCartData['couponList'] = array();
            return $storeCartData;
        }
        $couponStoreIds   = $storeCartData['storeIds'];
        $couponStoreIds[] = \Our\ApiConst::zero;
        $couponIds = array_column($memberCouponArray,'coupon_id');
        $couponSql = \Our\Common::format(' id in ({0}) and store_id in({1})',implode(',',$couponIds),implode(',',$couponStoreIds));
        $couponDao = \DAO\Coupon\CouponModel::getInstance(\Our\DbNameConst::masterDBConnectName);
        $couponList = $couponDao->getCartCouponTitles($couponSql);
        if(!$couponList){
            $storeCartData['couponList'] = array();
            return $storeCartData;
        }
        $storeCouponList = array();
        $newCouponList = array();
        $giftCouponIds = array();
        foreach($couponList as $temp){
            $storeCouponList[$temp['store_id']][] = $temp;
            $temp['order_amount'] = $temp['order_amount']*\Our\ApiConst::hundred;
            $temp['cash_money'] = $temp['cash_money']*\Our\ApiConst::hundred;
            $newCouponList[$temp['couponId']] = $temp;
            if($temp['coupon_type']==\Our\ApiConst::fullForCouponCouponType&&$temp['gift_coupon_id']>\Our\ApiConst::zero){
                $giftCouponIds[$temp['couponId']] = $temp['gift_coupon_id'];
            }
        }
        if($giftCouponIds){
            $giftCouponCon = ' and id in ('.implode(',',array_values($giftCouponIds)).')';
            $giftCoupons = $couponDao->getOnlineCouponList($giftCouponCon,\Our\NameConst::allField,false);//赠券前台不展示,仅用于赠送
            if($giftCouponIds&&$giftCoupons){
                $giftCouponsWithKey = array();
                foreach($giftCoupons as $coupon){
                    $giftCouponsWithKey[$coupon['id']] = $coupon;
                }
                foreach($giftCouponIds as $key=>$giftCouponId){
                    if($giftCouponsWithKey[$giftCouponId]){
                        $giftCouponList[$key] = $giftCouponsWithKey[$giftCouponId];
                    }
                }
            }
        }
        $storeCartData['newCouponList'] = $newCouponList;
        $platformCouponList = isset($storeCouponList[\Our\ApiConst::zero])?$storeCouponList[\Our\ApiConst::zero]:array();//平台优惠券列表
        $cartService = \Business\Cart\CartServiceModel::getInstance();
        foreach($storeCartData['cartList']  as $key=>&$tempStoreCarts){
            if(!$this->storeCouponIds[$key]){//当前店铺没有使用优惠券
                $storeCartData['cartList'][$key]['couponId'] = \Our\ApiConst::zero;
                $storeCartData['cartList'][$key]['reliefAmount'] = \Our\ApiConst::zero;
                continue;
            }
            if($platformCouponList){
                $tempStoreCarts = $cartService->calcCouponMoney($platformCouponList,$tempStoreCarts);
            }
            if(isset($storeCouponList[$key])){
                $tempStoreCarts =  $cartService->calcCouponMoney($storeCouponList[$key],$tempStoreCarts);
            }
            $coupons = $tempStoreCarts['coupons'];
            if(!$coupons){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::wrongCouponForStoreOrder);
            }
            $couponAmount = array_column($coupons, 'reliefAmount', 'couponId');
            $storeCartData['cartList'][$key]['couponId'] = $this->storeCouponIds[$key];
            $storeCartData['cartList'][$key]['reliefAmount'] = $couponAmount[$this->storeCouponIds[$key]];
            if($giftCouponList[$this->storeCouponIds[$key]]){
                $storeCartData['cartList'][$key]['giftCoupon'] = $giftCouponList[$this->storeCouponIds[$key]];
            }
        }
        return $storeCartData;

    }

    public function getStoreInfoAndBuyerInfo($store,$data){
        $reciverInfo['phone'] = $data['buyerMobile'];
        $reciverInfo['mob_phone'] = $data['buyerMobile'];
        $reciverInfo['tel_phone'] = $data['buyerMobile'];
        $reciverInfo['address'] = $store['store_address'];
        $reciverInfo['name'] = $data['member_name'];
        $reciverInfo['area'] = $store['area_info'];
        $reciverInfo['street'] = $store['store_address'];
        $reciverInfo['lng'] = $store['store_longitude'];
        $reciverInfo['lat'] = $store['store_latitude'];
        $reciverInfo['citycode'] = $store['store_citycode'];
        $reciverInfo['address_id'] = \Our\NameConst::emptyString;
        $reciverInfo['subaddress'] = $store['store_subaddress'];
        $reciverInfo = serialize($reciverInfo);
        $reciverName = $data['member_name'];
        return array($reciverInfo, $reciverName);
    }

    public function getReciverAddr($addressInfo = array()) {
        /*if (intval($addressInfo['dlyp_id'])) {
            $reciverInfo['phone'] = trim($addressInfo['dlyp_mobile'].($addressInfo['dlyp_telephony'] ? ','.$addressInfo['dlyp_telephony'] : null),',');
            $reciverInfo['tel_phone'] = $addressInfo['dlyp_telephony'];
            $reciverInfo['mob_phone'] = $addressInfo['dlyp_mobile'];
            $reciverInfo['address'] = $addressInfo['dlyp_area_info'].' '.$addressInfo['dlyp_address'];
            $reciverInfo['area'] = $addressInfo['dlyp_area_info'];
            $reciverInfo['street'] = $addressInfo['dlyp_address'];
            $reciverInfo['dlyp'] = 1;
            $reciverInfo = serialize($reciverInfo);
            $reciverName = $addressInfo['dlyp_address_name'];
        } else {
        }*/
        $reciverInfo['phone'] = trim($addressInfo['mob_phone'].($addressInfo['tel_phone'] ? ','.$addressInfo['tel_phone'] : null),',');
        $reciverInfo['mob_phone'] = $addressInfo['mob_phone'];
        $reciverInfo['tel_phone'] = $addressInfo['tel_phone'];
        $reciverInfo['address'] = $addressInfo['area_info'].' '.$addressInfo['address'];
        $reciverInfo['name'] = $addressInfo['true_name'];
        $reciverInfo['area'] = $addressInfo['area_info'];
        $reciverInfo['street'] = $addressInfo['address'];
        $reciverInfo['lng'] = $addressInfo['lng'];
        $reciverInfo['lat'] = $addressInfo['lat'];
        $reciverInfo['citycode'] = $addressInfo['citycode'];
        $reciverInfo['address_id'] = $addressInfo['address_id'];
        $reciverInfo['subaddress'] = $addressInfo['subaddress'];
        $reciverInfo = serialize($reciverInfo);
        $reciverName = $addressInfo['true_name'];
        return array($reciverInfo, $reciverName);
    }

    public function checkCurrentAddress($currentAddress,$memberId){
        $addressId = $currentAddress['addressId'];
        if($addressId>\Our\ApiConst::zero){
            $addressDao = \DAO\AddressModel::getInstance();
            $columns = $addressDao->getAddressColumns();
            $condition['address_id'] = $addressId;
            $address = \Our\RedisHelper::cachedFunction(\Redis\Db8\AddressRedisModel::getInstance(),array(&$addressDao, 'findByWhereWithColumns'),array($condition,$columns),3600,array($addressId));
            if(!$address||($address&&$address['member_id']!=$memberId)){
                \Error\ErrorModel::throwException(\Error\CodeConfigModel::addressNotExist);
            }
            return $address;
        }
        return false;
    }

    /**
     * 根据支付回调 确认order表payment_type的类型
     * @param $payType
     * @return int
     */
    public function getOrderPaymentType($payType){
        $orderPaymentType = \Our\ApiConst::wxpay;
        switch ($payType)
        {
            case \Our\ApiConst::wxAppPayType:
                $orderPaymentType = \Our\ApiConst::wxpay;
                break;
            case \Our\ApiConst::aliPayType:
                $orderPaymentType = \Our\ApiConst::alipay;
                break;
            case \Our\ApiConst::qqPayType:
                $orderPaymentType = \Our\ApiConst::tenpay;
                break;
            case \Our\ApiConst::wxLitePayType:
                $orderPaymentType = \Our\ApiConst::wxProgram;
                break;
        }
        return $orderPaymentType;
    }

    public function updateOrderToPayed($data){
        $errorCode = \Our\ApiConst::zero;
        $dbName = \Our\DbNameConst::masterDBConnectName;
        $orderModel  = \DAO\Order\OrderModel::getInstance($dbName);
        $orderModel->setDb($dbName);
        $orderPayModel = \DAO\Order\OrderPayModel::getInstance($dbName);
        $orderModel->db->doTransaction();
        $paySn = $data['paySn'];
		if(!$paySn){
            $errorCode = \Error\CodeConfigModel::emptyPaySnForOrder;
            return array('flag'=>\Our\ApiConst::zero,'errorCode'=>$errorCode,'data'=>$data);
        }
		$oldOrderPay = $orderPayModel->find(array('pay_sn'=>$paySn));
		if($oldOrderPay['api_pay_state']==\Our\ApiConst::one){
			return array('flag'=>\Our\ApiConst::one,'errorCode'=>$errorCode);
		}
        $resultOrderPay = $orderPayModel->update(array('api_pay_state'=>\Our\ApiConst::one,'pay_type'=>$data['pay_type']),array('pay_sn'=>$paySn));
        if(!$resultOrderPay){
            $orderModel->db->doRollback();
            $errorCode = \Error\CodeConfigModel::wrongPaySnForOrder;
            return array('flag'=>\Our\ApiConst::zero,'errorCode'=>$errorCode,'data'=>$data);
        }else{
            $orderPayRedis = \Redis\Db5\OrderPayRedisModel::getInstance();
            $orderPayRedis->tableDel($paySn);
        }

        $orderCon = array('pay_sn'=>$paySn,'order_state'=>array('in',array(\Our\ApiConst::orderStateWaitPay,ApiConst::orderStateCancel)));
        $orderList = $orderModel->getListByCon($orderCon,'order_id,coupon_id,buyer_id,store_id,order_sn');
        if(!$orderList){
            $errorCode = \Error\CodeConfigModel::noOrderListForPay;
            return array('flag'=>\Our\ApiConst::zero,'errorCode'=>$errorCode,'data'=>$data);
        }
        $memberId = $orderList[0]['buyer_id'];
        $updateOrder = array();
        $updateOrder['order_state'] = \Our\ApiConst::orderStateWaitConfirm;
        $updateOrder['is_receive_payment'] = TIMESTAMP;
        $updateOrder['payment_time'] = (isset($data['payment_time'])? strtotime($data['payment_time']) : TIMESTAMP);
        $updateOrder['finnshed_time'] = \Our\ApiConst::zero;
        $updateOrder['payment_type'] = $this->getOrderPaymentType($data['pay_type']);
        $orderUpdateResult = $orderModel->update($orderCon,$updateOrder);
        if(!$orderUpdateResult){
            $orderModel->db->doRollback();
            $errorCode = \Error\CodeConfigModel::updateOrderPayedStatusFailed;
            return array('flag'=>\Our\ApiConst::zero,'errorCode'=>$errorCode,'data'=>$data);

        }
        //更新订单支付状态
        $couponIds = array();
        $this->pushMessageOrders = array();
        foreach($orderList as $tempOrder){
            if($tempOrder['coupon_id']>\Our\ApiConst::zero){
                $couponIds[$tempOrder['order_id']] = $tempOrder['coupon_id'];
            }
            $orderModel->deleteOrderCache($tempOrder['buyer_id'],$tempOrder['order_id'],$tempOrder['store_id'],true,true);
            \Our\RedisHelper::memberTotalFromStateToState($tempOrder['buyer_id'],ApiConst::orderStateWaitPay,ApiConst::orderStateWaitConfirm);
            $tempPushOrder = array();
            $tempPushOrder['orderId'] = $tempOrder['order_id'];
            $tempPushOrder['orderSn'] = $tempOrder['order_sn'];
            $tempPushOrder['storeId'] = $tempOrder['store_id'];
            $this->pushMessageOrders[] = $tempPushOrder;
        }
        //送券、送礼品
        /*if($couponIds){

        }*/

        $orderModel->db->doCommit();
        $this->deleteCacheInfo($memberId);
        $this->pushMessage();
        return array('flag'=>\Our\ApiConst::one,'errorCode'=>$errorCode);
    }


    /**
     * 计算订单商品总金额
     * @param $coupon
     * @param $storeCarts
     * @return int
     */
    public function  reCalcOrderAmount($coupon,$storeCarts){
        $cartService = \Business\Cart\CartServiceModel::getInstance();
        $storeGoodsList = array();
        $totalPrice = \Our\ApiConst::zero;
        $storeCouponPrice = \Our\ApiConst::zero;
        if($storeCarts&&count($storeCarts)){
            foreach($storeCarts as $goods){
                $totalPrice += $goods['goodsPrice'];
                if ($goods['type'] == \Our\ApiConst::addGoodsToCart) {
                    if(isset($storeGoodsCommonCouponPriceArray[$goods['goodsCommonId']]['totalPrice'])){
                        $storeGoodsCommonCouponPriceArray[$goods['goodsCommonId']]['totalPrice'] += $goods['goodsPrice'];
                    }else{
                        $storeGoodsCommonCouponPriceArray[$goods['goodsCommonId']]['totalPrice'] = $goods['goodsPrice'];
                    }
                    if(isset($storeGcCouponPriceArray[$goods['gcId']]['totalPrice'])){
                        $storeGcCouponPriceArray[$goods['gcId']]['totalPrice'] += $goods['goodsPrice']*$goods['goodsNum'];
                    }else{
                        $storeGcCouponPriceArray[$goods['gcId']]['totalPrice'] = $goods['goodsPrice']*$goods['goodsNum'];
                    }

                    $storeCouponPrice += $goods['goodsPrice']*$goods['goodsNum'];
                }
            }
        }
        $storeGoodsList['gcPrices'] = isset($storeGcCouponPriceArray)?$storeGcCouponPriceArray:array();
        $storeGoodsList['goodsCommonPrices'] = $storeGoodsCommonCouponPriceArray;
        $storeGoodsList['storeCouponPrice'] = $storeCouponPrice;
        $reliefAmount = $cartService->getOneCouponReliefAmount($coupon,$storeGoodsList);
        if($reliefAmount&&$reliefAmount>\Our\ApiConst::zero){
            $totalPrice = ($reliefAmount > $totalPrice)? 0 : ($totalPrice-$reliefAmount);
        }
        return $totalPrice;
    }

    /**
     * 类实例
     *
     */
    private static $_instance = null;

    /**
     * 单例模式获取类实例
     *
     */
    public static function getInstance()
    {
        if (!(self::$_instance instanceof self)) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }
}
