<?php


namespace JinDouYun\Model\Order;


use JinDouYun\Cache\Stock;
use JinDouYun\Controller\Common\Logger;
use JinDouYun\Dao\Order\DSupplierOrderDetails;
use JinDouYun\Dao\Order\DSupplierOrderIndex;
use JinDouYun\Model\Cart\MCart;
use JinDouYun\Model\Customer\MCustomer;
use JinDouYun\Model\Customer\MShippingAddress;
use JinDouYun\Model\Finance\MCustomerBalance;
use JinDouYun\Model\Goods\MGoods;
use JinDouYun\Model\Market\MComBinPackage;
use JinDouYun\Model\Market\MUserCoupon;
use JinDouYun\Model\Purchase\MPurchase;
use JinDouYun\Model\Purchase\MSupplier;
use JinDouYun\Model\Stock\MInventory;
use JinDouYun\Model\Stock\MInventoryOut;
use JinDouYun\Model\Stock\MReservoirArea;
use JinDouYun\Model\System\MBasicSetup;
use JinDouYun\Model\System\MDeliverySetting;
use Mall\Framework\Core\ErrorCode;
use Mall\Framework\Core\ResultWrapper;
use Mall\Framework\Core\StatusCode;
use phpDocumentor\Reflection\Types\Self_;

trait TStdOrder
{

    private $supplierIds = [];

    /**
     * @var bool 是否开启供应商
     */
    private $isEnableSupplier = false;


    /**
     * Doc: (des="将商品数据按照指定的字段分组")
     * User: XMing
     * Date: 2020/12/15
     * Time: 4:52 下午
     * @param array $lists 商品数据
     * @param array $common 公共参数
     * @param array $shopMap 店铺对应仓库数据
     * @return ResultWrapper
     * @throws \Exception
     */
    public function groupSupplierOrderData(array $lists, array $common, array $shopMap): ResultWrapper
    {
        if (empty($lists)) {
            return ResultWrapper::success([]);
        }
        $this->isEnableSupplier = self::getIsEnableSupplier();
        //店铺商品数据
        $buildResult = self::buildOrderShopData($lists, $common, $shopMap);
        if (!$buildResult->isSuccess()) {
            return ResultWrapper::fail($buildResult->getData(), $buildResult->getErrorCode());
        }
        $build = $buildResult->getData();
        return ResultWrapper::success($build);
    }

