<?php




namespace app\common\repositories\store\order;


use app\common\dao\store\order\StoreOrderDao;
use app\common\model\store\order\StoreGroupOrder;
use app\common\model\store\order\StoreOrder;
use app\common\model\store\product\ProductPresellSku;
use app\common\model\user\User;
use app\common\repositories\BaseRepository;
use app\common\repositories\store\coupon\StoreCouponRepository;
use app\common\repositories\store\coupon\StoreCouponUserRepository;
use app\common\repositories\store\MerchantTakeRepository;
use app\common\repositories\store\product\ProductAssistSetRepository;
use app\common\repositories\store\product\ProductAssistSkuRepository;
use app\common\repositories\store\product\ProductAttrValueRepository;
use app\common\repositories\store\product\ProductCopyRepository;
use app\common\repositories\store\product\ProductGroupBuyingRepository;
use app\common\repositories\store\product\ProductGroupSkuRepository;
use app\common\repositories\store\product\ProductPresellSkuRepository;
use app\common\repositories\store\product\ProductRepository;
use app\common\repositories\store\shipping\ExpressPartnerRepository;
use app\common\repositories\store\shipping\ExpressRepository;
use app\common\repositories\store\StoreSeckillActiveRepository;
use app\common\repositories\system\attachment\AttachmentRepository;
use app\common\repositories\system\merchant\FinancialRecordRepository;
use app\common\repositories\system\merchant\MerchantRepository;
use app\common\repositories\system\serve\ServeDumpRepository;
use app\common\repositories\user\UserAddressRepository;
use app\common\repositories\user\UserBillRepository;
use app\common\repositories\user\UserMerchantRepository;
use app\common\repositories\user\UserRelationRepository;
use app\common\repositories\user\UserRepository;
use app\common\repositories\wechat\RoutineQrcodeRepository;
use app\common\repositories\wechat\WechatUserRepository;
use ln\jobs\PayGiveCouponJob;
use ln\jobs\SendSmsJob;
use ln\jobs\SendTemplateMessageJob;
use ln\jobs\UserBrokerageLevelJob;
use ln\services\AlipayService;
use ln\services\CombinePayService;
use ln\services\CrmebServeServices;
use ln\services\ExpressService;
use ln\services\MiniProgramService;
use ln\services\PayService;
use ln\services\QrcodeService;
use ln\services\printer\Printer;
use ln\services\SpreadsheetExcelService;
use ln\services\SwooleTaskService;
use ln\services\UploadService;
use ln\services\WechatService;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\Writer\PngWriter;
use Exception;
use FormBuilder\Factory\Elm;
use FormBuilder\Form;
use function Symfony\Component\String\b;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Log;
use think\facade\Queue;
use think\facade\Route;
use think\Model;

/**
 * Class StoreOrderRepository
 * @package app\common\repositories\store\order
 * @author xaboy
 * @day 2020/6/9
 * @mixin StoreOrderDao
 */
class StoreOrderRepository extends BaseRepository
{
    /**
     * 支付类型
     */
    const PAY_TYPE = ['balance', 'weixin', 'routine', 'h5', 'alipay', 'alipayQr', 'weixinQr'];

    /**
     * StoreOrderRepository constructor.
     * @param StoreOrderDao $dao
     */
    public function __construct(StoreOrderDao $dao)
    {
        $this->dao = $dao;
    }