    /**
     * Doc: (des="")
     * User: XMing
     * Date: 2020/12/18
     * Time: 12:17 下午
     * @param array $shopData 店铺商品数据
     * @param array $params 公共数据
     * @param array $shopMap
     * @return ResultWrapper
     * @throws \Exception
     */
    public function buildOrderShopData(array $shopData, array $params, array $shopMap): ResultWrapper
    {
        $params['createTime'] = time();
        $params['updateTime'] = time();
        $objStockCache = new Stock($this->onlineEnterpriseId);
        $orderIndex = [];
        $order = [];
        $orderReceive = [];
        $orderGoods = [];
        $lockInventoryData = [];
        $activityData = [];
        $goodsSaleData = [];
        $cartIds = [];
        $orderSn = [];
        $supplierIndex = [];
        $supplierDetails = [];

        $useCoupon = getArrayItem($params, 'useCoupon', []);
        $useCouponId = getArrayItem($useCoupon, 'id', 0);
        $proporties = getArrayItem($params,'proporties',[]);
        $version = getArrayItem($params,'version',0);
        foreach ($shopData as $key => &$val) {
            $serialNum = $objStockCache->createSerialSn(0, 'Order');
            $sn = $serialNum;
            $verifyCode = self::createVerifyCode(substr($serialNum, -3));
            $orderSn[] = $sn;
            //将数据写入索引表
            if ($params['orderType'] == StatusCode::$orderType['saleOrder']){
                $preferential = floatval(array_sum(array_column($val['shopGoodsData'],'preferential')));//优惠券优惠
                if ($params['source'] == StatusCode::$source['manage']){
                    $preferential = bcadd($preferential,isset($val['preferential']) ? $val['preferential'] : 0);
                }
                $vipDiscount = floatval(array_sum(array_column($val['shopGoodsData'],'vipDiscount')));//会员卡优惠
                $buyTotal = floatval(array_sum(array_column($val['shopGoodsData'],'buyNum')));
                $val['preferential'] = $preferential;
                $val['vipDiscount'] = $vipDiscount;
                $val['payMoney'] = bcadd($val['expressMoney'],bcsub($val['totalMoney'],bcadd($preferential,$vipDiscount),2),2);
                $val['buyTotal'] = $buyTotal;
            }

            if ($version == 1){
                //为了兼容xhjc
                $thisProporties = getArrayItem($proporties,$val['shopId'],[]);
                if (empty($thisProporties)){
                    return ResultWrapper::fail('proporties异常',ErrorCode::$paramError);
                }
                $deliveryType = getArrayItem($thisProporties,'deliveryType',StatusCode::$deliveryType['selfMention']);
                $selfRuleId = getArrayItem($thisProporties,'selfRuleId',0);
                $selfRuleData = getArrayItem($thisProporties,'selfRuleData',null);
                $addressData = getArrayItem($thisProporties,'addressData',[]);
            }else{
                $deliveryType = getArrayItem($params, 'deliveryType', StatusCode::$deliveryType['selfMention']);
                $selfRuleId = getArrayItem($params, 'selfRuleId', 0);
                $selfRuleData = getArrayItem($params, 'selfRuleData', null);
                $addressData = getArrayItem($params, 'addressData', []);
            }


            $orderIndex[] = [
                'shopId'       => getArrayItem($val, 'shopId', 0),
                'userCenterId' => getArrayItem($params, 'userCenterId', 0),
                'salesManId'   => getArrayItem($params, 'salesManId', 0),
                'createTime'   => getArrayItem($params, 'createTime', time()),
                'updateTime'   => getArrayItem($params, 'updateTime', time()),
                'deleteStatus' => getArrayItem($params, 'deleteStatus', StatusCode::$standard),
                'auditStatus'  => getArrayItem($params, 'auditStatus', StatusCode::$auditStatus['auditing']),
                'payStatus'    => getArrayItem($params, 'payStatus', StatusCode::$delete),
                'orderStatus'  => getArrayItem($params, 'orderStatus', StatusCode::$orderStatus['waitPay']),
                'outStatus'    => getArrayItem($params, 'outStatus', StatusCode::$delete),
                'returnStatus' => getArrayItem($params, 'returnStatus', StatusCode::$orderReturn['notReturn']),
                'deliveryType' => $deliveryType,
                'payType'      => getArrayItem($params, 'payType',''),
                'customerId'   => getArrayItem($params, 'id', 0),
                'no'           => $sn,
                'verifyCode'   => $verifyCode,
                'orderType'    => getArrayItem($params, 'orderType', StatusCode::$orderType['saleOrder']),
                'selfRuleId'   => getArrayItem($params, 'selfRuleId', 0),
            ];

            //订单数据
            $order[$sn] = [
                'customerId'         => getArrayItem($params, 'id', 0),
                'userCenterId'       => getArrayItem($params, 'userCenterId', 0),
                'shopId'             => getArrayItem($val, 'shopId', 0),
                'shopName'           => getArrayItem($val, 'shopName', ''),
                'no'                 => $sn,
                'outerTradeNo'       => getArrayItem($params, 'outerTradeNo', ''),
                'totalMoney'         => getArrayItem($val, 'totalMoney', 0),
                'payAmount'          => getArrayItem($val, 'payMoney', 0),
                'customerName'       => getArrayItem($params, 'name', ''),
                'customerMobile'     => getArrayItem($params, 'mobile', ''),
                'remark'             => getArrayItem($params, 'remark', ''),
                'deliveryType'       => $deliveryType,//配送方式
                'payType'            => getArrayItem($params, 'payType', ''),//支付方式
                'salesManId'         => getArrayItem($params, 'salesManId', 0),
                'salesManName'       => getArrayItem($params, 'salesManName', ''),
                'customerType'       => getArrayItem($params, 'customerType', 0),
                'buyTotal'           => getArrayItem($val, 'buyTotal', 0),
                'source'             => getArrayItem($params, 'source', StatusCode::$source['manage']),//来源
                'orderStatus'        => getArrayItem($params, 'orderStatus', StatusCode::$orderStatus['waitPay']),
                'payStatus'          => getArrayItem($params, 'payStatus', StatusCode::$delete),
                'returnStatus'       => getArrayItem($params, 'returnStatus', StatusCode::$orderReturn['notReturn']),
                'outStatus'          => getArrayItem($params, 'outStatus', StatusCode::$delete),
                'createTime'         => getArrayItem($params, 'createTime', time()),
                'updateTime'         => getArrayItem($params, 'updateTime', time()),
                'customerOwe'        => getArrayItem($params, 'customerOwe', 0),//客户当前欠款
                'auditStatus'        => getArrayItem($params, 'auditStatus', StatusCode::$auditStatus['auditing']),
                'preferential'       => getArrayItem($val, 'preferential', 0),//优惠券优惠金额
                'vipDiscount'        => getArrayItem($val, 'vipDiscount', 0),//会员卡优惠金额
                'vipDoubleDiscount'  => getArrayItem($val, 'vipDoubleDiscount', 0),
                'originPayAmount'    => getArrayItem($val, 'payAmount', 0),
                'orderType'          => getArrayItem($params, 'orderType', StatusCode::$orderType['saleOrder']),
                'verifyCode'         => $verifyCode,
                'expressMoney'       => getArrayItem($val, 'expressMoney', 0),
                'selfRuleId'         => $selfRuleId,
                'selfRuleData'       => json_encode($selfRuleData),
                'serialNum'          => $serialNum,
                'operatorName'       => getArrayItem($params, 'operatorName', $params['name']),
                'operatorId'         => $this->loginUserCenterId,
                'accountList'        => json_encode(getArrayItem($params, 'accountList', null)),
                'currentAccountName' => getArrayItem($params, 'currentAccountName', ''),
                'receivedMoney'      => getArrayItem($params, 'receivedMoney', 0),
                'reservoir'          => json_encode(getArrayItem($params, 'reservoir', [])),
                'comBinId'           => getArrayItem($params,'comBinId',0),
                'logisticsData'      => json_encode(getArrayItem($params,'logisticsData',null))
            ];

            $extend = [];
            // 处理混合支付数据
            if( !empty($params['admixPayData']) ){
                 $extend['admixPayData'] = $params['admixPayData'];
            }

            if( !empty($extend) ){
                $order[$sn]['extends'] = json_encode($extend);
            }

            if (!empty($addressData)) {
                $orderReceive[$sn] = [
                    'no'           => $sn,
                    'customerId'   => getArrayItem($params, 'id', 0),
                    'customerCode' => getArrayItem($addressData, 'customerCode', ''),//客户编码
                    'realName'     => getArrayItem($addressData, 'name', ''),//收货人姓名
                    'mobile'       => getArrayItem($addressData, 'mobile', ''),//收货人电话
                    'address'      => getArrayItem($addressData, 'address', ''),//收货人详细地址
                    'provinceCode' => getArrayItem($addressData, 'provinceCode', ''),
                    'cityCode'     => getArrayItem($addressData, 'cityCode', ''),
                    'districtCode' => getArrayItem($addressData, 'districtCode', ''),
                ];
            }

            foreach ($val['shopGoodsData'] as $k => &$v) {
                $orderGoods[$sn][] = [
                    'no'           => $sn,
                    'goodsId'      => getArrayItem($v, 'goodsId', 0),
                    'goodsName'    => getArrayItem($v, 'goodsName', ''),
                    'shopId'       => getArrayItem($val, 'shopId', 0),//商铺id
                    'shopName'     => getArrayItem($val, 'shopName', ''),//商铺名称
                    'originPrice'  => getArrayItem($v, 'originPrice', 0),
                    'price'        => getArrayItem($v, 'price', 0),
                    'buyNum'       => getArrayItem($v, 'buyNum', 0),
                    'otherNum'     => getArrayItem($v, 'otherNum', 0),
                    'totalMoney'   => getArrayItem($v, 'totalMoney', 0),
                    'skuId'        => getArrayItem($v, 'skuId', 0),
                    'goodsBasicId' => getArrayItem($v, 'goodsBasicId', 0),
                    'goodsCode'    => getArrayItem($v, 'goodsCode', ''),
                    'deliverNum'   => getArrayItem($v, 'buyNum', 0),//发货数量=购买数量
                    'unitName'     => getArrayItem($v, 'unitName', ''),//单位名称
                    'conversion'   => getArrayItem($v, 'conversion', 0),//换算比率
                    'preferential' => getArrayItem($v, 'preferential', 0),//优惠券优惠金额
                    'vipDiscount'  => getArrayItem($v, 'vipDiscount', 0),//会员卡优惠金额
                    'categoryPath' => getArrayItem($v, 'categoryPath', ''),//分类路径
                    'brandId'      => getArrayItem($v, 'brandId', 0),//品牌id
                    'specGroup'    => json_encode(getArrayItem($v, 'specGroup', null)),//
                    'goodsImages'  => getArrayItem($v, 'goodsImages', ''),
                    'barCode'      => getArrayItem($v, 'barCode', ''),
                    'storageCode'  => getArrayItem($v, 'storageCode', ''),
                    'categoryName' => getArrayItem($v, 'categoryName', ''),
                    'brandName'    => getArrayItem($v, 'brandName', ''),
                    'expressMoney' => getArrayItem($v, 'expressMoney', 0),
                    'outNum'       => 0,//已出库数量
                    'outOfNum'     => getArrayItem($v, 'buyNum', 0),//未出库数量
                    'isEq'         => getArrayItem($v,'isEq',StatusCode::$delete),
                    'extends'      => json_encode(getArrayItem($v, 'extends', null)),
                ];
                $lockInventoryData[$sn][] = [
                    'shopId'       => getArrayItem($val, 'shopId', 0),
                    'merchantId'   => getArrayItem($v, 'merchantId', 0),
                    'materielId'   => getArrayItem($v, 'goodsBasicId', 0),
                    'materielCode' => getArrayItem($v, 'goodsCode', ''),
                    'lockingNum'   => getArrayItem($v, 'buyNum', 0),
                    'originNo'     => $sn,
                    'source'       => StatusCode::$orderType['saleOrder'],
                    'sourceNo'     => $sn,
                    'operatorId'   => getArrayItem($val, 'id', 0),
                    'operatorName' => getArrayItem($val, 'name', ''),
                    'skuId'        => getArrayItem($v, 'skuId', 0),
                    'goodsName'    => getArrayItem($v, 'goodsName', ''),
                    'unitName'     => getArrayItem($v, 'unitName', ''),
                    'specGroup'    => getArrayItem($v, 'specGroup', null),
                ];
                $goodsSaleData [] = [
                    'goodsId' => getArrayItem($v, 'goodsId', 0),
                    'skuId'   => getArrayItem($v, 'skuId', 0),
                    'buyNum'  => getArrayItem($v, 'buyNum', 0),
                ];

                //活动商品数据
                if ($this->isFront) {
                    if (isset($v['activityId']) && $v['activityId'] != 0) {
                        $activityData[] = [
                            'goodsId'    => getArrayItem($v, 'goodsId', 0),
                            'skuId'      => getArrayItem($v, 'skuId', 0),
                            'activityId' => getArrayItem($v, 'activityId', 0),
                            'buyNum'     => getArrayItem($v, 'buyNum', 0)
                        ];
                    }
                }

                if (isset($v['cartId']) && !empty($v['cartId'])) {
                    $cartIds[] = getArrayItem($v, 'cartId', 0);
                }

                if ($this->isEnableSupplier) {
                    //开启了供应商的模块
                    if (isset($v['supplierId']) && !empty($v['supplierId'])) {
                        $supplierIndex[$sn][] = [
                            'no'           => $sn,
                            'supplierId'   => getArrayItem($v, 'supplierId', 0),
                            'supplierName' => getArrayItem($v, 'supplierName', ''),
                            'customerId'   => getArrayItem($params, 'id', 0),
                            'customerName' => getArrayItem($params, 'name', ''),
                            'shopId'       => getArrayItem($v, 'shopId', 0),
                            'shopName'     => getArrayItem($v, 'shopName', ''),
                            'reservoir'    => json_encode(getArrayItem($params, 'reservoir', []))
                        ];
                        $supplierDetails[] = [
                            'no'           => $sn,
                            'supplierId'   => getArrayItem($v, 'supplierId', 0),
                            'supplierName' => getArrayItem($v, 'supplierName', ''),
                            'userCenterId' => getArrayItem($params, 'userCenterId', 0),
                            'customerId'   => getArrayItem($params, 'id', 0),
                            'customerName' => getArrayItem($params, 'name', ''),
                            'shopId'       => getArrayItem($v, 'shopId', 0),
                            'shopName'     => getArrayItem($v, 'shopName', ''),
                            'materielId'   => getArrayItem($v, 'goodsBasicId', 0),
                            'materielCode' => getArrayItem($v, 'goodsCode', ''),
                            'goodsId'      => getArrayItem($v, 'goodsId', 0),
                            'goodsName'    => getArrayItem($v, 'goodsName', ''),
                            'goodsImages'  => getArrayItem($v, 'goodsImages', ''),
                            'skuId'        => getArrayItem($v, 'skuId', 0),
                            'unitName'     => getArrayItem($v, 'unitName', ''),
                            'conversion'   => getArrayItem($v, 'conversion', 0),
                            'specGroup'    => json_encode(getArrayItem($v, 'specGroup', null)),//
                            'categoryPath' => getArrayItem($v, 'categoryPath', ''),
                            'brandId'      => getArrayItem($v, 'brandId', 0),
                            'categoryName' => getArrayItem($v, 'categoryName', ''),
                            'brandName'    => getArrayItem($v, 'brandName', ''),
                            'barCode'      => getArrayItem($v, 'barCode', ''),
                            'storageCode'  => getArrayItem($v, 'storageCode', ''),
                            'buyNum'       => getArrayItem($v, 'buyNum', 0),
                            'costPrice'    => getArrayItem($v, 'costPrice', 0),
                            'price'        => getArrayItem($v, 'price', 0),
                            'totalMoney'   => getArrayItem($v, 'totalMoney', 0),
                            'createTime'   => time(),
                            'reservoir'    => json_encode(getArrayItem($params, 'reservoir', []))
                        ];
                    }
                }
            }
        }
        unset($val);

        return ResultWrapper::success([
            'orderIndex'        => $orderIndex,
            'order'             => $order,
            'orderGoods'        => $orderGoods,
            'orderReceive'      => $orderReceive,
            'lockInventoryData' => $lockInventoryData,
            'activityData'      => $activityData,
            'goodsSaleData'     => $goodsSaleData,
            'cartIds'           => $cartIds,
            'useCouponId'       => $useCouponId,
            'orderSn'           => $orderSn,
            'supplierIndex'     => $supplierIndex,
            'supplierDetails'   => $supplierDetails,
        ]);
    }

    /**
     * Doc: (des="")
     * User: XMing
     * Date: 2020/12/22
     * Time: 4:27 下午
     * @param array $params
     * @return array
     */
    public static function noRelIdMap(array $params): array
    {
        $map = [];
        foreach ($params as $val) {
            $map[$val['no']] = $val['id'];
        }
        return $map;
    }

    /**
     * Doc: (des="")
     * User: XMing
     * Date: 2020/12/18
     * Time: 3:08 下午
     * @param $originArr
     * @param $relMap
     * @param string $field
     * @param bool $mul
     * @return void
     */
    public function pushValByNo(&$originArr, $relMap, $field = 'orderId', $mul = false)
    {
        $map = [];
        foreach ($originArr as $no => &$item) {
            $orderId = getArrayItem($relMap, $no, 0);
            if ($mul === false) {
                $item[$field] = $orderId;
                continue;
            }
            foreach ($item as &$value) {
                $value[$field] = $orderId;
                $map[] = $value;
            }
        }
        $mul === true && $originArr = $map;
        $originArr = array_values($originArr);
    }


    /**
     * Doc: (des="转换锁定库存的数据格式")
     * User: XMing
     * Date: 2021/3/5
     * Time: 10:41 上午
     * @param $originArr
     * @return array
     */
    public function buildLockingByShopId($originArr): array
    {
        $map = [];
        foreach ($originArr as $item){
            $map[$item['shopId']][] = $item;
        }
        return $map;
    }