    public function createPresellOrder(User $user, int $pay_type, array $cartId, int $addressId, array $coupons, array $takes, array $mark, array $receipt_data)
    {
        $uid = $user->uid;
        $couponUserRepository = app()->make(StoreCouponUserRepository::class);
        foreach ($coupons as $merId => $coupon) {
            if (!is_array($coupon)) {
                unset($coupons[$merId]);
                continue;
            }
            $storeCoupon = $coupon['store'] ?? ($coupon['store'] = 0);
            $productCoupon = array_unique($coupon['product'] ?? ($coupon['product'] = []));
            $_coupons = $storeCoupon ? array_merge($productCoupon, [$storeCoupon]) : $productCoupon;
            if (!count($_coupons)) {
                unset($coupons[$merId]);
                continue;
            }
            if (count($couponUserRepository->validIntersection($merId, $uid, $_coupons)) != count($_coupons))
                throw new ValidateException('请选择正确的优惠券');
        }
        $order = $this->cartIdByOrderInfo($uid, $takes, $cartId, $addressId, 1, $coupons);
        if ($order['status'] == 'noDeliver')
            throw new ValidateException('部分商品不支持该区域');
        if (!$order['address']) throw new ValidateException('请选择正确的收货地址');

        $cartInfo = $order['order'][0];
        $address = $order['address'];

        if (in_array($cartInfo['mer_id'], $takes)) {
            if (!$cartInfo['take']['mer_take_status']) {
                throw new ValidateException('该店铺不支持到店自提');
            }
            $cartInfo['order']['pay_price'] = max(bcsub($cartInfo['order']['pay_price'], $cartInfo['order']['postage_price'], 2), 0);
            $cartInfo['order']['postage_price'] = 0;
        }

        $cost = 0;
        $totalNum = 0;
        $giveCouponIds = [];
        $total_extension_one = 0;
        $total_extension_two = 0;
        $useCoupon = [];
        $isSelfBuy = $user->is_promoter && systemConfig('extension_self') ? 1 : 0;
        if ($isSelfBuy) {
            $spreadUid = $user->uid;
            $topUid = $user->valid_spread_uid;
        } else {
            $spreadUid = $user->valid_spread_uid;
            $topUid = $user->valid_top_uid;
        }
        $ex = systemConfig('extension_status');
        foreach ($cartInfo['list'] as $cart) {
            $totalNum += $cart['cart_num'];
            $giveCouponIds = array_merge($giveCouponIds, $cart['product']['give_coupon_ids']);
            $cost = bcadd(bcmul($cart['productPresellAttr']['cost'], $cart['cart_num'], 2), $cost, 2);

            if ($ex) {
                if ($spreadUid && $cart['productPresellAttr']['bc_extension_one'] > 0)
                    $total_extension_one = bcadd($total_extension_one, bcmul($cart['cart_num'], $cart['productPresellAttr']['bc_extension_one'], 2), 2);
                if ($topUid && $cart['productPresellAttr']['bc_extension_two'] > 0)
                    $total_extension_two = bcadd($total_extension_two, bcmul($cart['cart_num'], $cart['productPresellAttr']['bc_extension_two'], 2), 2);
            }
        }

        foreach ($cartInfo['coupon'] as $coupon) {
            if (isset($coupon['checked']) && $coupon['checked']) $useCoupon[] = $coupon['coupon_user_id'];
        }

        $merchantRepository = app()->make(MerchantRepository::class);
        $order = [
            'commission_rate' => (float)$merchantRepository->get($cartInfo['mer_id'])->mer_commission_rate,
            'order_type' => in_array($cartInfo['mer_id'], $takes) == 1 ? 1 : 0,
            'extension_one' => $total_extension_one,
            'extension_two' => $total_extension_two,
            'orderInfo' => $cartInfo['order'],
            'cartInfo' => $cartInfo['list'],
            'order_sn' => $this->getNewOrderId() . 0,
            'uid' => $uid,
            'is_selfbuy' => $isSelfBuy,
            'real_name' => $address['real_name'],
            'user_phone' => $address['phone'],
            'user_address' => $address['province'] . $address['city'] . $address['district'] . ' ' . $address['detail'],
            'cart_id' => implode(',', array_column($cartInfo['list'], 'cart_id')),
            'total_num' => $cartInfo['order']['total_num'],
            'total_price' => $cartInfo['order']['total_price'],
            'total_postage' => $cartInfo['order']['postage_price'],
            'pay_postage' => $cartInfo['order']['postage_price'],
            'pay_price' => $cartInfo['order']['pay_price'],
            'activity_type' => 2,
            'mer_id' => $cartInfo['mer_id'],
            'cost' => $cost,
            'coupon_id' => implode(',', $useCoupon),
            'mark' => $mark[$cartInfo['mer_id']] ?? '',
            'coupon_price' => $cartInfo['order']['coupon_price'] > $cartInfo['order']['total_price'] ? $cartInfo['order']['total_price'] : $cartInfo['order']['coupon_price'],
            'pay_type' => $pay_type
        ];

        $groupOrder = [
            'uid' => $uid,
            'group_order_sn' => $this->getNewOrderId() . '0',
            'total_postage' => $order['total_postage'],
            'total_price' => $order['total_price'],
            'total_num' => $totalNum,
            'real_name' => $address['real_name'],
            'user_phone' => $address['phone'],
            'user_address' => $address['province'] . $address['city'] . $address['district'] . ' ' . $address['detail'],
            'pay_price' => $order['pay_price'],
            'coupon_price' => $order['coupon_price'],
            'pay_postage' => $order['total_postage'],
            'cost' => $cost,
            'pay_type' => $pay_type,
            'give_coupon_ids' => $giveCouponIds
        ];

        $storeGroupOrderRepository = app()->make(StoreGroupOrderRepository::class);
        $storeCartRepository = app()->make(StoreCartRepository::class);
        $attrValueRepository = app()->make(ProductAttrValueRepository::class);
        $productRepository = app()->make(ProductRepository::class);
        $storeOrderProductRepository = app()->make(StoreOrderProductRepository::class);
        $productPresellSkuRepository = app()->make(ProductPresellSkuRepository::class);

        $group = Db::transaction(function () use ($receipt_data, $topUid, $spreadUid, $uid, $cartInfo, $useCoupon, $order, $productPresellSkuRepository, $couponUserRepository, $storeOrderProductRepository, $productRepository, $attrValueRepository, $storeCartRepository, $storeGroupOrderRepository, $groupOrder) {
            $cart = $cartInfo['list'][0];
            try {
                $productPresellSkuRepository->descStock($cart['productPresellAttr']['product_presell_id'], $cart['productPresellAttr']['unique'], $cart['cart_num']);
                $attrValueRepository->descStock($cart['productAttr']['product_id'], $cart['productAttr']['unique'], $cart['cart_num']);
                $productRepository->descStock($cart['product']['product_id'], $cart['cart_num']);
            } catch (Exception $e) {
                throw new ValidateException('库存不足');
            }

            //修改购物车状态
            $storeCartRepository->update($cart['cart_id'], [
                'is_pay' => 1
            ]);

            if (count($useCoupon)) {
                //使用优惠券
                $couponUserRepository->updates($useCoupon, [
                    'use_time' => date('Y-m-d H:i:s'),
                    'status' => 1
                ]);
            }
            $groupOrder = $storeGroupOrderRepository->create($groupOrder);
            $order['group_order_id'] = $groupOrder->group_order_id;
            $_order = $this->dao->create($order);
            $orderStatus = [
                'order_id' => $_order->order_id,
                'change_message' => '订单生成',
                'change_type' => 'create'
            ];

            $finalPrice = max(bcsub($cartInfo['order']['final_price'], $cartInfo['order']['coupon_price'], 2), 0);

            $allFinalPrice = $order['order_type'] ? $finalPrice : bcadd($finalPrice, $order['pay_postage'], 2);

            if ($cart['productPresell']['presell_type'] == 1) {
                $productPrice = bcsub($cartInfo['order']['pay_price'], $order['pay_postage'], 2);
            } else {
                $productPrice = bcadd($cartInfo['order']['pay_price'], $finalPrice, 2);
            }

            if (isset($receipt_data[$_order['mer_id']])) {
                app()->make(StoreOrderReceiptRepository::class)->add($receipt_data[$_order['mer_id']], $_order, $productPrice);
            }

            $orderProduct = [
                'order_id' => $_order->order_id,
                'cart_id' => $cart['cart_id'],
                'uid' => $uid,
                'product_id' => $cart['product_id'],
                'product_price' => $productPrice,
                'extension_one' => $spreadUid ? $cart['productPresellAttr']['bc_extension_one'] : 0,
                'extension_two' => $topUid ? $cart['productPresellAttr']['bc_extension_two'] : 0,
                'product_sku' => $cart['productAttr']['unique'],
                'product_num' => $cart['cart_num'],
                'product_type' => $cart['product_type'],
                'activity_id' => $cart['source_id'],
                'refund_num' => $cart['cart_num'],
                'cart_info' => json_encode([
                    'product' => $cart['product'],
                    'productAttr' => $cart['productAttr'],
                    'productPresell' => $cart['productPresell'],
                    'productPresellAttr' => $cart['productPresellAttr'],
                    'product_type' => $cart['product_type'],
                ])
            ];
            if ($cart['productPresell']['presell_type'] == 2) {
                $presellOrderRepository = app()->make(PresellOrderRepository::class);
                $presellOrderRepository->create([
                    'uid' => $uid,
                    'order_id' => $_order->order_id,
                    'mer_id' => $_order->mer_id,
                    'final_start_time' => $cart['productPresell']['final_start_time'],
                    'final_end_time' => $cart['productPresell']['final_end_time'],
                    'pay_price' => $allFinalPrice,
                    'presell_order_sn' => $presellOrderRepository->getNewOrderId()
                ]);
            }
            app()->make(ProductPresellSkuRepository::class)->incCount($cart['source_id'], $cart['productAttr']['unique'], 'one_take');
            $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class);
            $userMerchantRepository = app()->make(UserMerchantRepository::class);
            $userMerchantRepository->getInfo($uid, $order['mer_id']);
            app()->make(MerchantRepository::class)->incSales($order['mer_id'], $order['total_num']);
            $storeOrderStatusRepository->create($orderStatus);
            $storeOrderProductRepository->create($orderProduct);
            return $groupOrder;
        });
        queue::push(SendTemplateMessageJob::class, ['tempCode' => 'ORDER_CREATE', 'id' => $group->group_order_id]);
        return $group;
    }

    /**
     * @param User $user
     * @param int $pay_type
     * @param array $cartId
     * @param int $addressId
     * @param array $coupons
     * @param array $takes
     * @param array $mark
     * @param array $receipt_data
     * @return mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @author xaboy
     * @day 2020/11/2
     */
    public function createOrder(User $user, int $pay_type, array $cartId, int $addressId, array $coupons, array $takes, array $mark, array $receipt_data)
    {
        $uid = $user->uid;
        $couponUserRepository = app()->make(StoreCouponUserRepository::class);
        foreach ($coupons as $merId => $coupon) {
            if (!is_array($coupon)) {
                unset($coupons[$merId]);
                continue;
            }
            $storeCoupon = $coupon['store'] ?? ($coupon['store'] = 0);
            $productCoupon = array_unique($coupon['product'] ?? ($coupon['product'] = []));
            $_coupons = $storeCoupon ? array_merge($productCoupon, [$storeCoupon]) : $productCoupon;
            if (!count($_coupons)) {
                unset($coupons[$merId]);
                continue;
            }
            if (count($couponUserRepository->validIntersection($merId, $uid, $_coupons)) != count($_coupons))
                throw new ValidateException('请选择正确的优惠券');
        }
        $order = $this->cartIdByOrderInfo($uid, $takes, $cartId, $addressId, false);
        if ($order['status'] == 'noDeliver')
            throw new ValidateException('部分商品不支持该区域');
        if (!$order['address']) throw new ValidateException('请选择正确的收货地址');
        if ($order['order_type'] == '2') throw new ValidateException('预售商品请单独购买');
        if ($order['order_type']) $coupons = [];
        $orderPrice = 0;
        $orderInfo = $order['order'];
        $address = $order['address'];
        $orderList = [];
        $totalPostage = 0;
        $totalPayPrice = 0;
        $totalCouponPrice = 0;
        $totalNum = 0;
        $totalCost = 0;
        $allUseCoupon = [];
        $productCouponList = [];
        $storeCouponList = [];
        $isSelfBuy = $user->is_promoter && systemConfig('extension_self') ? 1 : 0;
        if ($isSelfBuy) {
            $spreadUid = $user->uid;
            $topUid = $user->valid_spread_uid;
        } else {
            $spreadUid = $user->valid_spread_uid;
            $topUid = $user->valid_top_uid;
        }
        $giveCouponIds = [];
        $merchantRepository = app()->make(MerchantRepository::class);
        $ex = systemConfig('extension_status');

        foreach ($orderInfo as $k => $cartInfo) {

            if (in_array($cartInfo['mer_id'], $takes) && !$cartInfo['take']['mer_take_status'])
                throw new ValidateException('该店铺不支持到店自提');

            if (isset($receipt_data[$cartInfo['mer_id']]) && !$cartInfo['openReceipt'])
                throw new ValidateException('该店铺不支持开发票');

            $useCoupon = [];
            if (isset($coupons[$cartInfo['mer_id']])) {
                $coupon = $coupons[$cartInfo['mer_id']];
                if (count($coupon['product'])) {
                    foreach ($cartInfo['coupon'] as $_k => $_coupon) {
                        if (!$_coupon['coupon']['type']) continue;
                        if (in_array($_coupon['coupon_user_id'], $coupon['product'])) {
                            $productId = array_search($_coupon['coupon_user_id'], $coupon['product']);
                            if (!in_array($productId, array_column($_coupon['product'], 'product_id')))
                                throw new ValidateException('请选择正确的优惠券');
                            $useCoupon[] = $_coupon['coupon_user_id'];
                            unset($coupon['product'][$productId]);
                            $productCouponList[$productId] = [
                                'rate' => $cartInfo['order']['product_price'][$productId] > 0 ? bcdiv($_coupon['coupon_price'], $cartInfo['order']['product_price'][$productId], 4) : 1,
                                'coupon_price' => $_coupon['coupon_price'],
                                'price' => $cartInfo['order']['product_price'][$productId]
                            ];
                            $cartInfo['order']['pay_price'] = max(bcsub($cartInfo['order']['pay_price'], $_coupon['coupon_price'], 2), 0);
                            $cartInfo['order']['coupon_price'] = bcadd($cartInfo['order']['coupon_price'], $_coupon['coupon_price'], 2);
                        }
                    }
                    if (count($coupon['product'])) throw new ValidateException('请选择正确的优惠券');
                }
                if ($coupon['store']) {
                    $flag = false;
                    foreach ($cartInfo['coupon'] as $_coupon) {
                        if ($_coupon['coupon']['type']) continue;
                        if ($_coupon['coupon_user_id'] == $coupon['store']) {
                            $flag = true;
                            $useCoupon[] = $_coupon['coupon_user_id'];
                            $storeCouponList[$cartInfo['mer_id']] = [
                                'rate' => $cartInfo['order']['pay_price'] > 0 ? bcdiv($_coupon['coupon_price'], $cartInfo['order']['pay_price'], 4) : 1,
                                'coupon_price' => $_coupon['coupon_price'],
                                'price' => $cartInfo['order']['coupon_price']
                            ];
                            $cartInfo['order']['pay_price'] = max(bcsub($cartInfo['order']['pay_price'], $_coupon['coupon_price'], 2), 0);
                            $cartInfo['order']['coupon_price'] = bcadd($cartInfo['order']['coupon_price'], $_coupon['coupon_price'], 2);
                            break;
                        }
                    }
                    if (!$flag) throw new ValidateException('请选择正确的优惠券');
                }
            }
            $cost = 0;
            $total_extension_one = 0;
            $total_extension_two = 0;
            foreach ($cartInfo['list'] as $cart) {
                $totalNum += $cart['cart_num'];
                $giveCouponIds = array_merge($giveCouponIds, $cart['product']['give_coupon_ids']);
                $cost = bcadd(bcmul($cart['productAttr']['cost'], $cart['cart_num'], 2), $cost, 2);
                if ($ex && !$cart['product_type']) {
                    if ($spreadUid && $cart['productAttr']['bc_extension_one'] > 0)
                        $total_extension_one = bcadd($total_extension_one, bcmul($cart['cart_num'], $cart['productAttr']['bc_extension_one'], 2), 2);
                    if ($topUid && $cart['productAttr']['bc_extension_two'] > 0)
                        $total_extension_two = bcadd($total_extension_two, bcmul($cart['cart_num'], $cart['productAttr']['bc_extension_two'], 2), 2);
                }
            }
            if (in_array($cartInfo['mer_id'], $takes)) {
                $cartInfo['order']['pay_price'] = max(bcsub($cartInfo['order']['pay_price'], $cartInfo['order']['postage_price'], 2), 0);
                $cartInfo['order']['postage_price'] = 0;
            } else {
                $cartInfo['order']['pay_price'] = max($cartInfo['order']['pay_price'], $cartInfo['order']['postage_price']);
            }

            //TODO 生成订单

            $_order = [
                'activity_type' => $order['order_type'],
                'commission_rate' => (float)$merchantRepository->get($cartInfo['mer_id'])->mer_commission_rate,
                'order_type' => in_array($cartInfo['mer_id'], $takes) == 1 ? 1 : 0,
                'extension_one' => $total_extension_one,
                'extension_two' => $total_extension_two,
                'orderInfo' => $cartInfo['order'],
                'cartInfo' => $cartInfo['list'],
                'order_sn' => $this->getNewOrderId() . ($k + 1),
                'uid' => $uid,
                'is_selfbuy' => $isSelfBuy,
                'real_name' => $address['real_name'],
                'user_phone' => $address['phone'],
                'user_address' => $address['province'] . $address['city'] . $address['district'] . ' ' . $address['detail'],
                'cart_id' => implode(',', array_column($cartInfo['list'], 'cart_id')),
                'total_num' => $cartInfo['order']['total_num'],
                'total_price' => $cartInfo['order']['total_price'],
                'total_postage' => $cartInfo['order']['postage_price'],
                'pay_postage' => $cartInfo['order']['postage_price'],
                'pay_price' => $cartInfo['order']['pay_price'],
                'mer_id' => $cartInfo['mer_id'],
                'cost' => $cost,
                'coupon_id' => implode(',', $useCoupon),
                'mark' => $mark[$cartInfo['mer_id']] ?? '',
                'coupon_price' => $cartInfo['order']['coupon_price'] > $cartInfo['order']['total_price'] ? $cartInfo['order']['total_price'] : $cartInfo['order']['coupon_price'],
                'pay_type' => $pay_type
            ];
            $allUseCoupon = array_merge($allUseCoupon, $useCoupon);
            $orderList[] = $_order;
            $orderInfo[$k] = $cartInfo;
            $orderPrice = bcadd($orderPrice, $_order['total_price'], 2);
            $totalPostage = bcadd($totalPostage, $_order['total_postage'], 2);
            $totalPayPrice = bcadd($totalPayPrice, $_order['pay_price'], 2);
            $totalCouponPrice = bcadd($totalCouponPrice, $_order['coupon_price'], 2);
            $totalCost = bcadd($totalCost, $cost, 2);
        }
        $groupOrder = [
            'uid' => $uid,
            'group_order_sn' => $this->getNewOrderId() . '0',
            'total_postage' => $totalPostage,
            'total_price' => $orderPrice,
            'total_num' => $totalNum,
            'real_name' => $address['real_name'],
            'user_phone' => $address['phone'],
            'user_address' => $address['province'] . $address['city'] . $address['district'] . ' ' . $address['detail'],
            'pay_price' => $totalPayPrice,
            'coupon_price' => $totalCouponPrice,
            'pay_postage' => $totalPostage,
            'cost' => $totalCost,
            'pay_type' => $pay_type,
            'give_coupon_ids' => $giveCouponIds
        ];
        $storeGroupOrderRepository = app()->make(StoreGroupOrderRepository::class);
        $storeCartRepository = app()->make(StoreCartRepository::class);
        $attrValueRepository = app()->make(ProductAttrValueRepository::class);
        $productRepository = app()->make(ProductRepository::class);
        $storeOrderProductRepository = app()->make(StoreOrderProductRepository::class);

        $group = Db::transaction(function () use ($topUid, $spreadUid, $uid, $receipt_data, $productCouponList, $storeCouponList, $allUseCoupon, $couponUserRepository, $storeOrderProductRepository, $productRepository, $attrValueRepository, $storeCartRepository, $storeGroupOrderRepository, $groupOrder, $orderList, $orderInfo) {
            $cartIds = [];
            $uniqueList = [];
            //更新库存
            foreach ($orderInfo as $cartInfo) {
                $cartIds = array_merge($cartIds, array_column($cartInfo['list'], 'cart_id'));
                foreach ($cartInfo['list'] as $cart) {
                    if (!isset($uniqueList[$cart['productAttr']['product_id'] . $cart['productAttr']['unique']]))
                        $uniqueList[$cart['productAttr']['product_id'] . $cart['productAttr']['unique']] = true;
                    else
                        throw new ValidateException('购物车商品信息重复');

                    try {
                        if ($cart['product_type'] == '1') {
                            $attrValueRepository->descSkuStock($cart['product']['old_product_id'], $cart['productAttr']['sku'], $cart['cart_num']);
                            $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']);
                        } else if ($cart['product_type'] == '3') {
                            app()->make(ProductAssistSkuRepository::class)->descStock($cart['productAssistAttr']['product_assist_id'], $cart['productAssistAttr']['unique'], $cart['cart_num']);
                            $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']);
                            $attrValueRepository->descStock($cart['product']['old_product_id'], $cart['productAttr']['unique'], $cart['cart_num']);
                        } else if ($cart['product_type'] == '4') {
                            app()->make(ProductGroupSkuRepository::class)->descStock($cart['activeSku']['product_group_id'], $cart['activeSku']['unique'], $cart['cart_num']);
                            $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']);
                            $attrValueRepository->descStock($cart['product']['old_product_id'], $cart['productAttr']['unique'], $cart['cart_num']);
                        } else {
                            $attrValueRepository->descStock($cart['productAttr']['product_id'], $cart['productAttr']['unique'], $cart['cart_num']);
                            $productRepository->descStock($cart['product']['product_id'], $cart['cart_num']);
                        }
                    } catch (Exception $e) {
                        throw new ValidateException('库存不足');
                    }
                }
            }
            //修改购物车状态
            $storeCartRepository->updates($cartIds, [
                'is_pay' => 1
            ]);
            //使用优惠券
            if (count($allUseCoupon)) {
                $couponUserRepository->updates($allUseCoupon, [
                    'use_time' => date('Y-m-d H:i:s'),
                    'status' => 1
                ]);
            }
            $groupOrder = $storeGroupOrderRepository->create($groupOrder);
            foreach ($orderList as $k => $order) {
                $orderList[$k]['group_order_id'] = $groupOrder->group_order_id;
            }
            $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class);
            $orderProduct = [];
            $orderStatus = [];
            $userMerchantRepository = app()->make(UserMerchantRepository::class);
            foreach ($orderList as $order) {
                $cartInfo = $order['cartInfo'];
                $_orderInfo = $order['orderInfo'];
                unset($order['cartInfo'], $order['orderInfo']);
                $_order = $this->dao->create($order);
                if (isset($receipt_data[$_order['mer_id']])) {
                    app()->make(StoreOrderReceiptRepository::class)->add($receipt_data[$_order['mer_id']], $_order);
                }

                $orderStatus[] = [
                    'order_id' => $_order->order_id,
                    'change_message' => '订单生成',
                    'change_type' => 'create'
                ];

                foreach ($cartInfo as $k => $cart) {
                    $cartTotalPrice = bcmul($this->cartByPrice($cart), $cart['cart_num'], 2);
                    if (!$cart['product_type'] && $cartTotalPrice > 0 && isset($productCouponList[$cart['product_id']])) {
                        if ($productCouponList[$cart['product_id']]['rate'] >= 1) {
                            $cartTotalPrice = 0;
                        } else {
                            array_pop($_orderInfo['product_cart']);
                            if (!count($_orderInfo['product_cart'])) {
                                $cartTotalPrice = bcsub($cartTotalPrice, $productCouponList[$cart['product_id']]['coupon_price'], 2);
                            } else {
                                $couponPrice = bcmul($cartTotalPrice, $productCouponList[$cart['product_id']]['rate'], 2);
                                $cartTotalPrice = bcsub($cartTotalPrice, $couponPrice, 2);
                                $productCouponList[$cart['product_id']]['coupon_price'] = bcsub($productCouponList[$cart['product_id']]['coupon_price'], $couponPrice, 2);
                            }
                        }
                    }

                    if (!$cart['product_type'] && $cartTotalPrice > 0 && isset($storeCouponList[$order['mer_id']])) {
                        if ($storeCouponList[$order['mer_id']]['rate'] >= 1) {
                            $cartTotalPrice = 0;
                        } else {
                            if (count($cartInfo) == $k + 1) {
                                $cartTotalPrice = bcsub($cartTotalPrice, $storeCouponList[$order['mer_id']]['coupon_price'], 2);
                            } else {
                                $couponPrice = bcmul($cartTotalPrice, $storeCouponList[$order['mer_id']]['rate'], 2);
                                $cartTotalPrice = bcsub($cartTotalPrice, $couponPrice, 2);
                                $storeCouponList[$order['mer_id']]['coupon_price'] = bcsub($storeCouponList[$order['mer_id']]['coupon_price'], $couponPrice, 2);
                            }
                        }
                    }

                    $cartTotalPrice = max($cartTotalPrice, 0);

                    $info = [];
                    if ($cart['product_type'] == '3') {
                        $info = [
                            'productAssistAttr' => $cart['productAssistAttr'],
                            'productAssistSet' => $cart['productAssistSet'],
                        ];
                    } else if ($cart['product_type'] == '4') {
                        $info = [
                            'activeSku' => $cart['activeSku']
                        ];
                    }

                    $orderProduct[] = [
                        'order_id' => $_order->order_id,
                        'cart_id' => $cart['cart_id'],
                        'uid' => $uid,
                        'product_id' => $cart['product_id'],
                        'activity_id' => $cart['source'] >= 3 ? $cart['source_id'] : $cart['product_id'],
                        'product_price' => $cartTotalPrice,
                        'extension_one' => $spreadUid ? $cart['productAttr']['bc_extension_one'] : 0,
                        'extension_two' => $topUid ? $cart['productAttr']['bc_extension_two'] : 0,
                        'product_sku' => $cart['productAttr']['unique'],
                        'product_num' => $cart['cart_num'],
                        'refund_num' => $cart['cart_num'],
                        'product_type' => $cart['product_type'],
                        'cart_info' => json_encode([
                                'product' => $cart['product'],
                                'productAttr' => $cart['productAttr'],
                                'product_type' => $cart['product_type']
                            ] + $info)
                    ];
                }
                $userMerchantRepository->getInfo($uid, $order['mer_id']);
                app()->make(MerchantRepository::class)->incSales($order['mer_id'], $order['total_num']);
            }
            $storeOrderStatusRepository->insertAll($orderStatus);
            $storeOrderProductRepository->insertAll($orderProduct);
            return $groupOrder;
        });
        foreach ($orderInfo as $cartInfo) {
            foreach ($cartInfo['list'] as $cart) {
                if (($cart['productAttr']['stock'] - $cart['cart_num']) < (int)merchantConfig($cartInfo['mer_id'], 'mer_store_stock')) {
                    SwooleTaskService::merchant('notice', [
                        'type' => 'min_stock',
                        'data' => [
                            'title' => '库存不足',
                            'message' => $cart['product']['store_name'] . '(' . $cart['productAttr']['sku'] . ')库存不足',
                            'id' => $cart['product']['product_id']
                        ]
                    ], $cartInfo['mer_id']);
                }
            }
        }
        queue::push(SendTemplateMessageJob::class, ['tempCode' => 'ORDER_CREATE', 'id' => $group->group_order_id]);
        return $group;
    }

    /**
     * @param string $type
     * @param User $user
     * @param StoreGroupOrder $groupOrder
     * @param string $return_url
     * @return mixed
     * @author xaboy
     * @day 2020/10/22
     */
    public function pay(string $type, User $user, StoreGroupOrder $groupOrder, $return_url = '', $isApp = false)
    {

        if ($type === 'balance') {
            return $this->payBalance($user, $groupOrder);
        }

        if (in_array($type, ['weixin', 'alipay'], true) && $isApp) {
            $type .= 'App';
        }

        if (in_array($type, ['weixin', 'weixinApp', 'routine', 'h5', 'weixinQr'], true) && systemConfig('open_wx_combine')) {
            $service = new CombinePayService($type, $groupOrder->getCombinePayParams());
        } else {
            $service = new PayService($type, $groupOrder->getPayParams($type === 'alipay' ? $return_url : ''));
        }
        $config = $service->pay($user);
        return app('json')->status($type, $config + ['order_id' => $groupOrder['group_order_id']]);
    }

    /**
     * @param User $user
     * @param StoreGroupOrder $groupOrder
     * @return mixed
     * @author xaboy
     * @day 2020/6/9
     */
    public function payBalance(User $user, StoreGroupOrder $groupOrder)
    {
        if (!systemConfig('yue_pay_status'))
            throw new ValidateException('未开启余额支付');
        if ($user['now_money'] < $groupOrder['pay_price'])
            throw new ValidateException('余额不足' . floatval($groupOrder['pay_price']));
        Db::transaction(function () use ($user, $groupOrder) {
            $user->now_money = bcsub($user->now_money, $groupOrder['pay_price'], 2);
            $user->save();
            $userBillRepository = app()->make(UserBillRepository::class);
            $userBillRepository->decBill($user['uid'], 'now_money', 'pay_product', [
                'link_id' => $groupOrder['group_order_id'],
                'status' => 1,
                'title' => '购买商品',
                'number' => $groupOrder['pay_price'],
                'mark' => '余额支付支付' . floatval($groupOrder['pay_price']) . '元购买商品',
                'balance' => $user->now_money
            ]);
            $this->paySuccess($groupOrder);
        });
        return app('json')->status('success', '余额支付成功', ['order_id' => $groupOrder['group_order_id']]);
    }

    public function changePayType(StoreGroupOrder $groupOrder, int $pay_type)
    {
        Db::transaction(function () use ($groupOrder, $pay_type) {
            $groupOrder->pay_type = $pay_type;
            foreach ($groupOrder->orderList as $order) {
                $order->pay_type = $pay_type;
                $order->save();
            }
            $order->save();
        });
    }

    /**
     * @return string
     * @author xaboy
     * @day 2020/8/3
     */
    public function verifyCode()
    {
        $code = substr(uniqid('', true), 15) . substr(microtime(), 2, 8);
        if ($this->dao->existsWhere(['verify_code' => $code]))
            return $this->verifyCode();
        else
            return $code;
    }

    /**
     * //TODO 支付成功后
     *
     * @param StoreGroupOrder $groupOrder
     * @author xaboy
     * @day 2020/6/9
     */
    public function paySuccess(StoreGroupOrder $groupOrder, $is_combine = 0, $subOrders = [])
    {
        $groupOrder->append(['user']);
        //修改订单状态
        Db::transaction(function () use ($subOrders, $is_combine, $groupOrder) {
            $time = date('Y-m-d H:i:s');
            $groupOrder->paid = 1;
            $groupOrder->pay_time = $time;
            $groupOrder->is_combine = $is_combine;
            $orderStatus = [];
            $groupOrder->append(['orderList.orderProduct']);
            $flag = true;
            $finance = [];
            $profitsharing = [];
            $financialRecordRepository = app()->make(FinancialRecordRepository::class);
            $financeSn = $financialRecordRepository->getSn();
            $userMerchantRepository = app()->make(UserMerchantRepository::class);
            $storeOrderProfitsharingRepository = app()->make(StoreOrderProfitsharingRepository::class);
            $uid = $groupOrder->uid;
            $i = 1;
            foreach ($groupOrder->orderList as $_k => $order) {
                $order->paid = 1;
                $order->pay_time = $time;
                if (isset($subOrders[$order->order_sn])) {
                    $order->transaction_id = $subOrders[$order->order_sn]['transaction_id'];
                }
                $presell = false;
                //todo 等待付尾款
                if ($order->activity_type == 2) {
                    $_make = app()->make(ProductPresellSkuRepository::class);
                    if ($order->orderProduct[0]['cart_info']['productPresell']['presell_type'] == 2) {
                        $order->status = 10;
                        $presell = true;
                    } else {
                        $_make->incCount($order->orderProduct[0]['activity_id'], $order->orderProduct[0]['product_sku'], 'two_pay');
                    }
                    $_make->incCount($order->orderProduct[0]['activity_id'], $order->orderProduct[0]['product_sku'], 'one_pay');
                } else if ($order->activity_type == 4) {
                    $order->status = 9;
                    $order->save();
                    $group_buying_id = app()->make(ProductGroupBuyingRepository::class)->create(
                        $groupOrder->user,
                        $order->orderProduct[0]['cart_info']['activeSku']['product_group_id'],
                        $order->orderProduct[0]['activity_id'],
                        $order->order_id
                    );
                    $order->orderProduct[0]->activity_id = $group_buying_id;
                    $order->orderProduct[0]->save();
                } else if ($order->activity_type == 3) {
                    //更新助力状态
                    app()->make(ProductAssistSetRepository::class)->changStatus($order->orderProduct[0]['activity_id']);
                }
                if ($order->order_type == 1 && $order->status != 10)
                    $order->verify_code = $this->verifyCode();
                $order->save();
                $orderStatus[] = [
                    'order_id' => $order->order_id,
                    'change_message' => '订单支付成功',
                    'change_type' => 'pay_success'
                ];

                //TODO 成为推广员
                foreach ($order->orderProduct as $product) {
                    if ($flag && $product['cart_info']['product']['is_gift_bag']) {
                        app()->make(UserRepository::class)->promoter($order->uid);
                        $flag = false;
                    }
                }

                $finance[] = [
                    'order_id' => $order->order_id,
                    'order_sn' => $order->order_sn,
                    'user_info' => $groupOrder->user->nickname,
                    'user_id' => $uid,
                    'financial_type' => $presell ? 'order_presell' : 'order',
                    'financial_pm' => 1,
                    'type' => $presell ? 2 : 1,
                    'number' => $order->pay_price,
                    'mer_id' => $order->mer_id,
                    'financial_record_sn' => $financeSn . ($i++)
                ];

                $_payPrice = bcsub($order->pay_price, bcadd($order['extension_one'], $order['extension_two'], 3), 2);
                if ($presell) {
                    if (isset($order->orderProduct[0]['cart_info']['presell_extension_one']) && $order->orderProduct[0]['cart_info']['presell_extension_one'] > 0) {
                        $_payPrice = bcadd($_payPrice, $order->orderProduct[0]['cart_info']['presell_extension_one'], 2);
                    }
                    if (isset($order->orderProduct[0]['cart_info']['presell_extension_two']) && $order->orderProduct[0]['cart_info']['presell_extension_two'] > 0) {
                        $_payPrice = bcadd($_payPrice, $order->orderProduct[0]['cart_info']['presell_extension_two'], 2);
                    }
                }

                $_order_rate = 0;

                if ($order['commission_rate'] > 0) {

                    $commission_rate = ($order['commission_rate'] / 100);

                    $_order_rate = bcmul($_payPrice, $commission_rate, 2);

                    $_payPrice = bcsub($_payPrice, $_order_rate, 2);
                }

                if (!$presell) {
                    if ($order['extension_one'] > 0) {
                        $finance[] = [
                            'order_id' => $order->order_id,
                            'order_sn' => $order->order_sn,
                            'user_info' => $groupOrder->user->nickname,
                            'user_id' => $uid,
                            'financial_type' => 'brokerage_one',
                            'financial_pm' => 0,
                            'type' => 1,
                            'number' => $order['extension_one'],
                            'mer_id' => $order->mer_id,
                            'financial_record_sn' => $financeSn . ($i++)
                        ];
                    }

                    if ($order['extension_two'] > 0) {
                        $finance[] = [
                            'order_id' => $order->order_id,
                            'order_sn' => $order->order_sn,
                            'user_info' => $groupOrder->user->nickname,
                            'user_id' => $uid,
                            'financial_type' => 'brokerage_two',
                            'financial_pm' => 0,
                            'type' => 1,
                            'number' => $order['extension_two'],
                            'mer_id' => $order->mer_id,
                            'financial_record_sn' => $financeSn . ($i++)
                        ];
                    }

                    if ($order['commission_rate'] > 0) {
                        $finance[] = [
                            'order_id' => $order->order_id,
                            'order_sn' => $order->order_sn,
                            'user_info' => $groupOrder->user->nickname,
                            'user_id' => $uid,
                            'financial_type' => 'order_charge',
                            'financial_pm' => 0,
                            'type' => 1,
                            'number' => $_order_rate,
                            'mer_id' => $order->mer_id,
                            'financial_record_sn' => $financeSn . ($i++)
                        ];
                    }
                    $finance[] = [
                        'order_id' => $order->order_id,
                        'order_sn' => $order->order_sn,
                        'user_info' => $groupOrder->user->nickname,
                        'user_id' => $uid,
                        'financial_type' => 'order_true',
                        'financial_pm' => 0,
                        'type' => 2,
                        'number' => $_payPrice,
                        'mer_id' => $order->mer_id,
                        'financial_record_sn' => $financeSn . ($i++)
                    ];
                    if (!$is_combine) {
                        app()->make(MerchantRepository::class)->addLockMoney($order->mer_id, 'order', $order->order_id, $_payPrice);
//                        app()->make(MerchantRepository::class)->addMoney($order->mer_id, $_payPrice);
                    }
                }
                if ($is_combine) {
                    $profitsharing[] = [
                        'profitsharing_sn' => $storeOrderProfitsharingRepository->getOrderSn(),
                        'order_id' => $order->order_id,
                        'transaction_id' => $order->transaction_id ?? '',
                        'mer_id' => $order->mer_id,
                        'profitsharing_price' => $order->pay_price,
                        'profitsharing_mer_price' => $_payPrice,
                        'type' => 'order'
                    ];
                }
                $userMerchantRepository->updatePayTime($uid, $order->mer_id, $order->pay_price);
                SwooleTaskService::merchant('notice', [
                    'type' => 'new_order',
                    'data' => [
                        'title' => '新订单',
                        'message' => '您有一个新的订单',
                        'id' => $order->order_id
                    ]
                ], $order->mer_id);
                //自动打印订单
                $this->autoPrinter($order->order_id, $order->mer_id);
            }
            if ($groupOrder->user->spread_uid) {
                Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->user->spread_uid, 'type' => 'spread_pay_num', 'inc' => 1]);
                Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->user->spread_uid, 'type' => 'spread_money', 'inc' => $groupOrder->pay_price]);
            }
            app()->make(UserRepository::class)->update($groupOrder->uid, [
                'pay_count' => Db::raw('pay_count+' . count($groupOrder->orderList)),
                'pay_price' => Db::raw('pay_price+' . $groupOrder->pay_price),
            ]);
            $this->giveIntegral($groupOrder);
            if (count($profitsharing)) {
                $storeOrderProfitsharingRepository->insertAll($profitsharing);
            }
            $financialRecordRepository->insertAll($finance);
            app()->make(StoreOrderStatusRepository::class)->insertAll($orderStatus);
            if (count($groupOrder['give_coupon_ids']) > 0)
                $groupOrder['give_coupon_ids'] = app()->make(StoreCouponRepository::class)->getGiveCoupon($groupOrder['give_coupon_ids'])->column('coupon_id');
            $groupOrder->save();
        });

        if (count($groupOrder['give_coupon_ids']) > 0) {
            try {
                Queue::push(PayGiveCouponJob::class, ['ids' => $groupOrder['give_coupon_ids'], 'uid' => $groupOrder['uid']]);
            } catch (Exception $e) {
            }
        }

        queue::push(SendTemplateMessageJob::class, [
            'tempCode' => 'ORDER_PAY_SUCCESS',
            'id' => $groupOrder->group_order_id
        ]);
        Queue::push(SendSmsJob::class, [
            'tempId' => 'PAY_SUCCESS_CODE',
            'id' => $groupOrder->group_order_id
        ]);
        Queue::push(SendSmsJob::class, [
            'tempId' => 'ADMIN_PAY_SUCCESS_CODE',
            'id' => $groupOrder->group_order_id
        ]);

        Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->uid, 'type' => 'pay_money', 'inc' => $groupOrder->pay_price]);
        Queue::push(UserBrokerageLevelJob::class, ['uid' => $groupOrder->uid, 'type' => 'pay_num', 'inc' => 1]);
    }

    /**
     *  自动打印
     * @Author:Qinii
     * @Date: 2020/10/13
     * @param int $orderId
     * @param int $merId
     */
    public function autoPrinter(int $orderId, int $merId)
    {
        if (merchantConfig($merId, 'printing_auto_status')) {
            try {
                $this->printer($orderId, $merId);
            } catch (Exception $exception) {
                Log::info('自动打印小票报错：' . $exception);
            }
        } else {
            Log::info('自动打印小票验证：【' . $merId . '】' . merchantConfig($merId, 'printing_auto_status'));
        }
    }

    /**
     * @return string
     * @author xaboy
     * @day 2020/6/9
     */
    public function getNewOrderId()
    {
        list($msec, $sec) = explode(' ', microtime());
        $msectime = number_format((floatval($msec) + floatval($sec)) * 1000, 0, '', '');
        $orderId = 'wx' . $msectime . mt_rand(10000, max(intval($msec * 10000) + 10000, 98369));
        return $orderId;
    }

    /**
     * @param $uid
     * @param array $takes
     * @param array $cartId
     * @param int|null $addressId
     * @param bool $confirm
     * @param null $useCoupon
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @author xaboy
     * @day 2020/11/6
     */
    public function cartIdByOrderInfo($uid, array $takes, array $cartId, int $addressId = null, $confirm = true, $useCoupon = null)
    {
        $address = null;
        if ($addressId) {
            $addressRepository = app()->make(UserAddressRepository::class);
            $address = $addressRepository->getWhere(['uid' => $uid, 'address_id' => $addressId]);
            if (!$address['city_id'])
                throw new ValidateException('请选择正确的收货地址');
        }
        $storeCartRepository = app()->make(StoreCartRepository::class);
        $res = $storeCartRepository->checkCartList($storeCartRepository->cartIbByData($cartId, $uid, $address));
        $merchantInfo = $res['list'];
        $fail = $res['fail'];

        if (count($fail)) {
            if ($fail[0]['is_fail'])
                throw new ValidateException($fail[0]['product']['store_name'] . ' 已失效');
            if (in_array($fail[0]['product_type'], [1, 2, 3]) && !$fail[0]['userPayCount']) {
                throw new ValidateException($fail[0]['product']['store_name'] . ' 已超出购买限制');
            }
            throw new ValidateException($fail[0]['product']['store_name'] . ' 已失效');
        }

        foreach ($merchantInfo as $cart) {
            foreach ($cart['list'] as $item) {
                if ($item['product_type'] > 0 && (count($cart['list']) != 1 || count($merchantInfo) != 1)) {
                    throw new ValidateException('活动商品必须单独购买');
                }
            }
        }

        $merchantTakeRepository = app()->make(MerchantTakeRepository::class);
        $order_price = 0;
        $order_total_price = 0;
        $noDeliver = false;
        $order_type = 0;
        $presellType = 0;
        $fn = [];
        foreach ($merchantInfo as $k => $cartInfo) {
            $postageRule = [];
            $total_price = 0;
            $total_num = 0;
            $valid_total_price = 0;
            $postage_price = 0;
            $product_price = [];
            $final_price = 0;
            $down_price = 0;

            //TODO 计算邮费
            foreach ($cartInfo['list'] as $_k => $cart) {

                if ($cart['product_type'] > 0) $order_type = $cart['product_type'];

                if ($cart['product_type'] == 2) {
                    $cart->append(['productPresell', 'productPresellAttr']);
                    $final_price = bcadd($final_price, bcmul($cart['cart_num'], $cart['productPresellAttr']['final_price'], 2), 2);
                    if ($cart['productPresell']['presell_type'] == 2)
                        $down_price = bcadd($down_price, bcmul($cart['cart_num'], $cart['productPresellAttr']['down_price'], 2), 2);
                    $presellType = $cart['productPresell']['presell_type'];
                } else if ($cart['product_type'] == 3) {
                    $cart->append(['productAssistAttr']);
                } else if ($cart['product_type'] == 4) {
                    $cart->append(['activeSku']);
                }

                $price = bcmul($cart['cart_num'], $this->cartByPrice($cart), 2);
                $total_price = bcadd($total_price, $price, 2);
                $total_num += $cart['cart_num'];
                $_price = bcmul($cart['cart_num'], $this->cartByCouponPrice($cart), 2);
                if ($_price > 0) {
                    $product_price[$cart['product_id']] = bcadd($product_price[$cart['product_id']] ?? 0, $_price, 2);
                    $valid_total_price = bcadd($valid_total_price, $_price, 2);
                }
                if (!isset($product_cart[$cart['product_id']]))
                    $product_cart[$cart['product_id']] = [$cart['cart_id']];
                else
                    $product_cart[$cart['product_id']][] = $cart['cart_id'];
                if (!$address || !$cart['product']['temp']) {
                    $cartInfo['list'][$_k]['undelivered'] = true;
                    $noDeliver = true;
                    continue;
                }
                $temp1 = $cart['product']['temp'];
                $cart['undelivered'] = (!in_array($cartInfo['mer_id'], $takes)) && $temp1['undelivery'] && isset($temp1['undelives']);
                $free = $temp1['free'][0] ?? null;
                $region = $temp1['region'][0] ?? null;
                $fn[] = function () use ($cartInfo, $_k) {
                    unset($cartInfo['list'][$_k]['product']['temp']);
                };
                $cartInfo['list'][$_k] = $cart;

                if ($cart['undelivered']) {
                    $noDeliver = true;
                    continue;
                }

                if (!isset($postageRule[$cart['product']['temp_id']])) {
                    $postageRule[$cart['product']['temp_id']] = [
                        'free' => null,
                        'region' => null
                    ];
                }
                $number = $this->productByTempNumber($cart);
                $freeRule = $postageRule[$cart['product']['temp_id']]['free'];
                $regionRule = $postageRule[$cart['product']['temp_id']]['region'];
                if ($temp1['appoint'] && $free) {
                    if (!isset($freeRule)) {
                        $freeRule = $free;
                        $freeRule['cart_price'] = 0;
                        $freeRule['cart_number'] = 0;
                    }
                    $freeRule['cart_number'] = bcadd($freeRule['cart_number'], $number, 2);
                    $freeRule['cart_price'] = bcadd($freeRule['cart_price'], $price, 2);
                }

                if ($region) {
                    if (!isset($regionRule)) {
                        $regionRule = $region;
                        $regionRule['cart_price'] = 0;
                        $regionRule['cart_number'] = 0;
                    }
                    $regionRule['cart_number'] = bcadd($regionRule['cart_number'], $number, 2);
                    $regionRule['cart_price'] = bcadd($regionRule['cart_price'], $price, 2);
                }
                $postageRule[$cart['product']['temp_id']]['free'] = $freeRule;
                $postageRule[$cart['product']['temp_id']]['region'] = $regionRule;
            }

            foreach ($postageRule as $item) {
                $freeRule = $item['free'];
                if ($freeRule && $freeRule['cart_number'] >= $freeRule['number'] && $freeRule['cart_price'] >= $freeRule['price'])
                    continue;
                if (!$item['region']) continue;
                $regionRule = $item['region'];
                $postage = $regionRule['first_price'];
                if ($regionRule['first'] > 0 && $regionRule['cart_number'] > $regionRule['first']) {
                    $num = ceil(bcdiv(bcsub($regionRule['cart_number'], $regionRule['first'], 2), $regionRule['continue'], 2));
                    $postage = bcadd($postage, bcmul($num, $regionRule['continue_price'], 2), 2);
                }
                $postage_price = bcadd($postage_price, $postage, 2);
            }
            $coupon_price = 0;
            $use_coupon_product = [];
            $use_store_coupon = 0;
            foreach ($cartInfo['coupon'] as $__k => $coupon) {
                if (!$coupon['coupon']['type']) continue;
                if (!is_null($useCoupon)) {
                    if (isset($useCoupon[$cartInfo['mer_id']])) {
                        $productCoupon = $useCoupon[$cartInfo['mer_id']]['product'] ?? [];
                        if (!count($productCoupon) || !in_array($coupon['coupon_user_id'], $productCoupon))
                            continue;
                    } else {
                        continue;
                    }
                }
                //商品券
                if (count(array_intersect(array_column($coupon['product'], 'product_id'), array_keys($product_price))) == 0) {
                    unset($cartInfo['coupon'][$__k]);
                    continue;
                }
                $flag = false;
                foreach ($coupon['product'] as $_product) {
                    if (isset($product_price[$_product['product_id']]) && $product_price[$_product['product_id']] >= $coupon['use_min_price']) {
                        $flag = true;
                        if ($confirm && !isset($use_coupon_product[$_product['product_id']])) {
                            $coupon_price = bcadd($coupon_price, $coupon['coupon_price'], 2);
                            $use_coupon_product[$_product['product_id']] = $coupon['coupon_user_id'];
                            $cartInfo['coupon'][$__k]['checked'] = true;
                        }
                        break;
                    }
                }
                if (!isset($cartInfo['coupon'][$__k]['checked']))
                    $cartInfo['coupon'][$__k]['checked'] = false;
                if (!$flag) unset($cartInfo['coupon'][$__k]);
            }
            $pay_price = max(bcsub($valid_total_price, $coupon_price, 2), 0);
            $_pay_price = $pay_price;
            foreach ($cartInfo['coupon'] as $__k => $coupon) {
                if ($coupon['coupon']['type']) continue;
                if (!is_null($useCoupon)) {
                    if (isset($useCoupon[$cartInfo['mer_id']])) {
                        $store = $useCoupon[$cartInfo['mer_id']]['store'] ?? '';
                        if (!$store || $coupon['coupon_user_id'] != $store)
                            continue;
                    } else {
                        continue;
                    }
                }

                //店铺券
                if ($valid_total_price >= $coupon['use_min_price']) {
                    if (!$confirm || $pay_price <= 0 || $use_store_coupon) {
                        $cartInfo['coupon'][$__k]['checked'] = false;
                        continue;
                    }
                    $use_store_coupon = $coupon['coupon_user_id'];
                    $coupon_price = bcadd($coupon_price, $coupon['coupon_price'], 2);
                    $_pay_price = bcsub($_pay_price, $coupon['coupon_price'], 2);
                    $cartInfo['coupon'][$__k]['checked'] = true;
                } else {
                    unset($cartInfo['coupon'][$__k]);
                }
            }
            $take = $merchantTakeRepository->get($cartInfo['mer_id']);
            $org_price = bcadd(bcsub($total_price, $valid_total_price, 2), max($_pay_price, 0), 2);
            if ($presellType == 2)
                $org_price = max(bcsub($org_price, $final_price, 2), $down_price);
            $coupon_price = min($coupon_price, bcsub($total_price, $down_price, 2));
            if ($order_type != 2 || $presellType != 2) {
                $pay_price = bcadd($postage_price, $org_price, 2);
            } else {
                $pay_price = $org_price;
            }

            foreach ($fn as $callback) {
                $callback();
            }

            $cartInfo['take'] = $take['mer_take_status'] == '1' ? $take : ['mer_take_status' => 0];
            $cartInfo['coupon'] = array_values($cartInfo['coupon']);
            $cartInfo['order'] = compact('order_type', 'final_price', 'down_price', 'valid_total_price', 'product_cart', 'product_price', 'postage_price', 'org_price', 'total_price', 'total_num', 'pay_price', 'coupon_price', 'use_coupon_product', 'use_store_coupon');
            $merchantInfo[$k] = $cartInfo;
            $order_price = bcadd($order_price, $merchantInfo[$k]['order']['pay_price'], 2);
            $order_total_price = bcadd($order_total_price, $total_price, 2);
        }
        return ['order_type' => $order_type, 'order_price' => $order_price, 'total_price' => $order_total_price, 'address' => $address, 'order' => $merchantInfo, 'status' => $address ? ($noDeliver ? 'noDeliver' : 'finish') : 'noAddress'];
    }

    public function v2CartIdByOrderInfo($user, array $cartId, array $takes = null, array $useCoupon = null, bool $useIntegral = false, int $addressId = null)
    {
        $uid = $user->uid;
        $address = null;
        //验证地址
        if ($addressId) {
            $addressRepository = app()->make(UserAddressRepository::class);
            $address = $addressRepository->getWhere(['uid' => $uid, 'address_id' => $addressId]);
        }

        $storeCartRepository = app()->make(StoreCartRepository::class);
        $res = $storeCartRepository->checkCartList($storeCartRepository->cartIbByData($cartId, $uid, $address));
        $merchantInfo = $res['list'];
        $fail = $res['fail'];

        //检查购物车失效数据
        if (count($fail)) {
            if ($fail[0]['is_fail'])
                throw new ValidateException($fail[0]['product']['store_name'] . ' 已失效');
            if (in_array($fail[0]['product_type'], [1, 2, 3]) && !$fail[0]['userPayCount']) {
                throw new ValidateException($fail[0]['product']['store_name'] . ' 已超出购买限制');
            }
            throw new ValidateException($fail[0]['product']['store_name'] . ' 已失效');
        }

        //检查商品类型, 活动商品只能单独购买
        foreach ($merchantInfo as $cart) {
            foreach ($cart['list'] as $item) {
                if ($item['product_type'] > 0 && (count($cart['list']) != 1 || count($merchantInfo) != 1)) {
                    throw new ValidateException('活动商品必须单独购买');
                }
            }
        }

        $merchantTakeRepository = app()->make(MerchantTakeRepository::class);
        $order_price = 0;
        $order_total_price = 0;
        $order_total_integral = 0;
        $order_total_integral_price = 0;
        $order_total_give_integral = 0;
        $order_coupon_price = 0;
        $noDeliver = false;
        $order_type = 0;
        $presellType = 0;
        $fn = [];


        //积分配置
        $sysIntegralConfig = systemConfig(['integral_money', 'integral_status', 'integral_order_rate']);
        $merIntegralFlag = false;

        // 循环计算每个店铺的订单数据
        foreach ($merchantInfo as $k => $cartInfo) {
            $postageRule = [];
            $total_price = 0;
            $total_num = 0;
            $valid_total_price = 0;
            $postage_price = 0;
            $product_price = [];
            $final_price = 0;
            $down_price = 0;

            //是否自提
            $isTake = in_array($cartInfo['mer_id'], $takes ?? []);

            //自提信息
            $take = $merchantTakeRepository->get($cartInfo['mer_id']);
            $cartInfo['take'] = $take['mer_take_status'] == '1' ? $take : ['mer_take_status' => 0];

            if ($isTake && !$cartInfo['take']['mer_take_status'])
                throw new ValidateException($cartInfo['mer_name'] . ' 不支持到店自提');

            //加载商品数据
            foreach ($cartInfo['list'] as $_k => $cart) {
                //获取订单类型, 活动商品单次只能购买一个
                if ($cart['product_type'] > 0) $order_type = $cart['product_type'];

                //预售订单
                if ($cart['product_type'] == 2) {
                    $cart->append(['productPresell', 'productPresellAttr']);
                    //助力订单
                } else if ($cart['product_type'] == 3) {
                    $cart->append(['productAssistAttr']);
                    //拼团订单
                } else if ($cart['product_type'] == 4) {
                    $cart->append(['activeSku']);
                }
            }

            //如果是预售订单 获取预售的订单的首款,尾款预售类型
            if ($order_type == 2) {
                $final_price = bcadd($final_price, bcmul($cart['cart_num'], $cart['productPresellAttr']['final_price'], 2), 2);
                if ($cart['productPresell']['presell_type'] == 2)
                    $down_price = bcadd($down_price, bcmul($cart['cart_num'], $cart['productPresellAttr']['down_price'], 2), 2);
                $presellType = $cart['productPresell']['presell_type'];
            }

            //获取运费规则和统计商品数据
            foreach ($cartInfo['list'] as $_k => $cart) {
                $price = bcmul($cart['cart_num'], $this->cartByPrice($cart), 2);
                $cartInfo['list'][$_k]['total_price'] = $price;
                $total_price = bcadd($total_price, $price, 2);
                $total_num += $cart['cart_num'];
                $_price = bcmul($cart['cart_num'], $this->cartByCouponPrice($cart), 2);
                if ($_price > 0) {
                    $product_price[$cart['product_id']] = bcadd($product_price[$cart['product_id']] ?? 0, $_price, 2);
                    $valid_total_price = bcadd($valid_total_price, $_price, 2);
                }
                if (!isset($product_cart[$cart['product_id']]))
                    $product_cart[$cart['product_id']] = [$cart['cart_id']];
                else
                    $product_cart[$cart['product_id']][] = $cart['cart_id'];

                $temp1 = $cart['product']['temp'];
                $free = $temp1['free'][0] ?? null;
                $region = $temp1['region'][0] ?? null;

                if (!$address || !$cart['product']['temp'] || ($temp1['undelivery'] == 2 && !$free && (!$region || !$region['city_id']))) {
                    $cartInfo['list'][$_k]['undelivered'] = true;
                    $noDeliver = true;
                    continue;
                }
                $cart['undelivered'] = (!$isTake) && $temp1['undelivery'] == 1 && isset($temp1['undelives']);
                $fn[] = function () use ($cartInfo, $_k) {
                    unset($cartInfo['list'][$_k]['product']['temp']);
                };
                $cartInfo['list'][$_k] = $cart;

                if ($cart['undelivered']) {
                    $noDeliver = true;
                    continue;
                }

                if (!isset($postageRule[$cart['product']['temp_id']])) {
                    $postageRule[$cart['product']['temp_id']] = [
                        'free' => null,
                        'region' => null
                    ];
                }
                $number = $this->productByTempNumber($cart);
                $freeRule = $postageRule[$cart['product']['temp_id']]['free'];
                $regionRule = $postageRule[$cart['product']['temp_id']]['region'];
                if ($temp1['appoint'] && $free) {
                    if (!isset($freeRule)) {
                        $freeRule = $free;
                        $freeRule['cart_price'] = 0;
                        $freeRule['cart_number'] = 0;
                    }
                    $freeRule['cart_number'] = bcadd($freeRule['cart_number'], $number, 2);
                    $freeRule['cart_price'] = bcadd($freeRule['cart_price'], $price, 2);
                }

                if ($region) {
                    if (!isset($regionRule)) {
                        $regionRule = $region;
                        $regionRule['cart_price'] = 0;
                        $regionRule['cart_number'] = 0;
                    }
                    $regionRule['cart_number'] = bcadd($regionRule['cart_number'], $number, 2);
                    $regionRule['cart_price'] = bcadd($regionRule['cart_price'], $price, 2);
                }
                $postageRule[$cart['product']['temp_id']]['free'] = $freeRule;
                $postageRule[$cart['product']['temp_id']]['region'] = $regionRule;
            }

            if (!$isTake) {
                //计算运费
                foreach ($postageRule as $item) {
                    $freeRule = $item['free'];
                    if ($freeRule && $freeRule['cart_number'] >= $freeRule['number'] && $freeRule['cart_price'] >= $freeRule['price'])
                        continue;
                    if (!$item['region']) continue;
                    $regionRule = $item['region'];
                    $postage = $regionRule['first_price'];
                    if ($regionRule['first'] > 0 && $regionRule['cart_number'] > $regionRule['first']) {
                        $num = ceil(bcdiv(bcsub($regionRule['cart_number'], $regionRule['first'], 2), $regionRule['continue'], 2));
                        $postage = bcadd($postage, bcmul($num, $regionRule['continue_price'], 2), 2);
                    }
                    $postage_price = bcadd($postage_price, $postage, 2);
                }
            }

            $coupon_price = 0;
            $use_coupon_product = [];
            $use_store_coupon = 0;

            $useCouponFlag = isset($useCoupon[$cartInfo['mer_id']]);
            $merCouponIds = (array)($useCoupon[$cartInfo['mer_id']] ?? []);
            $all_coupon_product = [];

            //过滤不可用店铺优惠券
            foreach ($cartInfo['coupon'] as $__k => $coupon) {
                if (!$coupon['coupon']['type']) continue;

                $cartInfo['coupon'][$__k]['disabled'] = false;
                $cartInfo['coupon'][$__k]['checked'] = false;

                if (count(array_intersect(array_column($coupon['product'], 'product_id'), array_keys($product_price))) == 0) {
                    $cartInfo['coupon'][$__k]['disabled'] = true;
                    continue;
                }
                $flag = false;
                foreach ($coupon['product'] as $_product) {
                    if (isset($product_price[$_product['product_id']]) && $product_price[$_product['product_id']] >= $coupon['use_min_price']) {
                        $flag = true;
                        break;
                    }
                }
                if (!$flag) {
                    $cartInfo['coupon'][$__k]['disabled'] = true;
                }
                if (!$cartInfo['coupon'][$__k]['disabled']) {
                    $all_coupon_product[] = $coupon['coupon_user_id'];
                }
            }

//            if ($useCouponFlag && count(array_diff($all_coupon_product, $use_coupon_product))) {
//                throw new ValidateException('请选择有效的商品券');
//            }
            //计算商品券金额
            foreach ($cartInfo['coupon'] as $__k => $coupon) {
                if (!$coupon['coupon']['type']) continue;
                if ($coupon['disabled']) continue;

                foreach ($coupon['product'] as $_product) {
                    if (isset($product_price[$_product['product_id']]) && $product_price[$_product['product_id']] >= $coupon['use_min_price']) {
                        if ($useCouponFlag) {
                            if (!in_array($coupon['coupon_user_id'], $merCouponIds) || isset($use_coupon_product[$_product['product_id']])) {
                                continue;
                            }
                        } else if (isset($use_coupon_product[$_product['product_id']])) {
                            continue;
                        }
                        $coupon_price = bcadd($coupon_price, $coupon['coupon_price'], 2);
                        $use_coupon_product[$_product['product_id']] = $coupon;
                        $cartInfo['coupon'][$__k]['checked'] = true;
                        break;
                    }
                }
            }
            $pay_price = max(bcsub($valid_total_price, $coupon_price, 2), 0);
            $_pay_price = $pay_price;

            //计算店铺券
            foreach ($cartInfo['coupon'] as $__k => $coupon) {
                if ($coupon['coupon']['type']) continue;
                $cartInfo['coupon'][$__k]['checked'] = false;
                $cartInfo['coupon'][$__k]['disabled'] = $pay_price <= 0 || !!$use_store_coupon;
                if ($use_store_coupon || $pay_price <= 0) continue;

                //店铺券
                if ($valid_total_price >= $coupon['use_min_price']) {
                    if ($useCouponFlag) {
                        if (!in_array($coupon['coupon_user_id'], $merCouponIds)) {
                            continue;
                        }
                    }
                    $use_store_coupon = $coupon;
                    $coupon_price = bcadd($coupon_price, $coupon['coupon_price'], 2);
                    $_pay_price = bcsub($_pay_price, $coupon['coupon_price'], 2);
                    $cartInfo['coupon'][$__k]['checked'] = true;
                } else {
                    $cartInfo['coupon'][$__k]['disabled'] = true;
                }
            }

            $productCouponRate = [];
            $storeCouponRate = null;
            $useCouponIds = [];
            //计算优惠占比
            foreach ($use_coupon_product as $productId => $coupon) {
                $productCouponRate[$productId] = [
                    'rate' => $product_price[$productId] > 0 ? bcdiv($coupon['coupon_price'], $product_price[$productId], 4) : 1,
                    'coupon_price' => $coupon['coupon_price'],
                    'price' => $product_price[$productId]
                ];
                $useCouponIds[] = $coupon['coupon_user_id'];
            }

            if ($use_store_coupon) {
                $storeCouponRate = [
                    'rate' => $pay_price > 0 ? bcdiv($use_store_coupon['coupon_price'], $pay_price, 4) : 1,
                    'coupon_price' => $use_store_coupon['coupon_price'],
                    'price' => $coupon_price
                ];
                $useCouponIds[] = $use_store_coupon['coupon_user_id'];
            }

            //计算单个商品实际支付金额
            foreach ($cartInfo['list'] as $_k => $cart) {
                $cartTotalPrice = bcmul($this->cartByPrice($cart), $cart['cart_num'], 2);
                if (!$cart['product_type'] && $cartTotalPrice > 0) {
                    if (isset($productCouponRate[$cart['product_id']])) {
                        //计算每个商品优惠金额(商品券)
                        if ($productCouponRate[$cart['product_id']]['rate'] >= 1) {
                            $cartTotalPrice = 0;
                        } else {
                            array_pop($product_cart);
                            if (!count($product_cart)) {
                                $cartTotalPrice = bcsub($cartTotalPrice, $productCouponRate[$cart['product_id']]['coupon_price'], 2);
                            } else {
                                $couponPrice = bcmul($cartTotalPrice, $productCouponRate[$cart['product_id']]['rate'], 2);
                                $cartTotalPrice = bcsub($cartTotalPrice, $couponPrice, 2);
                                $productCouponRate[$cart['product_id']]['coupon_price'] = bcsub($productCouponRate[$cart['product_id']]['coupon_price'], $couponPrice, 2);
                            }
                        }
                    }

                    //(店铺券)
                    if ($storeCouponRate && $cartTotalPrice > 0) {
                        if ($storeCouponRate['rate'] >= 1) {
                            $cartTotalPrice = 0;
                        } else {
                            if (count($cartInfo['list']) == $_k + 1) {
                                $cartTotalPrice = bcsub($cartTotalPrice, $storeCouponRate['coupon_price'], 2);
                            } else {
                                $couponPrice = bcmul($cartTotalPrice, $storeCouponRate['rate'], 2);
                                $cartTotalPrice = bcsub($cartTotalPrice, $couponPrice, 2);
                                $storeCouponRate['coupon_price'] = bcsub($storeCouponRate['coupon_price'], $couponPrice, 2);
                            }
                        }
                    }
                }

                //单个商品实际支付金额
                $cartInfo['list'][$_k]['true_price'] = $cartTotalPrice;
            }

            $merIntegralConfig = merchantConfig($cartInfo['mer_id'], ['mer_integral_status', 'mer_integral_rate']);
            $merIntegralConfig['mer_integral_rate'] = min(1, $merIntegralConfig['mer_integral_rate'] > 0 ? bcdiv($merIntegralConfig['mer_integral_rate'], 100, 4) : $merIntegralConfig['mer_integral_rate']);

            $total_integral = 0;
            $total_integral_price = 0;
            $userIntegral = $user->integral;

            $merIntegralFlag = $merIntegralFlag || ((bool)$merIntegralConfig['mer_integral_status']);

            $integralFlag = $useIntegral && $sysIntegralConfig['integral_status'] && $sysIntegralConfig['integral_money'] > 0 && $merIntegralConfig['mer_integral_status'];
            //计算积分抵扣
            foreach ($cartInfo['list'] as $_k => $cart) {
                //只有普通商品可以抵扣
                if ($cart['product_type'] == 0 && $integralFlag && $userIntegral > 0 && $_pay_price > 0) {
                    $integralRate = $cart['product']['integral_rate'];
                    if ($integralRate < 0) {
                        $integralRate = $merIntegralConfig['mer_integral_rate'];
                    }else{
                        $integralRate = min(bcdiv($integralRate, 100, 4), 1);
                    }
                    if ($integralRate > 0) {
                        $productIntegralPrice = min(bcmul(bcmul($this->cartByPrice($cart), $cart['cart_num'], 2), $integralRate, 2), $cart['true_price']);
                        if ($productIntegralPrice > 0) {
                            $productIntegral = ceil(bcdiv($productIntegralPrice, $sysIntegralConfig['integral_money'], 3));
                            if ($productIntegral <= $userIntegral) {
                                $userIntegral = bcsub($userIntegral, $productIntegral, 0);
                                //使用多少积分抵扣了多少金额
                                $cartInfo['list'][$_k]['integral'] = [
                                    'use' => $productIntegral,
                                    'price' => $productIntegralPrice
                                ];
                            } else {
                                $productIntegralPrice = bcmul($userIntegral, $sysIntegralConfig['integral_money'], 2);
                                //使用多少积分抵扣了多少金额
                                $cartInfo['list'][$_k]['integral'] = [
                                    'use' => $userIntegral,
                                    'price' => $productIntegralPrice
                                ];
                                $userIntegral = 0;
                            }

                            $cartInfo['list'][$_k]['true_price'] = bcsub($cart['true_price'], $cartInfo['list'][$_k]['integral']['price'], 2);
                            $_pay_price = bcsub($_pay_price, $cartInfo['list'][$_k]['integral']['price'], 2);

                            $total_integral_price = bcadd($total_integral_price, $cartInfo['list'][$_k]['integral']['price'], 2);
                            $total_integral = bcadd($total_integral, $cartInfo['list'][$_k]['integral']['use'], 0);
                            continue;
                        }
                    }
                }
                $cartInfo['list'][$_k]['integral'] = null;
            }

            $order_total_integral = bcadd($order_total_integral, $total_integral, 0);
            $order_total_integral_price = bcadd($order_total_integral_price, $total_integral_price, 2);


//            //计算赠送积分
//            foreach ($cartInfo['list'] as $_k => $cart) {
//                $give_integral = 0;
//                //计算赠送积分, 只有普通商品赠送积分
//                if ($giveIntegralFlag && $cart['product_type'] == 0 && $cart['true_price'] > 0) {
//                    $give_integral = floor(bcmul($cart['true_price'], $sysIntegralConfig['integral_order_rate'], 1));
//                }
//                if ($give_integral > 0) {
//                    $cartInfo['list'][$_k]['give_integral'] = $give_integral;
//                    $cartInfo['list'][$_k]['product_give_integral'] = bcmul($give_integral, $cart['cart_num'], 0);
//                    $total_give_integral = bcadd($total_give_integral, $cartInfo['list'][$_k]['product_give_integral'], 0);
//                } else {
//                    $cartInfo['list'][$_k]['give_integral'] = 0;
//                    $cartInfo['list'][$_k]['product_give_integral'] = 0;
//                }
//            }

            //计算订单商品金额
            $org_price = bcadd(bcsub($total_price, $valid_total_price, 2), max($_pay_price, 0), 2);
            if ($presellType == 2) {
                $org_price = max(bcsub($org_price, $final_price, 2), $down_price);
            }

            //获取可优惠金额
            $coupon_price = min($coupon_price, bcsub($total_price, $down_price, 2));
            $order_coupon_price = bcadd($coupon_price, $order_coupon_price, 2);

            //计算订单金额
            if ($order_type != 2 || $presellType != 2) {
                $pay_price = bcadd($postage_price, $org_price, 2);
            } else {
                $pay_price = $org_price;
            }

            $giveIntegralFlag = $sysIntegralConfig['integral_status'] && $sysIntegralConfig['integral_order_rate'] > 0;
            $total_give_integral = 0;
            //计算赠送积分, 只有普通商品赠送积分
            if ($giveIntegralFlag && !$order_type && $pay_price > 0) {
                $total_give_integral = floor(bcmul($pay_price, $sysIntegralConfig['integral_order_rate'], 0));
            }
            $order_total_give_integral = bcadd($total_give_integral, $order_total_give_integral, 0);

            foreach ($fn as $callback) {
                $callback();
            }

            $cartInfo['order'] = compact(
                'total_give_integral',
                'total_integral_price',
                'total_integral',
                'useCouponIds',
                'order_type',
                'final_price',
                'down_price',
                'valid_total_price',
                'postage_price',
                'org_price',
                'total_price',
                'total_num',
                'pay_price',
                'coupon_price',
                'isTake'
            );

            $merchantInfo[$k] = $cartInfo;
            $order_price = bcadd($order_price, $pay_price, 2);
            $order_total_price = bcadd($order_total_price, $total_price, 2);
        }

        //兼容v1
        $status = $address ? ($noDeliver ? 'noDeliver' : 'finish') : 'noAddress';
        $order = $merchantInfo;
        $total_price = $order_total_price;
        $openIntegral = $merIntegralFlag && !$order_type && $sysIntegralConfig['integral_status'] && $sysIntegralConfig['integral_money'] > 0;
        return compact(
            'order_type',
            'order_price',
            'total_price',
            'order_total_integral',
            'order_total_integral_price',
            'order_total_give_integral',
            'order_coupon_price',
            'order',
            'status',
            'address',
            'openIntegral',
            'useIntegral'
        );
    }

    public function v2CreateOrder(int $pay_type, $user, array $cartId, array $mark, array $receipt_data, array $takes = null, array $useCoupon = null, bool $useIntegral = false, int $addressId = null)
    {
        $uid = $user->uid;
        $orderInfo = $this->v2CartIdByOrderInfo($user, $cartId, $takes, $useCoupon, $useIntegral, $addressId);
        if ($orderInfo['status'] == 'noDeliver') throw new ValidateException('部分商品不支持该区域');
        if (!$orderInfo['address']) throw new ValidateException('请选择正确的收货地址');
        if(!$orderInfo['address']['province_id']) throw new ValidateException('请完善收货地址信息');

        $orderType = $orderInfo['order_type'];
        if ($orderType && (count($orderInfo['order']) > 1 || count($orderInfo['order'][0]['list']) > 1)) {
            throw new ValidateException('活动商品请单独购买');
        }

        $isSelfBuy = $user->is_promoter && systemConfig('extension_self') ? 1 : 0;
        if ($isSelfBuy) {
            $spreadUser = $user;
            $topUser = $user->valid_spread;
        } else {
            $spreadUser = $user->valid_spread;
            $topUser = $user->valid_top;
        }
        $spreadUid = $spreadUser->uid ?? 0;
        $topUid = $topUser->uid ?? 0;

        $cartList = $orderInfo['order'];
        $merchantRepository = app()->make(MerchantRepository::class);
        $giveCouponIds = [];
        $ex = systemConfig('extension_status');
        $address = $orderInfo['address'];
        $allUseCoupon = [];
        $totalNum = 0;
        $totalPostage = 0;
        $totalCost = 0;
        $cartIds = [];

        foreach ($cartList as $k => $cartInfo) {

            //检查发票状态
            if (isset($receipt_data[$cartInfo['mer_id']]) && !$cartInfo['openReceipt'])
                throw new ValidateException('该店铺不支持开发票');

            $cost = 0;
            $total_extension_one = 0;
            $total_extension_two = 0;
            //计算佣金和赠送的优惠券
            foreach ($cartInfo['list'] as $__k => $cart) {
                $cartIds[] = $cart['cart_id'];
                $giveCouponIds = array_merge($giveCouponIds, $cart['product']['give_coupon_ids'] ?: []);
                $cost = bcadd(bcmul($orderType == 2 ? $cart['productPresellAttr']['cost'] : $cart['productAttr']['cost'], $cart['cart_num'], 2), $cost, 2);
                $extension_one = 0;
                $extension_two = 0;
                if ($ex) {
                    //预售订单
                    if ($orderType == 2) {
                        $_payPrice = $cartInfo['order']['pay_price'];
                        $rate = $cart['productPresell']['presell_type'] == 2 ? bcdiv($cart['productPresellAttr']['down_price'], $cart['productPresellAttr']['presell_price'], 3) : 1;
                        $one_price = $_payPrice > 0 ? bcdiv($_payPrice, $cart['cart_num'], 2) : 0;
                        if ($spreadUid && $cart['productPresellAttr']['bc_extension_one'] > 0) {
                            $org_extension = $cart['productPresellAttr']['bc_extension_one'];
                            if ($spreadUser->brokerage_level > 0 && $spreadUser->brokerage && $spreadUser->brokerage->extension_one_rate > 0) {
                                $org_extension = bcmul($org_extension, 1 + $spreadUser->brokerage->extension_one_rate, 2);
                            }
                            $_extension_one = bcmul($rate, $org_extension, 3);
                            $presell_extension_one = 0;
                            if ($cart['true_price'] > 0) {
                                $extension_one = bcmul(bcdiv($one_price, $cart['productPresellAttr']['down_price'], 3), $_extension_one, 2);
                            }
                            if ($rate < 1) {
                                $presell_extension_one = bcmul(1 - $rate, $org_extension, 2);
                            }
                            $cartList[$k]['list'][$__k]['final_extension_one'] = bcmul($extension_one, $cart['cart_num'], 2);
                            $extension_one = bcadd($extension_one, $presell_extension_one, 2);
                            $cartList[$k]['list'][$__k]['presell_extension_one'] = bcmul($presell_extension_one, $cart['cart_num'], 2);
                        }
                        if ($topUid && $cart['productPresellAttr']['bc_extension_two'] > 0) {
                            $org_extension = $cart['productPresellAttr']['bc_extension_two'];
                            if ($topUser->brokerage_level > 0 && $topUser->brokerage && $topUser->brokerage->extension_two_rate > 0) {
                                $org_extension = bcmul($org_extension, 1 + $topUser->brokerage->extension_two_rate, 2);
                            }
                            $_extension_two = bcmul($rate, $org_extension, 2);
                            $presell_extension_two = 0;
                            if ($cart['true_price'] > 0) {
                                $extension_two = bcmul(bcdiv($one_price, $cart['productPresellAttr']['down_price'], 3), $_extension_two, 2);
                            }
                            if ($rate < 1) {
                                $presell_extension_two = bcmul(1 - $rate, $org_extension, 2);
                            }
                            $cartList[$k]['list'][$__k]['final_extension_two'] = bcmul($extension_two, $cart['cart_num'], 2);;
                            $extension_two = bcadd($extension_two, $presell_extension_two, 2);
                            $cartList[$k]['list'][$__k]['presell_extension_two'] = bcmul($presell_extension_two, $cart['cart_num'], 2);
                        }
                    } else if (!$orderType) {
                        if ($spreadUid && $cart['productAttr']['bc_extension_one'] > 0) {
                            $org_extension = $cart['productAttr']['bc_extension_one'];
                            if ($spreadUser->brokerage_level > 0 && $spreadUser->brokerage && $spreadUser->brokerage->extension_one_rate > 0) {
                                $org_extension = bcmul($org_extension, 1 + $spreadUser->brokerage->extension_one_rate, 2);
                            }
                            $extension_one = $cart['true_price'] > 0 ? bcmul(bcdiv($cart['true_price'], $cart['total_price'], 3), $org_extension, 2) : 0;

                        }
                        if ($topUid && $cart['productAttr']['bc_extension_two'] > 0) {
                            $org_extension = $cart['productAttr']['bc_extension_two'];
                            if ($topUser->brokerage_level > 0 && $topUser->brokerage && $topUser->brokerage->extension_two_rate > 0) {
                                $org_extension = bcmul($org_extension, 1 + $topUser->brokerage->extension_two_rate, 2);
                            }
                            $extension_two = $cart['true_price'] > 0 ? bcmul(bcdiv($cart['true_price'], $cart['total_price'], 3), $org_extension, 2) : 0;
                        }
                    }
                }
                $cartList[$k]['list'][$__k]['extension_one'] = $extension_one;
                $cartList[$k]['list'][$__k]['extension_two'] = $extension_two;
                $total_extension_one = bcadd($total_extension_one, bcmul($extension_one, $cart['cart_num'], 2), 2);
                $total_extension_two = bcadd($total_extension_two, bcmul($extension_two, $cart['cart_num'], 2), 2);
            }

            //整理订单数据
            $_order = [
                'cartInfo' => $cartInfo,
                'activity_type' => $orderInfo['order_type'],
                'commission_rate' => (float)$merchantRepository->get($cartInfo['mer_id'])->mer_commission_rate,
                'order_type' => $cartInfo['order']['isTake'] ? 1 : 0,
                'extension_one' => $total_extension_one,
                'extension_two' => $total_extension_two,
                'order_sn' => $this->getNewOrderId() . ($k + 1),
                'uid' => $uid,
                'is_selfbuy' => $isSelfBuy,
                'real_name' => $address['real_name'],
                'user_phone' => $address['phone'],
                'user_address' => $address['province'] . $address['city'] . $address['district'] . ' ' . $address['detail'],
                'cart_id' => implode(',', array_column($cartInfo['list'], 'cart_id')),
                'total_num' => $cartInfo['order']['total_num'],
                'total_price' => $cartInfo['order']['total_price'],
                'total_postage' => $cartInfo['order']['postage_price'],
                'pay_postage' => $cartInfo['order']['postage_price'],
                'pay_price' => $cartInfo['order']['pay_price'],
                'integral' => $cartInfo['order']['total_integral'],
                'integral_price' => $cartInfo['order']['total_integral_price'],
                'give_integral' => $cartInfo['order']['total_give_integral'],
                'mer_id' => $cartInfo['mer_id'],
                'cost' => $cost,
                'coupon_id' => implode(',', $cartInfo['order']['useCouponIds']),
                'mark' => $mark[$cartInfo['mer_id']] ?? '',
                'coupon_price' => $cartInfo['order']['coupon_price'],
                'pay_type' => $pay_type
            ];
            $allUseCoupon = array_merge($allUseCoupon, $cartInfo['order']['useCouponIds']);
            $orderList[] = $_order;
            $totalPostage = bcadd($totalPostage, $_order['total_postage'], 2);
            $totalCost = bcadd($totalCost, $cost, 2);
            $totalNum += $cartInfo['order']['total_num'];
        }

        $groupOrder = [
            'uid' => $uid,
            'group_order_sn' => $this->getNewOrderId() . '0',
            'total_postage' => $totalPostage,
            'total_price' => $orderInfo['total_price'],
            'total_num' => $totalNum,
            'real_name' => $address['real_name'],
            'user_phone' => $address['phone'],
            'user_address' => $address['province'] . $address['city'] . $address['district'] . ' ' . $address['detail'],
            'pay_price' => $orderInfo['order_price'],
            'coupon_price' => $orderInfo['order_coupon_price'],
            'pay_postage' => $totalPostage,
            'cost' => $totalCost,
            'pay_type' => $pay_type,
            'give_coupon_ids' => $giveCouponIds,
            'integral' => $orderInfo['order_total_integral'],
            'integral_price' => $orderInfo['order_total_integral_price'],
            'give_integral' => $orderInfo['order_total_give_integral'],
        ];

        $group = Db::transaction(function () use ($ex, $user, $topUid, $spreadUid, $uid, $receipt_data, $cartIds, $allUseCoupon, $groupOrder, $orderList, $orderInfo) {
            $storeGroupOrderRepository = app()->make(StoreGroupOrderRepository::class);
            $storeCartRepository = app()->make(StoreCartRepository::class);
            $attrValueRepository = app()->make(ProductAttrValueRepository::class);
            $productRepository = app()->make(ProductRepository::class);
            $storeOrderProductRepository = app()->make(StoreOrderProductRepository::class);
            $couponUserRepository = app()->make(StoreCouponUserRepository::class);
            $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class);
            $userMerchantRepository = app()->make(UserMerchantRepository::class);

            //减库存
            foreach ($orderList as $order) {
                foreach ($order['cartInfo']['list'] as $cart) {
                    if (!isset($uniqueList[$cart['productAttr']['product_id'] . $cart['productAttr']['unique']]))
                        $uniqueList[$cart['productAttr']['product_id'] . $cart['productAttr']['unique']] = true;
                    else
                        throw new ValidateException('购物车商品信息重复');

                    try {
                        if ($cart['product_type'] == '1') {
                            $attrValueRepository->descSkuStock($cart['product']['old_product_id'], $cart['productAttr']['sku'], $cart['cart_num']);
                            $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']);
                        } else if ($cart['product_type'] == '2') {
                            $productPresellSkuRepository = app()->make(ProductPresellSkuRepository::class);
                            $productPresellSkuRepository->descStock($cart['productPresellAttr']['product_presell_id'], $cart['productPresellAttr']['unique'], $cart['cart_num']);
                            $attrValueRepository->descStock($cart['productAttr']['product_id'], $cart['productAttr']['unique'], $cart['cart_num']);
                            $productRepository->descStock($cart['product']['product_id'], $cart['cart_num']);
                        } else if ($cart['product_type'] == '3') {
                            app()->make(ProductAssistSkuRepository::class)->descStock($cart['productAssistAttr']['product_assist_id'], $cart['productAssistAttr']['unique'], $cart['cart_num']);
                            $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']);
                            $attrValueRepository->descStock($cart['product']['old_product_id'], $cart['productAttr']['unique'], $cart['cart_num']);
                        } else if ($cart['product_type'] == '4') {
                            app()->make(ProductGroupSkuRepository::class)->descStock($cart['activeSku']['product_group_id'], $cart['activeSku']['unique'], $cart['cart_num']);
                            $productRepository->descStock($cart['product']['old_product_id'], $cart['cart_num']);
                            $attrValueRepository->descStock($cart['product']['old_product_id'], $cart['productAttr']['unique'], $cart['cart_num']);
                        } else {
                            $attrValueRepository->descStock($cart['productAttr']['product_id'], $cart['productAttr']['unique'], $cart['cart_num']);
                            $productRepository->descStock($cart['product']['product_id'], $cart['cart_num']);
                            if ($cart['integral'] && $cart['integral']['use'] > 0) {
                                $productRepository->incIntegral($cart['product']['product_id'], $cart['integral']['use'], $cart['integral']['price']);
                            }
                        }
                    } catch (Exception $e) {
                        throw new ValidateException('库存不足');
                    }
                }
            }

            //修改购物车状态
            $storeCartRepository->updates($cartIds, [
                'is_pay' => 1
            ]);

            //使用优惠券
            if (count($allUseCoupon)) {
                $couponUserRepository->updates($allUseCoupon, [
                    'use_time' => date('Y-m-d H:i:s'),
                    'status' => 1
                ]);
            }

            //创建订单
            $groupOrder = $storeGroupOrderRepository->create($groupOrder);
            $bills = [];

            if ($groupOrder['integral'] > 0) {
                $user->integral = bcsub($user->integral, $groupOrder['integral'], 0);
                app()->make(UserBillRepository::class)->decBill($user['uid'], 'integral', 'deduction', [
                    'link_id' => $groupOrder['group_order_id'],
                    'status' => 1,
                    'title' => '购买商品',
                    'number' => $groupOrder['integral'],
                    'mark' => '购买商品使用积分抵扣' . floatval($groupOrder['integral_price']) . '元',
                    'balance' => $user->integral
                ]);
                $user->save();
            }

            foreach ($orderList as $k => $order) {
                $orderList[$k]['group_order_id'] = $groupOrder->group_order_id;
            }

            $orderProduct = [];
            $orderStatus = [];
            foreach ($orderList as $order) {
                $cartInfo = $order['cartInfo'];
                unset($order['cartInfo']);
                //创建子订单
                $_order = $this->dao->create($order);

                if ($order['integral'] > 0) {
                    $bills[] = [
                        'uid' => $uid,
                        'link_id' => $_order->order_id,
                        'pm' => 0,
                        'title' => '积分抵扣',
                        'category' => 'mer_integral',
                        'type' => 'deduction',
                        'number' => $order['integral'],
                        'balance' => $user->integral,
                        'mark' => '购买商品使用' . $order['integral'] . '积分抵扣' . floatval($order['integral_price']) . '元',
                        'mer_id' => $order['mer_id'],
                        'status' => 1
                    ];
                }

                //创建发票信息
                if (isset($receipt_data[$_order['mer_id']])) {
                    app()->make(StoreOrderReceiptRepository::class)->add($receipt_data[$_order['mer_id']], $_order);
                }

                $orderStatus[] = [
                    'order_id' => $_order->order_id,
                    'change_message' => '订单生成',
                    'change_type' => 'create'
                ];

                foreach ($cartInfo['list'] as $cart) {

                    $productPrice = $cart['true_price'];
                    $extension_one = $cart['extension_one'];
                    $extension_two = $cart['extension_two'];

                    //计算预售订单尾款
                    if ($cartInfo['order']['order_type'] == 2) {
                        $finalPrice = max(bcsub($cartInfo['order']['final_price'], $cartInfo['order']['coupon_price'], 2), 0);
                        $allFinalPrice = $order['order_type'] ? $finalPrice : bcadd($finalPrice, $order['pay_postage'], 2);
                        if ($cart['productPresell']['presell_type'] == 1) {
                            $productPrice = bcsub($cartInfo['order']['pay_price'], $order['pay_postage'], 2);
                        } else {
                            $productPrice = bcadd($cartInfo['order']['pay_price'], $finalPrice, 2);
                        }
                        //生成尾款订单
                        if ($cart['productPresell']['presell_type'] == 2) {
                            $presellOrderRepository = app()->make(PresellOrderRepository::class);
                            $presellOrderRepository->create([
                                'uid' => $uid,
                                'order_id' => $_order->order_id,
                                'mer_id' => $_order->mer_id,
                                'final_start_time' => $cart['productPresell']['final_start_time'],
                                'final_end_time' => $cart['productPresell']['final_end_time'],
                                'pay_price' => $allFinalPrice,
                                'presell_order_sn' => $presellOrderRepository->getNewOrderId()
                            ]);
                        }
                        app()->make(ProductPresellSkuRepository::class)->incCount($cart['source_id'], $cart['productAttr']['unique'], 'one_take');
                    }

                    $order_cart = [
                        'product' => $cart['product'],
                        'productAttr' => $cart['productAttr'],
                        'product_type' => $cart['product_type']
                    ];

                    if ($cart['product_type'] == '2') {
                        $order_cart['productPresell'] = $cart['productPresell'];
                        $order_cart['productPresellAttr'] = $cart['productPresellAttr'];
                        $order_cart['final_extension_one'] = $cart['final_extension_one'] ?? 0;
                        $order_cart['final_extension_two'] = $cart['final_extension_two'] ?? 0;
                        $order_cart['presell_extension_one'] = $cart['presell_extension_one'] ?? 0;
                        $order_cart['presell_extension_two'] = $cart['presell_extension_two'] ?? 0;
                    } else if ($cart['product_type'] == '3') {
                        $order_cart['productAssistAttr'] = $cart['productAssistAttr'];
                        $order_cart['productAssistSet'] = $cart['productAssistSet'];
                    } else if ($cart['product_type'] == '4') {
                        $order_cart['activeSku'] = $cart['activeSku'];
                    }

                    $orderProduct[] = [
                        'order_id' => $_order->order_id,
                        'cart_id' => $cart['cart_id'],
                        'uid' => $uid,
                        'product_id' => $cart['product_id'],
                        'activity_id' => $cart['source'] >= 2 ? $cart['source_id'] : $cart['product_id'],
                        'product_price' => $productPrice,
                        'extension_one' => $extension_one,
                        'extension_two' => $extension_two,
                        'product_sku' => $cart['productAttr']['unique'],
                        'product_num' => $cart['cart_num'],
                        'refund_num' => $cart['cart_num'],
                        'integral' => $cart['integral'] ? bcdiv($cart['integral']['use'], $cart['cart_num'], 0) : 0,
                        'product_type' => $cart['product_type'],
                        'cart_info' => json_encode($order_cart)
                    ];
                }

                $userMerchantRepository->getInfo($uid, $order['mer_id']);
                app()->make(MerchantRepository::class)->incSales($order['mer_id'], $order['total_num']);
            }

            if (count($bills) > 0) {
                app()->make(UserBillRepository::class)->insertAll($bills);
            }
            $storeOrderStatusRepository->insertAll($orderStatus);
            $storeOrderProductRepository->insertAll($orderProduct);
            return $groupOrder;
        });
        foreach ($cartList as $cartInfo) {
            foreach ($cartInfo['list'] as $cart) {
                if (($cart['productAttr']['stock'] - $cart['cart_num']) < (int)merchantConfig($cartInfo['mer_id'], 'mer_store_stock')) {
                    SwooleTaskService::merchant('notice', [
                        'type' => 'min_stock',
                        'data' => [
                            'title' => '库存不足',
                            'message' => $cart['product']['store_name'] . '(' . $cart['productAttr']['sku'] . ')库存不足',
                            'id' => $cart['product']['product_id']
                        ]
                    ], $cartInfo['mer_id']);
                }
            }
        }
        queue::push(SendTemplateMessageJob::class, ['tempCode' => 'ORDER_CREATE', 'id' => $group->group_order_id]);
        return $group;
    }

    /**
     * @param $cart
     * @return string
     * @author xaboy
     * @day 2020/6/9
     */
    public function productByTempNumber($cart)
    {
        $type = $cart['product']['temp']['type'];
        $cartNum = $cart['cart_num'];
        if (!$type)
            return $cartNum;
        else if ($type == 2) {
            return bcmul($cartNum, $cart['productAttr']['volume'], 2);
        } else {
            return bcmul($cartNum, $cart['productAttr']['weight'], 2);
        }
    }

    public function cartByPrice($cart)
    {
        if ($cart['product_type'] == '2') {
            return $cart['productPresellAttr']['presell_price'];
        } else if ($cart['product_type'] == '3') {
            return $cart['productAssistAttr']['assist_price'];
        } else if ($cart['product_type'] == '4') {
            return $cart['activeSku']['active_price'];
        } else {
            return $cart['productAttr']['price'];
        }
    }

    public function cartByCouponPrice($cart)
    {
        if ($cart['product_type'] == '2') {
            return $cart['productPresellAttr']['final_price'];
        } else if ($cart['product_type'] == '1') {
            return 0;
        } else if ($cart['product_type'] == '3') {
            return 0;
        } else if ($cart['product_type'] == '4') {
            return 0;
        } else {
            return $cart['productAttr']['price'];
        }
    }

    public function cartByDownPrice($cart)
    {
        if ($cart['product_type'] == '2') {
            return $cart['productPresellAttr']['down_price'];
        } else {
            return 0;
        }
    }


    /**
     * @param int $uid
     * @return array
     * @author xaboy
     * @day 2020/6/10
     */
    public function userOrderNumber(int $uid)
    {
        $noPay = app()->make(StoreGroupOrderRepository::class)->orderNumber($uid);
        $noPostage = $this->dao->search(['uid' => $uid, 'status' => 0, 'paid' => 1])->where('StoreOrder.is_del', 0)->count();
        $all = $this->dao->search(['uid' => $uid, 'paid' => 1])->where('StoreOrder.is_del', 0)->count();
        $noDeliver = $this->dao->search(['uid' => $uid, 'status' => 1, 'paid' => 1])->where('StoreOrder.is_del', 0)->count();
        $noComment = $this->dao->search(['uid' => $uid, 'status' => 2, 'paid' => 1])->where('StoreOrder.is_del', 0)->count();
        $done = $this->dao->search(['uid' => $uid, 'status' => 3, 'paid' => 1])->where('StoreOrder.is_del', 0)->count();
        $refund = app()->make(StoreRefundOrderRepository::class)->getWhereCount(['uid' => $uid, 'status' => [0, 1, 2]]);
        //$orderPrice = $this->dao->search(['uid' => $uid, 'paid' => 1])->sum('pay_price');
        $orderCount = $this->dao->search(['uid' => $uid, 'paid' => 1])->count();
        return compact('noComment', 'done', 'refund', 'noDeliver', 'noPay', 'noPostage', 'orderCount', 'all');
    }

    /**
     * @param $id
     * @param null $uid
     * @return array|Model|null
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @author xaboy
     * @day 2020/6/10
     */
    public function getDetail($id, $uid = null)
    {
        $where = [];
        $with = ['orderProduct', 'merchant' => function ($query) {
            return $query->field('mer_id,mer_name');
        }];
        if ($uid) {
            $where['uid'] = $uid;
        } else if (!$uid) {
            $with['user'] = function ($query) {
                return $query->field('uid,nickname');
            };
        }
        $order = $this->dao->search($where)->where('order_id', $id)->where('StoreOrder.is_del', 0)->with($with)->append(['refund_status'])->find();
        if (!$order) {
            return null;
        }
        if ($order->activity_type == 2) {
            if ($order->presellOrder) {
                $order->presellOrder->append(['activeStatus']);
                $order->presell_price = bcadd($order->pay_price, $order->presellOrder->pay_price, 2);
            } else {
                $order->presell_price = $order->pay_price;
            }
        }
        return $order;
    }

    public function codeByDetail($code, $uid = null)
    {
        $where = [];
        if ($uid) $where['uid'] = $uid;
        return $this->dao->search($where)->where('verify_code', $code)->where('StoreOrder.is_del', 0)->with(['orderProduct', 'merchant' => function ($query) {
            return $query->field('mer_id,mer_name');
        }])->find();
    }

    public function giveIntegral($groupOrder)
    {
        if ($groupOrder->give_integral > 0) {
            app()->make(UserBillRepository::class)->incBill($groupOrder->uid, 'integral', 'lock', [
                'link_id' => $groupOrder['group_order_id'],
                'status' => 0,
                'title' => '下单赠送积分',
                'number' => $groupOrder->give_integral,
                'mark' => '成功消费' . floatval($groupOrder['pay_price']) . '元,赠送积分' . floatval($groupOrder->give_integral),
                'balance' => $groupOrder->user->integral
            ]);
        }
    }

    /**
     * @param StoreOrder $order
     * @param User $user
     * @author xaboy
     * @day 2020/8/3
     */
    public function computed(StoreOrder $order, User $user)
    {
        $userBillRepository = app()->make(UserBillRepository::class);
        if ($order->is_selfbuy) {
            $spreadUid = $user->uid;
            $topUid = $user->spread_uid;
        } else {
            $spreadUid = $user->spread_uid;
            $topUid = $user->top_uid;
        }
        //TODO 添加冻结佣金
        if ($order->extension_one > 0 && $spreadUid) {
            $userBillRepository->incBill($spreadUid, 'brokerage', 'order_one', [
                'link_id' => $order['order_id'],
                'status' => 0,
                'title' => '获得推广佣金',
                'number' => $order->extension_one,
                'mark' => $user['nickname'] . '成功消费' . floatval($order['pay_price']) . '元,奖励推广佣金' . floatval($order->extension_one),
                'balance' => 0
            ]);
            $userRepository = app()->make(UserRepository::class);
            $userRepository->incBrokerage($spreadUid, $order->extension_one);
//            app()->make(FinancialRecordRepository::class)->dec([
//                'order_id' => $order->order_id,
//                'order_sn' => $order->order_sn,
//                'user_info' => $userRepository->getUsername($spreadUid),
//                'user_id' => $spreadUid,
//                'financial_type' => 'brokerage_one',
//                'number' => $order->extension_one,
//            ], $order->mer_id);
        }
        if ($order->extension_two > 0 && $topUid) {
            $userBillRepository->incBill($topUid, 'brokerage', 'order_two', [
                'link_id' => $order['order_id'],
                'status' => 0,
                'title' => '获得推广佣金',
                'number' => $order->extension_two,
                'mark' => $user['nickname'] . '成功消费' . floatval($order['pay_price']) . '元,奖励推广佣金' . floatval($order->extension_two),
                'balance' => 0
            ]);
            $userRepository = app()->make(UserRepository::class);
            $userRepository->incBrokerage($topUid, $order->extension_two);
//            app()->make(FinancialRecordRepository::class)->dec([
//                'order_id' => $order->order_id,
//                'order_sn' => $order->order_sn,
//                'user_info' => $userRepository->getUsername($topUid),
//                'user_id' => $topUid,
//                'financial_type' => 'brokerage_two',
//                'number' => $order->extension_two,
//            ], $order->mer_id);
        }
    }

    /**
     * @param StoreOrder $order
     * @param User $user
     * @param string $type
     * @author xaboy
     * @day 2020/8/3
     */
    public function takeAfter(StoreOrder $order, User $user)
    {
        Db::transaction(function () use ($user, $order) {
            $this->computed($order, $user);
            //TODO 确认收货
            app()->make(StoreOrderStatusRepository::class)->status($order->order_id, 'take', '已收货');
            Queue::push(SendTemplateMessageJob::class, [
                'tempCode' => 'ORDER_TAKE_SUCCESS',
                'id' => $order->order_id
            ]);
            Queue::push(SendSmsJob::class, [
                'tempId' => 'TAKE_DELIVERY_CODE',
                'id' => $order->order_id
            ]);
            Queue::push(SendSmsJob::class, [
                'tempId' => 'ADMIN_TAKE_DELIVERY_CODE',
                'id' => $order->order_id
            ]);
            $order->save();
        });
    }

    /**
     * @param $id
     * @param User $user
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @author xaboy
     * @day 2020/6/17
     */
    public function takeOrder($id, ?User $user = null)
    {
        $order = $this->dao->search(!$user ? [] : ['uid' => $user->uid], null)->where('order_id', $id)->where('StoreOrder.is_del', 0)->find();
        if (!$order)
            throw new ValidateException('订单不存在');
        if ($order['status'] != 1 || $order['order_type'])
            throw new ValidateException('订单状态有误');
        if (!$user) $user = $order->user;
        $order->status = 2;
        $order->verify_time = date('Y-m-d H:i:s');
        Db::transaction(function () use ($order, $user) {
            $this->takeAfter($order, $user);
            $order->save();
        });
    }


    /**
     *  获取订单列表头部统计数据
     * @Author:Qinii
     * @Date: 2020/9/12
     * @param int|null $merId
     * @param int|null $orderType
     * @return array
     */
    public function OrderTitleNumber(?int $merId, ?int $orderType)
    {
        $where = [];
        $sysDel = $merId ? 0 : null;                    //商户删除
        if ($merId) $where['mer_id'] = $merId;          //商户订单
        if ($orderType === 0) $where['order_type'] = 0; //普通订单
        if ($orderType === 1) $where['take_order'] = 1; //已核销订单
        //1: 未支付 2: 未发货 3: 待收货 4: 待评价 5: 交易完成 6: 已退款 7: 已删除
        $all = $this->dao->search($where, $sysDel)->where($this->getOrderType(0))->count();
        $statusAll = $all;
        $unpaid = $this->dao->search($where, $sysDel)->where($this->getOrderType(1))->count();
        $unshipped = $this->dao->search($where, $sysDel)->where($this->getOrderType(2))->count();
        $untake = $this->dao->search($where, $sysDel)->where($this->getOrderType(3))->count();
        $unevaluate = $this->dao->search($where, $sysDel)->where($this->getOrderType(4))->count();
        $complete = $this->dao->search($where, $sysDel)->where($this->getOrderType(5))->count();
        $refund = $this->dao->search($where, $sysDel)->where($this->getOrderType(6))->count();
        $del = $this->dao->search($where, $sysDel)->where($this->getOrderType(7))->count();

        return compact('all', 'statusAll', 'unpaid', 'unshipped', 'untake', 'unevaluate', 'complete', 'refund', 'del');
    }

    public function orderType(array $where)
    {
        return [
            [
                'count' => $this->dao->search($where)->count(),
                'title' => '全部',
                'order_type' => -1,
            ],
            [
                'count' => $this->dao->search($where)->where('order_type', 0)->count(),
                'title' => '普通订单',
                'order_type' => 0,
            ],
            [
                'count' => $this->dao->search($where)->where('order_type', 1)->count(),
                'title' => '核销订单',
                'order_type' => 1,
            ],
        ];
    }

    /**
     * @param $status
     * @return mixed
     * @author Qinii
     */
    public function getOrderType($status)
    {
        $param['StoreOrder.is_del'] = 0;
        switch ($status) {
            case 1:
                $param['paid'] = 0;
                break;    // 未支付
            case 2:
                $param['paid'] = 1;
                $param['StoreOrder.status'] = 0;
                break;  // 待发货
            case 3:
                $param['StoreOrder.status'] = 1;
                break;  // 待收货
            case 4:
                $param['StoreOrder.status'] = 2;
                break;  // 待评价
            case 5:
                $param['StoreOrder.status'] = 3;
                break;  // 交易完成
            case 6:
                $param['StoreOrder.status'] = -1;
                break;  // 已退款
            case 7:
                $param['StoreOrder.is_del'] = 1;
                break;  // 已删除
            default:
                unset($param['StoreOrder.is_del']);
                break;  //全部
        }
        return $param;
    }

    /**
     * @param int $id
     * @param int|null $merId
     * @return array|Model|null
     * @author Qinii
     */
    public function merDeliveryExists(int $id, ?int $merId)
    {
        $where = ['order_id' => $id, 'is_del' => 0, 'paid' => 1];
        if ($merId) $where['mer_id'] = $merId;
        return $this->dao->merFieldExists($where);
    }

    /**
     * TODO
     * @param int $id
     * @param int|null $merId
     * @return bool
     * @author Qinii
     * @day 2020-06-11
     */
    public function merGetDeliveryExists(int $id, ?int $merId)
    {
        $where = ['order_id' => $id, 'is_del' => 0, 'paid' => 1, 'status' => 1];
        if ($merId) $where['mer_id'] = $merId;
        return $this->dao->merFieldExists($where);
    }

    /**
     * @param int $id
     * @param int|null $merId
     * @return array|Model|null
     * @author Qinii
     */
    public function merStatusExists(int $id, ?int $merId)
    {
        $where = ['order_id' => $id, 'is_del' => 0, 'paid' => 0, 'status' => 0];
        if ($merId) $where['mer_id'] = $merId;
        return $this->dao->merFieldExists($where);
    }

    public function userDelExists(int $id, ?int $merId)
    {
        $where = ['order_id' => $id, 'is_del' => 1];
        if ($merId) $where['mer_id'] = $merId;
        return $this->dao->merFieldExists($where);
    }

    /**
     * @param $id
     * @return Form
     * @author Qinii
     */
    public function form($id)
    {
        $data = $this->dao->getWhere([$this->dao->getPk() => $id], 'total_price,pay_price,total_postage,pay_postage');
        $form = Elm::createForm(Route::buildUrl('merchantStoreOrderUpdate', ['id' => $id])->build());
        $form->setRule([
            Elm::number('total_price', '订单总价', $data['total_price'])->required(),
            Elm::number('total_postage', '订单邮费', $data['total_postage'])->required(),
            Elm::number('pay_price', '实际支付金额', $data['pay_price'])->required(),
        ]);
        return $form->setTitle('修改订单');
    }

    /**
     * TODO 修改订单价格
     * @param int $id
     * @param array $data
     * @author Qinii
     * @day 12/15/20
     */
    public function eidt(int $id, array $data)
    {

        /**
         * 1 计算出新的实际支付价格
         *      1.1 计算邮费
         *      1.2 计算商品总价
         * 2 修改订单信息
         * 3 计算总单数据
         * 4 修改总单数据
         * 5 修改订单商品单价
         *
         * pay_price = total_price - coupon_price + pay_postage
         */
        $order = $this->dao->get($id);
        if ($order->activity_type == 2) {
            throw new ValidateException('预售订单不支持改价');
        }
        $extension_total = (float)bcadd($order->extension_one, $order->extension_two, 2);
        $data['pay_price'] = $this->bcmathPrice($data['total_price'], $order['coupon_price'], $data['pay_postage']);
        if ($data['pay_price'] < 0) {
            throw new ValidateException('实际支付金额不能小于0');
        } else if ($data['pay_price'] < $extension_total) {
            throw new ValidateException('实际支付金额不能小于佣金' . $extension_total);
        }
        $make = app()->make(StoreGroupOrderRepository::class);
        $orderGroup = $make->dao->getWhere(['group_order_id' => $order['group_order_id']]);

        //总单总价格
        $_group['total_price'] = $this->bcmathPrice($orderGroup['total_price'], $order['total_price'], $data['total_price']);
        //总单实际支付价格
        $_group['pay_price'] = $this->bcmathPrice($orderGroup['pay_price'], $order['pay_price'], $data['pay_price']);
        //总单实际支付邮费
        $_group['pay_postage'] = $this->bcmathPrice($orderGroup['pay_postage'], $order['pay_postage'], $data['pay_postage']);
        Db::transaction(function () use ($id, $data, $orderGroup, $order, $_group) {
            $orderGroup->total_price = $_group['total_price'];
            $orderGroup->pay_price = $_group['pay_price'];
            $orderGroup->pay_postage = $_group['pay_postage'];
            $orderGroup->group_order_sn = $this->getNewOrderId() . '0';
            $orderGroup->save();

            $this->dao->update($id, $data);
            $this->changOrderProduct($id, $data);

            app()->make(StoreOrderStatusRepository::class)->status($id, 'change', '订单信息修改');
            if ($data['pay_price'] != $order['pay_price']) Queue::push(SendSmsJob::class, ['tempId' => 'PRICE_REVISION_CODE', 'id' => $id]);
        });
    }

    /**
     * TODO 改价后重新计算每个商品的单价
     * @param int $orderId
     * @param array $data
     * @author Qinii
     * @day 12/15/20
     */
    public function changOrderProduct(int $orderId, array $data)
    {
        $make = app()->make(StoreOrderProductRepository::class);
        $ret = $make->getSearch(['order_id' => $orderId])->field('order_product_id,product_num,product_price')->select();
        $count = $make->getSearch(['order_id' => $orderId])->sum('product_price');
        $_count = (count($ret->toArray()) - 1);
        $pay_price = $data['total_price'];
        foreach ($ret as $k => $item) {
            $_price = 0;
            /**
             *  比例 =  单个商品总价 / 订单原总价；
             *
             *  新的商品总价 = 比例 * 订单修改总价
             *
             *  更新数据库
             */
            if ($k == $_count) {
                $_price = $pay_price;
            } else {
                $_reta = bcdiv($item->product_price, $count, 3);
                $_price = bcmul($_reta, $data['total_price'], 2);
            }

            $item->product_price = $_price;
            $item->save();

            $pay_price = $this->bcmathPrice($pay_price, $_price, 0);
        }
    }

    /**
     * TODO 计算的重复利用
     * @param $total
     * @param $old
     * @param $new
     * @return int|string
     * @author Qinii
     * @day 12/15/20
     */
    public function bcmathPrice($total, $old, $new)
    {
        $_bcsub = bcsub($total, $old, 2);
        $_count = (bccomp($_bcsub, 0, 2) == -1) ? 0 : $_bcsub;
        $count = bcadd($_count, $new, 2);
        return (bccomp($count, 0, 2) == -1) ? 0 : $count;
    }

    /**
     * @param $id
     * @param $uid
     * @return mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @author xaboy
     * @day 2020/6/12
     */
    public function refundProduct($id, $uid)
    {
        $order = $this->dao->userOrder($id, $uid);
        if (!$order)
            throw new ValidateException('订单不存在');
        if (!count($order->refundProduct))
            throw new ValidateException('没有可退款商品');
        return $order->refundProduct->toArray();
    }

    /**
     * TODO
     * @param $id
     * @param $data
     * @return mixed
     * @author Qinii
     * @day 7/26/21
     */
    public function orderDumpInfo($id,$data,$merId)
    {
        $where = [
            'order_id' => $id,
        ];
        $ret = $this->dao->getWhere($where);
        $cargo = '';
        $count = 0;
        foreach ($ret->orderProduct as $item) {
//            $cargo .= $item['cart_info']['product']['store_name']. ' ' .$item['cart_info']['productAttr']['sku']  .' * ' .$item['product_num'].$item['cart_info']['product']['unit_name'].PHP_EOL;
            $count += $item['product_num'];
        }

        $data['to_name'] = $ret['real_name'];
        $data['to_tel'] = $ret['user_phone'];
        $data['to_addr'] = $ret['user_address'];
        $data['cargo'] = $cargo;
        $data['count'] = $count;
        $data['order_sn'] = $ret['order_sn'];
        return $data;
    }

    /**
     * TODO 批量发货
     * @param int $merId
     * @param array $params
     * @author Qinii
     * @day 7/26/21
     */
    public function batchDelivery(int $merId, array $params)
    {
        $count = count($params['order_id']);
        $import = app()->make(StoreImportRepository::class)->create($merId,'delivery',$params['delivery_type']);
        $make = app()->make(StoreImportDeliveryRepository::class);
        $data = [];
        $num = 0;

        foreach ($params['order_id'] as $item) {
            $ret = $this->dao->getWhere(['order_id' => $params['order_id']]);
            $imp =[
                'order_sn' =>  $ret['order_sn'] ?? $item,
                'delivery_id'   => $params['delivery_id'],
                'delivery_type' => $params['delivery_type'],
                'delivery_name' => $params['delivery_name'],
                'import_id' => $import['import_id'],
                'mer_id' => $merId
            ];

            if (!$ret ||
                $ret['mer_id'] != $merId ||
                $ret['is_del'] != 0 ||
                $ret['paid'] != 1 ||
                $ret['delivery_type'] != 0
            ){
                $imp['status'] = 0;
                $imp['mark'] = '订单信息不存在或状态错误';
            } else {

                switch ($params['delivery_type']){
                    case 4:  //电子面单
                        $dump = [
                            'temp_id'   => $params['temp_id'],
                            'from_tel'  => $params['from_tel'],
                            'from_addr' => $params['from_addr'],
                            'from_name' => $params['from_name'],
                            'delivery_name'=> $params['delivery_name'],
                        ];
                        $dump = $this->orderDumpInfo($item,$dump,$merId);
                        try {
                            $ret = $this->dump($item, $merId, $dump);
                            $num++;
                            $imp['delivery_id'] = $ret['delivery_id'];
                            $imp['delivery_name'] = $ret['delivery_name'];
                            $imp['status'] = 1;
                        } catch (Exception $exception) {
                            $imp['status'] = 0;
                            $imp['mark'] = $exception->getMessage();
                        }
                        break;
                    default:
                        try{
                            $this->delivery($item,[
                                'delivery_id'   => $params['delivery_id'],
                                'delivery_type' => $params['delivery_type'],
                                'delivery_name' => $params['delivery_name'],
                            ]);
                            $num++;
                            $imp['status'] = 1;
                        }catch (Exception $exception){
                            $imp['status'] = 0;
                            $imp['mark'] = $exception->getMessage();
                        }
                        break;
                }

            }
            $data[] = $imp;
        }

        $_status = ($num == 0)  ? -1 : (($count == $num) ?  1 : 10);
        $make->insertAll($data);
        $arr = ['count'=> $count,'success' => $num,'status' => $_status];
        app()->make(StoreImportRepository::class)->update($import['import_id'],$arr);
    }


    /**
     * TODO 打印电子面单，组合参数
     * @param int $id
     * @param int $merId
     * @param array $data
     * @return mixed
     * @author Qinii
     * @day 7/26/21
     */
    public function dump(int $id, int $merId, array $data)
    {
        $make = app()->make(MerchantRepository::class);
        $make->checkCrmebNum($merId,'dump');

        $data = $this->orderDumpInfo($id,$data,$merId);

        $data['com'] = $data['delivery_name'];
        $result = app()->make(CrmebServeServices::class)->express()->dump($merId,$data);
        if(!isset($result['kuaidinum'])) throw new ValidateException('打印失败');

        $delivery = [
            'delivery_type' => 4,
            'delivery_name' => $data['delivery_name'],
            'delivery_id' => $result['kuaidinum']
        ];

        $dump = [
            'delivery_name' => $delivery['delivery_name'],
            'delivery_id' => $delivery['delivery_id'],
            'from_name' => $data['from_name'],
            'order_sn' => $data['order_sn'],
            'to_name' => $data['to_name'],
        ];
        Db::transaction(function () use($merId, $id, $delivery, $make, $dump){
            $this->delivery($id, $delivery);
            $arr = [
                'type' => 'mer_dump',
                'num' => -1,
                'message' => '电子面单',
                'info' => $dump
            ];
            app()->make(ProductCopyRepository::class)->add($arr, $merId);
        });
        return $delivery;
    }

    /**
     * TODO 发货订单操作
     * @param $id
     * @param $data
     * @return mixed
     * @author Qinii
     * @day 7/26/21
     */
    public function delivery($id, $data)
    {
        $data['status'] = 1;
        $order = $this->dao->get($id);

        if ($data['delivery_type'] == 1) {
            $exprss = app()->make(ExpressRepository::class)->getWhere(['code' => $data['delivery_name']]);
            if (!$exprss) throw new ValidateException('快递公司不存在');
            $data['delivery_name'] = $exprss['name'];
            $change_type = 'delivery_0';
            $change_message = '订单已配送【快递名称】:' . $exprss['name'] . '; 【快递单号】：' . $data['delivery_id'];
            $temp_code = 'ORDER_POSTAGE_SUCCESS';
        }

        if ($data['delivery_type'] == 2) {
            if (!preg_match("/^1[3456789]{1}\d{9}$/", $data['delivery_id'])) throw new ValidateException('手机号格式错误');
            $change_type = 'delivery_1';
            $change_message = '订单已配送【送货人姓名】:' . $data['delivery_name'] . '; 【手机号】：' . $data['delivery_id'];
            $temp_code = 'DELIVER_GOODS_CODE';
        }

        if ($data['delivery_type'] == 3) {
            $change_type = 'delivery_2';
            $change_message = '订单已配送【虚拟发货】';
        }

        if ($data['delivery_type'] == 4) {
            $exprss = app()->make(ExpressRepository::class)->getWhere(['code' => $data['delivery_name']]);
            if (!$exprss) throw new ValidateException('快递公司不存在');
            $data['delivery_name'] = $exprss['name'];
            $change_type = 'delivery_0';
            $change_message = '订单已配送【快递名称】:' . $exprss['name'] . '; 【快递单号】：' . $data['delivery_id'];
            $temp_code = 'ORDER_POSTAGE_SUCCESS';
        }

        $this->dao->update($id, $data);

        app()->make(StoreOrderStatusRepository::class)->status($id, $change_type, $change_message);
        if(isset($temp_code)) queue::push(SendTemplateMessageJob::class, ['tempCode' => $temp_code, 'id' => $order['order_id']]);
        return $data;
    }

    public function getOne($id, ?int $merId)
    {
        $where = [$this->getPk() => $id];
        if ($merId) {
            $whre['mer_id'] = $merId;
            $whre['is_system_del'] = 0;
        }
        return $this->dao->getWhere($where, '*', ['user' => function ($query) {
            $query->field('uid,real_name,nickname');
        }, 'finalOrder']);
    }

    public function getOrderStatus($id, $page, $limit)
    {
        return app()->make(StoreOrderStatusRepository::class)->search($id, $page, $limit);
    }

    public function remarkForm($id)
    {
        $data = $this->dao->get($id);
        $form = Elm::createForm(Route::buildUrl('merchantStoreOrderRemark', ['id' => $id])->build());
        $form->setRule([
            Elm::text('remark', '备注', $data['remark'])->required(),
        ]);
        return $form->setTitle('修改备注');
    }

    public function adminMarkForm($id)
    {
        $data = $this->dao->get($id);
        $form = Elm::createForm(Route::buildUrl('systemMerchantOrderMark', ['id' => $id])->build());
        $form->setRule([
            Elm::text('admin_mark', '备注', $data['admin_mark'])->required(),
        ]);
        return $form->setTitle('修改备注');
    }

    /**
     * TODO 平台每个商户的订单列表
     * @param $where
     * @param $page
     * @param $limit
     * @return array
     * @author Qinii
     * @day 2020-06-15
     */
    public function adminMerGetList($where, $page, $limit)
    {
        $where['paid'] = 1;
        $query = $this->dao->search($where, null);
        $count = $query->count();
        $list = $query->with([
            'orderProduct',
            'merchant' => function ($query) {
                $query->field('mer_id,mer_name,is_trader');
            },
            'groupOrder' => function ($query) {
                $query->field('group_order_id,group_order_sn');
            },
            'finalOrder',
        ])->page($page, $limit)->select();

        return compact('count', 'list');
    }

    public function reconList($where, $page, $limit)
    {
        $ids = app()->make(MerchantReconciliationOrderRepository::class)->getIds($where);
        $query = $this->dao->search([], null)->whereIn('order_id', $ids);
        $count = $query->count();
        $list = $query->with(['orderProduct'])->page($page, $limit)->select()->each(function ($item) {
            //(实付金额 - 一级佣金 - 二级佣金) * 抽成
            $commission_rate = ($item['commission_rate'] / 100);
            //佣金
            $_order_extension = bcadd($item['extension_one'], $item['extension_two'], 3);
            //手续费 =  (实付金额 - 一级佣金 - 二级佣金) * 比例
            $_order_rate = bcmul(bcsub($item['pay_price'], $_order_extension, 3), $commission_rate, 3);
            $item['order_extension'] = round($_order_extension, 2);
            $item['order_rate'] = round($_order_rate, 2);
            return $item;
        });

        return compact('count', 'list');
    }

    /**
     * @param array $where
     * @param $page
     * @param $limit
     * @return array
     * @author Qinii
     */
    public function merchantGetList(array $where, $page, $limit)
    {
        $status = $where['status'];
        unset($where['status']);
        $query = $this->dao->search($where)->where($this->getOrderType($status))
            ->with([
                'orderProduct',
                'merchant' => function ($query) {
                    $query->field('mer_id,mer_name');
                },
                'verifyService' => function ($query) {
                    $query->field('service_id,nickname');
                },
                'finalOrder',
                'groupUser.groupBuying'
            ]);
        $count = $query->count();
        $list = $query->page($page, $limit)->select();
        return compact('count', 'list');
    }

    /**
     * TODO 平台总的订单列表
     * @param array $where
     * @param $page
     * @param $limit
     * @return array
     * @author Qinii
     * @day 2020-06-15
     */
    public function adminGetList(array $where, $page, $limit)
    {
        $status = $where['status'];
        unset($where['status']);
        $query = $this->dao->search($where, null)->where($this->getOrderType($status))
            ->with([
                'orderProduct',
                'merchant' => function ($query) {
                    return $query->field('mer_id,mer_name,is_trader');
                },
                'verifyService' => function ($query) {
                    return $query->field('service_id,nickname');
                },
                'groupOrder' => function ($query) {
                    $query->field('group_order_id,group_order_sn');
                },
                'finalOrder',
                'groupUser.groupBuying'
            ]);
        $count = $query->count();
        $list = $query->page($page, $limit)->select();

        return compact('count', 'list');
    }

    public function getStat(array $where, $status)
    {
        $make = app()->make(StoreRefundOrderRepository::class);
        $presellOrderRepository = app()->make(PresellOrderRepository::class);

        //退款订单id
        $orderId = $this->dao->search($where)->where($this->getOrderType($status))->column('order_id');
        //退款金额
        $orderRefund = $make->refundPirceByOrder($orderId);
        //实际支付订单数量
        $all = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1)->count();
        //实际支付订单金额
        $countQuery = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1);
        $countOrderId = $countQuery->column('order_id');
        $countPay1 = $countQuery->sum('StoreOrder.pay_price');
        $countPay2 = $presellOrderRepository->search(['paid' => 1, 'order_ids' => $countOrderId])->sum('pay_price');
        $countPay = bcadd($countPay1, $countPay2, 2);

        //余额支付
        $banclQuery = $this->dao->search(array_merge($where, ['paid' => 1, 'pay_type' => 0]))->where($this->getOrderType($status));
        $banclOrderId = $banclQuery->column('order_id');
        $banclPay1 = $banclQuery->sum('StoreOrder.pay_price');
        $banclPay2 = $presellOrderRepository->search(['pay_type' => [0], 'paid' => 1, 'order_ids' => $banclOrderId])->sum('pay_price');
        $banclPay = bcadd($banclPay1, $banclPay2, 2);

        //微信金额
        $wechatQuery = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1)->where('pay_type', 'in', [1, 2, 3, 6]);
        $wechatOrderId = $wechatQuery->column('order_id');
        $wechatPay1 = $wechatQuery->sum('StoreOrder.pay_price');
        $wechatPay2 = $presellOrderRepository->search(['pay_type' => [1, 2, 3, 6], 'paid' => 1, 'order_ids' => $wechatOrderId])->sum('pay_price');
        $wechatPay = bcadd($wechatPay1, $wechatPay2, 2);

        //支付宝金额
        $aliQuery = $this->dao->search($where)->where($this->getOrderType($status))->where('paid', 1)->where('pay_type', 'in', [4, 5]);
        $aliOrderId = $aliQuery->column('order_id');
        $aliPay1 = $aliQuery->sum('StoreOrder.pay_price');
        $aliPay2 = $presellOrderRepository->search(['pay_type' => [4, 5], 'paid' => 1, 'order_ids' => $aliOrderId])->sum('pay_price');
        $aliPay = bcadd($aliPay1, $aliPay2, 2);


        $stat = [
            [
                'className' => 'el-icon-s-goods',
                'count' => $all,
                'field' => '件',
                'name' => '已支付订单数量'
            ],
            [
                'className' => 'el-icon-s-order',
                'count' => (float)$countPay,
                'field' => '元',
                'name' => '实际支付金额'
            ],
            [
                'className' => 'el-icon-s-cooperation',
                'count' => (float)$orderRefund,
                'field' => '元',
                'name' => '已退款金额'
            ],
            [
                'className' => 'el-icon-s-cooperation',
                'count' => (float)$wechatPay,
                'field' => '元',
                'name' => '微信支付金额'
            ],
            [
                'className' => 'el-icon-s-finance',
                'count' => (float)$banclPay,
                'field' => '元',
                'name' => '余额支付金额'
            ],
            [
                'className' => 'el-icon-s-cooperation',
                'count' => (float)$aliPay,
                'field' => '元',
                'name' => '支付宝支付金额'
            ],
        ];
        return $stat;
    }

    /**
     * @param array $where
     * @param $page
     * @param $limit
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @author xaboy
     * @day 2020/6/10
     */
    public function getList(array $where, $page, $limit)
    {
        $query = $this->dao->search($where)->where('StoreOrder.is_del', 0);
        $count = $query->count();
        $list = $query->with(['orderProduct', 'presellOrder', 'merchant' => function ($query) {
            return $query->field('mer_id,mer_name');
        }])->page($page, $limit)->order('pay_time DESC')->append(['refund_status'])->select();

        foreach ($list as $order) {
            if ($order->activity_type == 2) {
                if ($order->presellOrder) {
                    $order->presellOrder->append(['activeStatus']);
                    $order->presell_price = bcadd($order->pay_price, $order->presellOrder->pay_price, 2);
                } else {
                    $order->presell_price = $order->pay_price;
                }
            }
        }

        return compact('list', 'count');
    }

    public function userList($uid, $page, $limit)
    {
        $query = $this->dao->search([
            'uid' => $uid,
            'paid' => 1
        ]);
        $count = $query->count();
        $list = $query->page($page, $limit)->select();
        return compact('count', 'list');
    }


    public function userMerList($uid, $merId, $page, $limit)
    {
        $query = $this->dao->search([
            'uid' => $uid,
            'mer_id' => $merId,
            'paid' => 1
        ]);
        $count = $query->count();
        $list = $query->with(['presellOrder'])->page($page, $limit)->select();
        foreach ($list as $order) {
            if ($order->activity_type == 2 && $order->status >= 0 && $order->status < 10 && $order->presellOrder) {
                $order->pay_price = bcadd($order->pay_price, $order->presellOrder->pay_price, 2);
            }
        }
        return compact('count', 'list');
    }

    public function express($orderId,$merId)
    {
        $order = $this->dao->get($orderId);
        if ($order['mer_id']  != $merId)  throw new ValidateException('订单信息不存在');
        if (!in_array($order['delivery_type'],[1,4]))  throw new ValidateException('订单状态错误');
        return ExpressService::express($order['delivery_id'],$order['delivery_name']);
    }

    public function checkPrinterConfig(int $merId)
    {
        if (!merchantConfig($merId, 'printing_status'))
            throw new ValidateException('打印功能未开启');
        $config = [
            'clientId' => merchantConfig($merId, 'printing_client_id'),
            'apiKey' => merchantConfig($merId, 'printing_api_key'),
            'partner' => merchantConfig($merId, 'develop_id'),
            'terminal' => merchantConfig($merId, 'terminal_number')
        ];
        if (!$config['clientId'] || !$config['apiKey'] || !$config['partner'] || !$config['terminal'])
            throw new ValidateException('打印机配置错误');
        return $config;
    }

    /**
     * TODO 打印机
     * @param int $id
     * @param int $merId
     * @return bool|mixed|string
     * @author Qinii
     * @day 2020-07-30
     */
    public function printer(int $id, int $merId)
    {
        $res = $this->dao->getWhere(['order_id' => $id], '*', ['orderProduct', 'merchant' => function ($query) {
            $query->field('mer_id,mer_name');
        }]);
        foreach ($res['orderProduct'] as $item) {
            $product[] = [
                'store_name' => $item['cart_info']['product']['store_name'] . '【' . $item['cart_info']['productAttr']['sku'] . '】',
                'product_num' => $item['product_num'],
                'price' => bcdiv($item['product_price'], $item['product_num'], 2),
                'product_price' => $item['product_price'],
            ];
        }
        $data = [
            'order_sn' => $res['order_sn'],
            'pay_time' => $res['pay_time'],
            'real_name' => $res['real_name'],
            'user_phone' => $res['user_phone'],
            'user_address' => $res['user_address'],
            'total_price' => $res['total_price'],
            'coupon_price' => $res['coupon_price'],
            'pay_price' => $res['pay_price'],
            'total_postage' => $res['total_postage'],
            'pay_postage' => $res['pay_postage'],
            'mark' => $res['mark'],
        ];
        $config = $this->checkPrinterConfig($merId);
        $printer = new Printer('yi_lian_yun', $config);
        return $res = $printer->setPrinterContent([
            'name' => $res['merchant']['mer_name'],
            'orderInfo' => $data,
            'product' => $product
        ])->startPrinter();
    }

    public function verifyOrder($id, $merId, $serviceId)
    {
        $order = $this->dao->getWhere(['verify_code' => $id, 'mer_id' => $merId]);
        if (!$order)
            throw new ValidateException('订单不存在');
        if ($order->status == 2)
            throw new ValidateException('订单已核销');
        if ($order->status != 0)
            throw new ValidateException('订单状态有误');
        if (!$order->paid)
            throw new ValidateException('订单未支付');
        $order->status = 2;
        $order->verify_time = date('Y-m-d H:i:s');
        $order->verify_service_id = $serviceId;
        Db::transaction(function () use ($order) {
            $this->takeAfter($order, $order->user);
            $order->save();
        });
    }

    public function wxQrcode($orderId, $verify_code)
    {
        $siteUrl = systemConfig('site_url');
        $name = md5('owx' . $orderId . date('Ymd')) . '.jpg';
        $attachmentRepository = app()->make(AttachmentRepository::class);
        $imageInfo = $attachmentRepository->getWhere(['attachment_name' => $name]);

        if (isset($imageInfo['attachment_src']) && strstr($imageInfo['attachment_src'], 'http') !== false && curl_file_exist($imageInfo['attachment_src']) === false) {
            $imageInfo->delete();
            $imageInfo = null;
        }
        if (!$imageInfo) {
//            $codeUrl = set_http_type(rtrim($siteUrl, '/') . '/pages/admin/order_cancellation/index?verify_code=' . $verify_code, request()->isSsl() ? 0 : 1);//二维码链接
            $imageInfo = app()->make(QrcodeService::class)->getQRCodePath($verify_code, $name);
            if (is_string($imageInfo)) throw new ValidateException('二维码生成失败');

            $imageInfo['dir'] = tidy_url($imageInfo['dir'], null, $siteUrl);

            $attachmentRepository->create(systemConfig('upload_type') ?: 1, -2, $orderId, [
                'attachment_category_id' => 0,
                'attachment_name' => $imageInfo['name'],
                'attachment_src' => $imageInfo['dir']
            ]);
            $urlCode = $imageInfo['dir'];
        } else $urlCode = $imageInfo['attachment_src'];
        return $urlCode;
    }

    public function routineQrcode($orderId, $verify_code)
    {
        $name = md5('sort' . $orderId . date('Ymd')) . '.jpg';
        return app()->make(QrcodeService::class)->getRoutineQrcodePath($name, 'pages/admin/order_cancellation/index', 'verify_code=' . $verify_code);
    }

    /**
     * TODO 根据商品ID获取订单数
     * @param int $productId
     * @return int
     * @author Qinii
     * @day 2020-08-05
     */
    public function seckillOrderCounut(int $productId)
    {
        $where = [
            'activity_id' => $productId,
            'product_type' => 1,
            'day' => date('Y-m-d', time())
        ];
        $count = $this->dao->getTattendCount($where, null)->count();
        $count_ = $this->dao->getSeckillRefundCount($where, 2);
        $count__ = $this->dao->getSeckillRefundCount($where, 1);
        return $count - $count_ - $count__;
    }

    /**
     * TODO 根据商品sku获取订单数
     * @param int $productId
     * @return int
     * @author Qinii
     * @day 2020-08-05
     */
    public function seckillSkuOrderCounut(string $sku)
    {
        $where = [
            'product_sku' => $sku,
            'product_type' => 1,
            'day' => date('Y-m-d', time())
        ];
        $count = $this->dao->getTattendCount($where, null)->count();
        $count_ = $this->dao->getSeckillRefundCount($where, 2);
        $count__ = $this->dao->getSeckillRefundCount($where, 1);
        return $count - $count_ - $count__;
    }

    /**
     * TODO 获取sku的总销量
     * @param string $sku
     * @return int|mixed
     * @author Qinii
     * @day 3/4/21
     */
    public function skuSalesCount(string $sku)
    {
        $where = [
            'product_sku' => $sku,
            'product_type' => 1,
        ];
        $count = $this->dao->getTattendSuccessCount($where, null)->count();
        $count_ = $this->dao->getSeckillRefundCount($where, 2);
        $count__ = $this->dao->getSeckillRefundCount($where, 1);
        return $count - $count_ - $count__;
    }

    /**
     * TODO 秒杀获取个人当天限购
     * @param int $uid
     * @param int $productId
     * @return int
     * @author Qinii
     * @day 2020-08-15
     */
    public function getDayPayCount(int $uid, int $productId)
    {
        $make = app()->make(StoreSeckillActiveRepository::class);
        $active = $make->getWhere(['product_id' => $productId]);
        if ($active['once_pay_count'] == 0) return true;

        $where = [
            'activity_id' => $productId,
            'product_type' => 1,
            'day' => date('Y-m-d', time())
        ];

        $count = $this->dao->getTattendCount($where, $uid)->count();
        return ($active['once_pay_count'] > $count);
    }

    /**
     * TODO 秒杀获取个人总限购
     * @param int $uid
     * @param int $productId
     * @return int
     * @author Qinii
     * @day 2020-08-15
     */
    public function getPayCount(int $uid, int $productId)
    {
        $make = app()->make(StoreSeckillActiveRepository::class);
        $active = $make->getWhere(['product_id' => $productId]);
        if ($active['all_pay_count'] == 0) return true;
        $where = [
            'activity_id' => $productId,
            'product_type' => 1,
            'day' => date('Y-m-d', time())
        ];
        $count = $this->dao->getTattendCount($where, $uid)->count();
        return ($active['all_pay_count'] > $count);
    }

    /**
     *  根据订单id查看是否全部退款
     * @Author:Qinii
     * @Date: 2020/9/11
     * @param int $orderId
     * @return bool
     */
    public function checkRefundStatusById(int $orderId, int $refundId)
    {
        return Db::transaction(function () use ($orderId, $refundId) {
            $res = $this->dao->search(['order_id' => $orderId])->with(['orderProduct'])->find();
            $refund = app()->make(StoreRefundOrderRepository::class)->getRefundCount($orderId, $refundId);
            if ($refund) return false;
            foreach ($res['orderProduct'] as $item) {
                if ($item['refund_num'] !== 0) return false;
                $item->is_refund = 3;
                $item->save();
            }
            $res->status = -1;
            $res->save();
            app()->make(StoreOrderStatusRepository::class)->status($orderId, 'refund_all', '订单已全部退款');
            return true;
        });
    }

    /**
     * @param $id
     * @param $uid
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @author xaboy
     * @day 2020/9/17
     */
    public function userDel($id, $uid)
    {
        $order = $this->dao->getWhere([['status', 'in', [0, 3, -1, 11]], ['order_id', '=', $id], ['uid', '=', $uid], ['is_del', '=', 0]]);
        if (!$order || ($order->status == 0 && $order->paid == 1))
            throw new ValidateException('订单状态有误');
        $this->delOrder($order, '订单删除');
    }

    public function delOrder($order, $info = '订单删除')
    {
        Db::transaction(function () use ($info, $order) {
            $order->is_del = 1;
            $order->save();
            app()->make(StoreOrderStatusRepository::class)->status($order->order_id, 'delete', $info);
            $productRepository = app()->make(ProductRepository::class);
            foreach ($order->orderProduct as $cart) {
                $productRepository->orderProductIncStock($order, $cart);
            }
        });
    }

    public function merDelete($id)
    {
        Db::transaction(function () use ($id) {
            $data['is_system_del'] = 1;
            $this->dao->update($id, $data);
            app()->make(StoreOrderReceiptRepository::class)->deleteByOrderId($id);
        });
    }

    /**
     * @param $id
     * @return \FormBuilder\Form
     * @author Qinii
     */
    public function sendProductForm($id, $data)
    {
        $express = app()->make(ExpressRepository::class)->options();
        $form = Elm::createForm(Route::buildUrl('merchantStoreOrderDelivery', ['id' => $id])->build());

        if (in_array($data['delivery_type'], [1, 2])) {
            if ($data['delivery_type'] == 1) {
                $form->setRule([
                    Elm::hidden('delivery_type', 1),
                    [
                        'type' => 'span',
                        'title' => '原快递名称',
                        'children' => [(string)$data['delivery_name']]
                    ],
                    [
                        'type' => 'span',
                        'title' => '原快递单号',
                        'children' => [(string)$data['delivery_id']]
                    ],
                    Elm::select('delivery_name', '快递名称')->options(function () use ($express) {
                        return $express;
                    }),
                    Elm::input('delivery_id', '快递单号')->required(),
                ]);
            } else {
                $form->setRule([
                    Elm::hidden('delivery_type', 2),
                    [
                        'type' => 'span',
                        'title' => '原送货人姓名',
                        'children' => [(string)$data['delivery_name']]
                    ],
                    [
                        'type' => 'span',
                        'title' => '原手机号',
                        'children' => [(string)$data['delivery_id']]
                    ],
                    Elm::input('delivery_name', '送货人姓名')->required(),
                    Elm::input('delivery_id', '手机号')->required(),
                ]);
            }
        }
        if ($data['delivery_type'] == 3) {
            $form->setRule([
                Elm::hidden('delivery_type', 3),
                [
                    'type' => 'span',
                    'title' => '发货类型',
                    'children' => ['无需物流']
                ]
            ]);
        }
        if (!$data['delivery_type']) {
            $form->setRule([
                Elm::radio('delivery_type', '发货类型', 1)
                    ->setOptions([
                        ['value' => 1, 'label' => '发货'],
                        ['value' => 2, 'label' => '送货'],
                        ['value' => 3, 'label' => '无需物流'],
                    ])->control([
                        [
                            'value' => 1,
                            'rule' => [
                                Elm::select('delivery_name', '快递名称')->options(function () use ($express) {
                                    return $express;
                                }),
                                Elm::input('delivery_id', '快递单号')->required(),
                            ]
                        ],
                        [
                            'value' => 2,
                            'rule' => [
                                Elm::input('delivery_name', '送货人姓名')->required(),
                                Elm::input('delivery_id', '手机号')->required(),
                            ]
                        ],
                        [
                            'value' => 3,
                            'rule' => []
                        ],

                    ]),
            ]);
        }

        return $form->setTitle('发货信息');
    }

    /**
     * TODO 导入发货信息
     * @param array $data
     * @param $merId
     * @author Qinii
     * @day 3/16/21
     */
    public function setWhereDeliveryStatus(array $arrary,$merId)
    {
        //读取excel
        $data = SpreadsheetExcelService::instance()->_import($arrary['path'],$arrary['sql'],$arrary['where'],4);
        if(!$data) return ;
        $import_id = $arrary['import_id'];
        Db::transaction(function() use ($data,$merId,$import_id){
            $result = [];
            $num = 0;
            $count = 0;
            $status = 0;
            foreach ($data as $datum){
                $value = [];
                $ret = [];
                if($datum['where']){
                    $count = $count +1;
                    if(empty($datum['value']['delivery_id'])){
                        $mark = '发货单号为空';
                    }else{
                        $ret = $this->getSearch([])
                            ->where('status',0)
                            ->where('paid',1)
                            ->where('order_type',0)
                            ->where('mer_id',$merId)
                            ->where($datum['where'])
                            ->find();
                        $mark = '数据有误或已发货';
                    }
                    if($ret){
                        try{
                            $value = array_merge($datum['value'],['status' => 1]);
                            $value['delivery_type'] = 1;
                            $this->delivery($ret['order_id'],$value);

                            $status = 1;
                            $mark = '';

                            $num = $num + 1;
                        }catch (\Exception $exception){
                            $mark = '数据库操作失败';
                        }
                    }
                    $datum['where']['mark'] = $mark;
                    $datum['where']['mer_id'] = $merId;
                    $datum['where']['status'] = $status;
                    $datum['where']['import_id'] = $import_id;
                    $result[] = array_merge($datum['where'],$datum['value']);
                }
            }
            // 记录入库操作
            if(!empty($result)) app()->make(StoreImportDeliveryRepository::class)->insertAll($result);
            $_status = ($count == $num) ? 1 : (($num < 1) ? -1 : 10 );
            app()->make(StoreImportRepository::class)->update($import_id,['count'=> $count,'success' => $num,'status' => $_status]);
        });
        if(file_exists($arrary['path'])) unlink($arrary['path']);
    }
}