    /**
     * Doc: (des="写入订单数据")
     * User: XMing
     * Date: 2020/12/19
     * Time: 2:44 下午
     * @param array $buildGroup
     * @param $params
     * @return ResultWrapper
     * @throws \Exception
     */
    public function insertOrder(array $buildGroup, $params): ResultWrapper
    {
        $objMCart = new MCart($this->onlineUserId, $this->onlineEnterpriseId);
        $objMUserCoupon = new MUserCoupon($this->onlineUserId, $this->onlineEnterpriseId);
        $objMInventory = new MInventory($this->onlineEnterpriseId, $this->onlineUserId);
        $objMGoods = new MGoods($this->onlineEnterpriseId, false, $this->onlineUserId);
        $objMComBinPackage = new MComBinPackage($this->onlineEnterpriseId,$this->onlineUserId);
        $objDSupplierOrderIndex = new DSupplierOrderIndex();
        $objDSupplierOrderDetails = new DSupplierOrderDetails();
        //1. 先写索引表
        $fix = ceil($this->onlineUserId / $this->cutTable);
        $this->objDOrderIndex->setTable('qianniao_order_index_' . $this->onlineEnterpriseId);
        $this->objDOrder->setTable('qianniao_order_' . $this->onlineEnterpriseId . '_' . $fix);
        $this->objDOrderGoods->setTable('qianniao_order_goods_' . $this->onlineEnterpriseId . '_' . $fix);
        $this->objDOrderReceive->setTable('qianniao_order_receive_' . $this->onlineEnterpriseId . '_' . $fix);
        $objDSupplierOrderIndex->setTable('qianniao_supplier_order_index_' . $this->onlineEnterpriseId);

        $orderIndex = getArrayItem($buildGroup, 'orderIndex', []);
        $order = getArrayItem($buildGroup, 'order', []);
        $orderGoods = getArrayItem($buildGroup, 'orderGoods', []);
        $orderReceive = getArrayItem($buildGroup, 'orderReceive', []);
        $delCartIds = getArrayItem($buildGroup, 'cartIds', []);
        $useCouponId = getArrayItem($buildGroup, 'useCouponId', 0);
        $lockInventoryData = getArrayItem($buildGroup, 'lockInventoryData', []);
        $goodsSaleData = getArrayItem($buildGroup, 'goodsSaleData', []);
        $activityData = getArrayItem($buildGroup, 'activityData', []);
        $orderSn = getArrayItem($buildGroup, 'orderSn', []);
        $supplierIndex = getArrayItem($buildGroup, 'supplierIndex', []);
        $supplierDetails = getArrayItem($buildGroup, 'supplierDetails', []);
        $comBinId = getArrayItem($params,'comBinId',0);
        $this->objDOrder->beginTransaction();

        $orderIds = $this->objDOrderIndex->insert($orderIndex, true);
        if ($orderIds === false) {
            $this->objDOrder->rollBack();
            return ResultWrapper::fail($this->objDOrderIndex->error(), ErrorCode::$dberror);
        }

        $noRelIdMap = $this->objDOrderIndex->select(['id' => $orderIds], 'id,no');
        if ($noRelIdMap === false) {
            $this->objDOrder->rollBack();
            return ResultWrapper::fail($this->objDOrderIndex->error(), ErrorCode::$dberror);
        }
        $noRelIdMap = self::noRelIdMap($noRelIdMap);
        self::pushValByNo($order, $noRelIdMap, 'id');
        self::pushValByNo($orderGoods, $noRelIdMap, 'orderId', true);
        self::pushValByNo($lockInventoryData, $noRelIdMap, 'originId', true);
        $lockInventoryData = self::buildLockingByShopId($lockInventoryData);//处理锁定数据
        if (!empty($orderReceive)) {
            self::pushValByNo($orderReceive, $noRelIdMap, 'orderId');
        }

        if (!empty($comBinId)){
            //组合套餐
            $comBinIncResult = $objMComBinPackage->incPackNum($comBinId,$params,$noRelIdMap);
            if (!$comBinIncResult->isSuccess()){
                $this->objDOrder->rollBack();
                return ResultWrapper::fail($comBinIncResult->getData(),$comBinIncResult->getErrorCode());
            }
        }

        // 订单主单据数据
        $orderResult = $this->objDOrder->insert($order, true);
        if ($orderResult === false) {
            $this->objDOrder->rollBack();
            return ResultWrapper::fail($this->objDOrder->error(), ErrorCode::$dberror);
        }

        // 订单商品
        $orderGoodsResult = $this->objDOrderGoods->insert($orderGoods, true);
        if ($orderGoodsResult === false) {
            $this->objDOrder->rollBack();
            return ResultWrapper::fail($this->objDOrderGoods->error(), ErrorCode::$dberror);
        }

        // 收货地址
        if (!empty($orderReceive)) {
            $orderReceiveResult = $this->objDOrderReceive->insert($orderReceive, true);
            if ($orderReceiveResult === false) {
                $this->objDOrder->rollBack();
                return ResultWrapper::fail($this->objDOrderReceive->error(), ErrorCode::$dberror);
            }
        }


        //删除购物车内已生成订单商品
        if (!empty($delCartIds)) {
            $result = $objMCart->delCart($delCartIds, true);
            if (!$result->isSuccess()) {
                $this->objDOrder->rollBack();
                return ResultWrapper::fail($result->getData(), ErrorCode::$dberror);
            }
        }


        //将优惠券改为已使用
        if (isset($useCouponId) && !empty($useCouponId)) {
            $useCouponOrderData = [];
            foreach ($noRelIdMap as $key=>$value){
                $useCouponOrderData[] = [
                    'no' => $key,
                    'id' => $value
                ];
            }
            $useCouponData = [
                'isUse'   => StatusCode::$delete,
                'useTime' => time(),
                'orderData' => json_encode($useCouponOrderData)
            ];
            $result = $objMUserCoupon->updateIsUse(['id' => $useCouponId], $useCouponData);
            if (!$result->isSuccess()) {
                $this->objDOrder->rollBack();
                return ResultWrapper::fail($result->getData(), ErrorCode::$dberror);
            }
        }

        //锁定库存商品数量
        foreach ($lockInventoryData as $shopId => $lockInventory){
            $lockInventoryResult = $objMInventory->updateLockInventory($shopId,$lockInventory);
            if (!$lockInventoryResult->isSuccess()) {
                $this->objDOrder->rollBack();
                return ResultWrapper::fail($lockInventoryResult->getData(), $lockInventoryResult->getErrorCode());
            }
        }

        if (!empty($supplierIndex)) {
            self::pushValByNo($supplierIndex, $noRelIdMap, 'orderId', true);
            $supplierIndexIds = $objDSupplierOrderIndex->insert($supplierIndex, true);
            if ($supplierIndexIds === false) {
                Logger::logs(E_USER_ERROR, 'sql error', __CLASS__, __LINE__, $objDSupplierOrderIndex->error());
                $this->objDOrder->rollBack();
                return ResultWrapper::fail($objDSupplierOrderIndex->error(), ErrorCode::$dberror);
            }
            self::relArrMap($supplierDetails, $supplierIndexIds);
            $maxOrderId = max($orderIds);
            $fix = ceil($maxOrderId / MSupplierOrderDetails::$cutTable);
            $objDSupplierOrderDetails->setTable('qianniao_supplier_order_details_' . $this->onlineEnterpriseId . '_' . $fix);
            $result = $objDSupplierOrderDetails->insert($supplierDetails, true);
            if ($result === false) {
                Logger::logs(E_USER_ERROR, 'sql error', __CLASS__, __LINE__, $objDSupplierOrderIndex->error());
                $this->objDOrder->rollBack();
                return ResultWrapper::fail($objDSupplierOrderIndex->error(), ErrorCode::$dberror);
            }
        }

        //销售单
        if ($params['orderType'] === StatusCode::$orderType['salesSlip']) {
            $runSalesSlipResult = self::runSalesSlip($orderIds);
            if (!$runSalesSlipResult->isSuccess()) {
                $this->objDOrder->rollBack();
                return ResultWrapper::fail($runSalesSlipResult->getData(), $runSalesSlipResult->getErrorCode());
            }
        }

        //写es
        $address = (array)array_shift($orderReceive);
        foreach ($order as $item) {
            //self::esData($item, $address);
            self::buildSaleOrderData($params,$address,$item,$orderGoods);
        }
        $this->objDOrder->commit();

        //增加销量
        if (!empty($goodsSaleData)) {
            foreach ($goodsSaleData as $value) {
                $result = $objMGoods->updateSalesNum($value['goodsId'], $value['skuId'], $value['buyNum']);
                if ($result === false) {
                    Logger::logs(E_USER_ERROR, 'sql error', __CLASS__, __LINE__, '商品增加销量失败');
                }
            }
        }

        //减活动商品总数量
        if (!empty($activityData)) {
            foreach ($activityData as $value) {
                $this->objActivityLimitCache->rPop($value['activityId'], $value['goodsId'], $value['skuId'], $value['buyNum']);
            }
        }

        // 后台代课下单不参与分销
        if ($params['source'] != StatusCode::$source['manage']){
            foreach ($orderIds as $orderId) {
                self::taskCreateCommission(getArrayItem($params, 'token', ''), getArrayItem($params, 'auth', ''), getArrayItem($params, 'id', 0), $orderId);   
            }
        }


        //统计订单信息
        self::noticeStatistics([
            'userCenterId' => $this->onlineUserId,
            'enterpriseId' => $this->onlineEnterpriseId,
            'customerId'   => getArrayItem($params, 'id', 0),
            'no'           => $orderSn,
            'noticeType'   => 'create',
        ], 'MOrderStatistics');

        //写日志
        foreach ($orderSn as $sn) {
            parent::saveLog([
                'no'            => $sn,
                'actionType'    => '创建订单',//创建订单
                'operationData' => '',
                'userCenterId'  => $this->onlineUserId,
                'enterpriseId'  => $this->onlineEnterpriseId,
                'createTime'    => time(),
            ]);
        }
        return ResultWrapper::success($orderIds);
    }

    /**
     * Doc: (des="销售单-出库-收款-完成")
     * User: XMing
     * Date: 2020/12/21
     * Time: 11:53 上午
     * @param array $orderIds
     * @return ResultWrapper
     * @throws \Exception
     */
    public function runSalesSlip(array $orderIds): ResultWrapper
    {
        //自动审核订单
        $objMInventoryOut = new MInventoryOut($this->onlineEnterpriseId, $this->onlineUserId);
        foreach ($orderIds as $id) {
            //自动审核订单
            $auditResult = self::updateAuditStatus([
                'id'          => $id,
                'audit'       => '销售单-自动审核',
                'auditId'     => $this->onlineUserId,
                'auditStatus' => StatusCode::$auditStatus['auditPass']
            ]);
            if (!$auditResult->isSuccess()) {
                return ResultWrapper::fail($auditResult->getData(), $auditResult->getErrorCode());
            }
            $outId = $auditResult->getData();//出库单id
            //自动出库
            $dbResult = $objMInventoryOut->updateInventoryOutStatus([
                'id'        => $outId,
                'auditId'   => $this->onlineUserId,
                'auditName' => '销售单-自动审核'
            ]);
            if (!$dbResult->isSuccess()) {
                return ResultWrapper::fail($dbResult->getData(), $dbResult->getErrorCode());
            }
            unset($dbResult);

            //确认收款
            $dbResult = self::updateOrderPayData(
                [
                    'payStatus' => StatusCode::$standard,
                    'payTime'   => time()
                ],
                ['id' => $id]
            );
            if (!$dbResult->isSuccess()) {
                return ResultWrapper::fail($dbResult->getData(), $dbResult->getErrorCode());
            }
            unset($dbResult);

            $dbResult = self::updateOrderStatus($id,
                ['orderStatus' => StatusCode::$orderStatus['finish']],
                []
            );
            if (!$dbResult->isSuccess()) {
                return ResultWrapper::fail($dbResult->getData(), $dbResult->getErrorCode());
            }
        }
        return ResultWrapper::success(true);
    }

    /**
     * Doc: (des="")
     * User: XMing
     * Date: 2020/12/19
     * Time: 3:06 下午
     * @param array $lists
     * @oaram array $params
     * @return ResultWrapper
     */
    public function buildGoodsByShop(array $lists,array $params): ResultWrapper
    {
        if (empty($lists)) {
            return ResultWrapper::success([]);
        }

        $totalReduceMoney = getArrayItem($params,'totalReduceMoney',0);
        $map = [];
        foreach ($lists as $list) {
            if (isset($list['subMoney'])) {
                $list['totalMoney'] = $list['subMoney'];
                unset($list['subMoney']);
            }
            if (isset($list['basicGoodsId'])) {
                $list['goodsBasicId'] = $list['basicGoodsId'];
                unset($list['basicGoodsId']);
            }
            if (isset($list['code'])) {
                $list['goodsCode'] = $list['code'];
                unset($list['code']);
            }
            if ($list['salePrice']) {
                $list['price'] = $list['salePrice'];
                unset($list['salePrice']);
            }
            if (!isset($map[$list['shopId']]['totalMoney'])) {
                $map[$list['shopId']]['totalMoney'] = 0;
            }
            if (!isset($map[$list['shopId']]['preferential'])) {
                $map[$list['shopId']]['preferential'] = 0;
            }
            if (!isset($map[$list['shopId']]['payMoney'])) {
                $map[$list['shopId']]['payMoney'] = 0;
            }
            if (!isset($map[$list['shopId']]['buyTotal'])) {
                $map[$list['shopId']]['buyTotal'] = 0;
            }
            if (!isset($list['supplierId'])) {
                $list['supplierId'] = 0;
            }
            if (!isset($list['supplerName'])) {
                $list['supplerName'] = '';
            }
            $totalMoney = getArrayItem($list, 'totalMoney', 0);
            $preferential = getArrayItem($list, 'preferential', 0);
            $buyNum = getArrayItem($list, 'buyNum', 0);
            $map[$list['shopId']]['shopId'] = getArrayItem($list, 'shopId', 0);
            $map[$list['shopId']]['shopName'] = getArrayItem($list, 'shopName', 0);
            $map[$list['shopId']]['expressMoney'] = 0;//后台下单没有运费
            $map[$list['shopId']]['buyTotal'] = bcadd($map[$list['shopId']]['buyTotal'], $buyNum, 2);
            $map[$list['shopId']]['totalMoney'] = bcadd($map[$list['shopId']]['totalMoney'], $totalMoney, 2);
            $map[$list['shopId']]['payMoney'] = bcadd($map[$list['shopId']]['payMoney'], bcsub($totalMoney, $preferential + $totalReduceMoney), 2);
            $map[$list['shopId']]['preferential'] = bcadd($map[$list['shopId']]['preferential'], $preferential + $totalReduceMoney, 2);
            $map[$list['shopId']]['shopGoodsData'][] = $list;
            $totalReduceMoney = 0;
            if ($map[$list['shopId']]['payMoney'] <= 0){
                return ResultWrapper::fail('订单金额计算异常',ErrorCode::$paramError);
            }
        }
        return ResultWrapper::success(array_values($map));
    }

    /**
     * 格式化订单关联数据
     * @param $common
     * @return ResultWrapper
     * @throws \Exception
     */
    public function formatCommonParams($common): ResultWrapper
    {
        $objMCustomer = new MCustomer($this->onlineEnterpriseId, $this->onlineUserId);
        $objMCustomerBalance = new MCustomerBalance($this->onlineEnterpriseId, $this->onlineUserId);

        // 获取客户信息
        $customerData = $objMCustomer->getCustomerInfoByUserCenterId($common['userCenterId']);
        if (!$customerData->isSuccess()) {
            return ResultWrapper::fail($customerData->getData(), $customerData->getErrorCode());
        }
        $customerData = $customerData->getData();

        // 获取客户当前欠款
        $customerOwe = $objMCustomerBalance->getCustomerBalance($customerData['id']);
        $customerData['customerOwe'] = $customerOwe;
        unset($customerData['remark']);
        $common = array_merge($common, $customerData);

        if (isset($common['version']) && $common['version'] == 1){
            //多配送方式
            foreach ($common['proporties'] as $shopId => &$item){
                $deliveryResult = self::getObjectByDeliveryType($item);
                if (!$deliveryResult->isSuccess()){
                    return ResultWrapper::fail($deliveryResult->getData(),$deliveryResult->getErrorCode());
                }
                $deliveryData = $deliveryResult->getData();
                $item['selfRuleData'] = getArrayItem($deliveryData,'selfRuleData',[]);
                $item['addressData'] = getArrayItem($deliveryData,'addressData',[]);
            }
            unset($item);
        }

        // 获取物流信息
        $deliveryResult = self::getObjectByDeliveryType($common);
        if (!$deliveryResult->isSuccess()){
            return ResultWrapper::fail($deliveryResult->getData(),$deliveryResult->getErrorCode());
        }
        $deliveryData = $deliveryResult->getData();
        $common['selfRuleData'] = getArrayItem($deliveryData,'selfRuleData',[]);
        $common['addressData'] = getArrayItem($deliveryData,'addressData',[]);

        return ResultWrapper::success($common);
    }

    /**
     * Doc: (des="通过配送方式获取配送信息")
     * User: XMing
     * Date: 2021/2/4
     * Time: 8:12 下午
     * @param array $common
     * @return ResultWrapper
     * @throws \Exception
     */
    private function getObjectByDeliveryType(array $common): ResultWrapper
    {
        $objMDeliverySetting = new MDeliverySetting($this->onlineUserId, $this->onlineEnterpriseId);
        $selfRuleData = [];
        $addressData = [];
        switch ($common['deliveryType']) {
            case StatusCode::$deliveryType['selfMention']: // 上门自提
                if (isset($common['selfRuleId']) && !empty($common['selfRuleId'])) {
                    $selfRuleDataResult = $objMDeliverySetting->getSelfRuleInfo($common['selfRuleId']);
                    if (!$selfRuleDataResult->isSuccess()) {
                        return ResultWrapper::fail($selfRuleDataResult->getData(), $selfRuleDataResult->getErrorCode());
                    }
                    $selfRuleData = $selfRuleDataResult->getData();
                    $selfRuleData = isset($selfRuleData['setData']) ? $selfRuleData['setData'] : [];
                }
                break;
            case in_array( $common['deliveryType'],[StatusCode::$deliveryType['goodsDelivery'],StatusCode::$deliveryType['logistics'],StatusCode::$deliveryType['logisticsLines'],StatusCode::$deliveryType['logisticsVehicle']] ):
                if (isset($common['addressId']) && !empty($common['addressId'])){
                    $common['receiveAddressId'] = $common['addressId'];
                }
                if (isset($common['receiveAddressId']) && !empty($common['receiveAddressId'])) {
                    $objMShippingAddress = new MShippingAddress($this->onlineEnterpriseId);
                    $result = $objMShippingAddress->getShippingAddressInfo($common['receiveAddressId']);
                    if (!$result->isSuccess()) {
                        return ResultWrapper::fail($result->getData(), ErrorCode::$dberror);
                    }
                    $addressData = $result->getData();
                    if (empty($addressData)) {
                        return ResultWrapper::fail('收货地址信息不存在', ErrorCode::$dberror);
                    }
                }
                break;
        }
        return ResultWrapper::success([
            'selfRuleData' => $selfRuleData,
            'addressData'  => $addressData
        ]);
    }

    /**
     * Doc: (des="")
     * User: XMing
     * Date: 2020/12/22
     * Time: 4:56 下午
     * @param $arr
     * @param $ids
     */
    private function relArrMap(&$arr, $ids)
    {
        foreach ($arr as $index => &$value) {
            $value['id'] = getArrayItem($ids, $index, 0);
        }
    }

    /**
     * Doc: (des="查询供应商模块是否启用")
     * User: XMing
     * Date: 2020/12/22
     * Time: 10:01 上午
     * @return bool true=>开启 false=>关闭
     */
    public function getIsEnableSupplier(): bool
    {
        $objMBasicSetup = new MBasicSetup($this->onlineEnterpriseId);
        $setResult = $objMBasicSetup->getBasicField('supplierSet');
        if (!$setResult->isSuccess()) {
            return false;
        }
        $set = (array)$setResult->getData();
        $supplierSet = (array)getArrayItem($set, 'supplierSet', []);
        $isEnableSupplier = getArrayItem($supplierSet, 'enable_istrue', StatusCode::$delete);
        if ($isEnableSupplier == StatusCode::$standard) {
            return true;
        }
        return false;
    }

    /**
     * Doc: (des="")
     * User: XMing
     * Date: 2020/12/23
     * Time: 9:50 上午
     * @param array $params
     * @param array $lists
     * @return array
     */
    public function buildPurchase(array $params, array $lists): array
    {

        $goodsData = [];
        foreach ($lists as $list) {
            $skuId = getArrayItem($list, 'skuId', 0);

            if (!isset($goodsData[$skuId]['buyerNum'])) {
                $goodsData[$skuId]['buyerNum'] = 0;
            }

            $goodsData[$skuId]['basicGoodsId'] = getArrayItem($list, 'materielId', 0);
            $goodsData[$skuId]['goodsCode'] = getArrayItem($list, 'materielCode', '');
            $goodsData[$skuId]['goodsName'] = getArrayItem($list, 'goodsName', '');
            $goodsData[$skuId]['skuId'] = getArrayItem($list, 'skuId', 0);
            $goodsData[$skuId]['buyerNum'] = bcadd($goodsData[$skuId]['buyerNum'], $list['buyNum'], 2);
            $goodsData[$skuId]['buyerUnitPrice'] = getArrayItem($list, 'costPrice', 0);
            $goodsData[$skuId]['subtotalPrice'] = bcmul(getArrayItem($list, 'costPrice', 0), $goodsData[$skuId]['buyerNum'], 2);
            $goodsData[$skuId]['categoryId'] = getArrayItem($list, 'categoryId', 0);
            $goodsData[$skuId]['categoryName'] = getArrayItem($list, 'categoryName', '');
            $goodsData[$skuId]['unitName'] = getArrayItem($list, 'unitName', '');
            $goodsData[$skuId]['skuName'] = MPurchase::formatSpecGroup(json_decode(getArrayItem($list, 'specGroup', [])));
        }

        return [
            'shopId'         => getArrayItem($params, 'shopId', 0),
            'shopName'       => getArrayItem($params, 'shopName', ''),
            'supplierId'     => getArrayItem($params, 'supplierId', 0),
            'supplierName'   => getArrayItem($params, 'supplierName', ''),
            'buyerId'        => getArrayItem($params, 'buyerId', 0),
            'departmentPath' => getArrayItem($params, 'departmentPath', ''),
            'buyerName'      => getArrayItem($params, 'buyerName', ''),
            'operatorName'   => getArrayItem($params, 'operatorName', ''),
            'operatorId'     => getArrayItem($params, 'operatorId', 0),
            'couponAmount'   => getArrayItem($params, 'couponAmount', 0),
            'otherAmount'    => getArrayItem($params, 'otherAmount', 0),
            'remark'         => getArrayItem($params, 'remark', ''),
            'goodsData'      => $goodsData,
        ];
    }

    /**
     * Doc: (des="订单es")
     * User: XMing
     * Date: 2020/12/30
     * Time: 6:30 下午
     * @param $order
     * @param $addressData
     */
    public function esData($order, $addressData)
    {
        $orderEsData = [
            /*订单表信息*/
            'id'                => getArrayItem($order, 'id', 0),//订单编号,
            'no'                => getArrayItem($order, 'no', ''),//订单编号,
            'outerTradeNo'      => getArrayItem($order, 'outerTradeNo', ''),//'外部流水号(支付宝/微信返回的流水号)'
            'shopId'            => getArrayItem($order, 'shopId', 0),
            'shopName'          => getArrayItem($order, 'shopName', ''),
            'enterpriseId'      => $this->onlineEnterpriseId,
            'userCenterId'      => getArrayItem($order, 'userCenterId', 0),
            'totalMoney'        => getArrayItem($order, 'totalMoney', 0),
            'payAmount'         => getArrayItem($order, 'payAmount', 0),
            'buyTotal'          => getArrayItem($order, 'buyTotal', 0),
            'customerName'      => getArrayItem($order, 'customerName', ''),//客户姓名
            'customerId'        => getArrayItem($order, 'customerId', 0),
            'customerType'      => getArrayItem($order, 'customerType', 0),//客户类型
            'payStatus'         => getArrayItem($order, 'payStatus', StatusCode::$delete),//'支付状态  默认4 未支付 5已支付'
            'orderStatus'       => getArrayItem($order, 'orderStatus', StatusCode::$orderStatus['waitPay']),//订单状态 默认1 创建 2待支付 3代发货 4待收货 5已完成 6已关闭
            'payType'           => getArrayItem($order, 'payType', StatusCode::$orderType['saleOrder']),//'支付方式 1微信 2支付宝 3货到付款 4上门自提'
            'deliveryType'      => getArrayItem($order, 'deliveryType', StatusCode::$deliveryType['selfMention']),
            'source'            => getArrayItem($order, 'source', StatusCode::$source['manage']),//订单来源 默认1 ios 2android 3小程序 4后台创建
            'remark'            => getArrayItem($order, 'remark', ''),//订单备注
            'auditStatus'       => getArrayItem($order, 'auditStatus', StatusCode::$auditStatus['auditing']),// '审核状态 默认1 待审 2审核通过 3 审核未通过 4 审核中'
            'createTime'        => getArrayItem($order, 'createTime', time()),
            'updateTime'        => getArrayItem($order, 'updateTime', time()),//'修改时间',
            'salesManId'        => getArrayItem($order, 'salesManId', 0),
            'salesManName'      => getArrayItem($order, 'salesManName', ''),
            'returnStatus'      => getArrayItem($order, 'notReturn', StatusCode::$orderReturn['notReturn']),
            'outStatus'         => getArrayItem($order, 'outStatus', StatusCode::$delete),
            'verifyCode'        => getArrayItem($order, 'verifyCode', $order['verifyCode']),//核销码

            /*收货人信息*/
            'realName'          => getArrayItem($addressData, 'realName', ''),//收货人姓名
            'mobile'            => getArrayItem($addressData, 'mobile', ''),//收货人电话
            'address'           => getArrayItem($addressData, 'address', ''),//收货详细地址
            'provinceCode'      => getArrayItem($addressData, 'provinceCode', ''),//收货人省份编码
            'cityCode'          => getArrayItem($addressData, 'cityCode', ''),//收货人城市编码
            'districtCode'      => getArrayItem($addressData, 'districtCode', ''),//收货人区编码

            /*优惠信息*/
            'preferential'      => getArrayItem($order, 'preferential', 0),//优惠券优惠金额
            'vipDiscount'       => getArrayItem($order, 'vipDiscount', 0),//会员卡优惠金额
            'vipDoubleDiscount' => getArrayItem($order, 'vipDoubleDiscount', 0),//会员卡折上折优惠金额
            'orderType'         => getArrayItem($order, 'orderType', StatusCode::$orderType['salesSlip']),
        ];

        $_id = self::createEsDocumentId($orderEsData['id']);
        $result = $this->objDOrder->addUpSearchIndexDocument($orderEsData, $_id);
        if (isset($result['_shards']) && isset($result['_shards']['successful']) && $result['_shards']['successful'] == 1) {
            //echo "es操作成功";
            //return;
            return;
        }
        Logger::logs(E_USER_ERROR, 'es error', __CLASS__, __LINE__, $_id);
        //echo "es操作失败";
    }

    /**
     * Doc: (des="订单打印小票")
     * User: XMing
     * Date: 2020/12/31
     * Time: 10:59 上午
     * @param $params
     * @param $address
     * @param $order
     * @param $goodsDetails
     */
    public function buildSaleOrderData($params,$address,$order,$goodsDetails)
    {
        //销售单数据
        $this->isEnablePrint = false;
        if (isset($params['isEnablePrint']) && $params['isEnablePrint'] == StatusCode::$standard){
            $this->isEnablePrint = true;
        }
        if ($this->isEnablePrint === false){
            return;
        }
        $this->objSaleOrder->setReceiptTitle('销售订单');
        $this->objSaleOrder->setCodeName('订单号');
        $this->objSaleOrder->setCustomerName(getArrayItem($params, 'name', ''));
        $this->objSaleOrder->setCustomerMobile(getArrayItem($params, 'mobile', ''));
        $this->objSaleOrder->setPreferentialAmount(getArrayItem($params, 'preferential', 0));//目前销售订单没有优惠
        $this->objSaleOrder->setTotalAmount(getArrayItem($params, 'totalMoney', 0));
        $this->objSaleOrder->setPayAmount(getArrayItem($params, 'payAmount', 0));
        $this->objSaleOrder->setAddress(getArrayItem($address,'address',''));
        $this->objSaleOrder->setNo(getArrayItem($order,'no',''));//目前只会有一个订单
        $this->objSaleOrder->setShopName(getArrayItem($order,'shopName',''));
        $this->objSaleOrder->setCreateTime(getArrayItem($order,'createTime',time()));
        $this->objSaleOrder->setGoodsDetails($goodsDetails);
    }

    public function test()
    {

    }
}