db->beginTransaction(); try { $mall_id = $activity['mall_id']; $order_arr = $order_ids; //中文配置 $customize_text = \Yii::$app->services->setting->addons->get($mall_id, LuckyGroupEnum::ADDONS_NAME, 'customize_text'); $customize_reward_name = \Yii::$app->services->setting->addons->get($mall_id, LuckyGroupEnum::ADDONS_NAME, 'customize_reward_name'); $customize_arr = array_merge($customize_text, $customize_reward_name); // 获取同一拼团同一商品,参团中的订单,抽中次数小于购买次数的订单 - 按时间顺序取拼团数量 $group_require_num = $activity['group_num']; //开团需要人数 $virtual_num = $activity['virtual_num']; //活动设置的虚拟人数 $real_group_require_num = $group_require_num - $virtual_num; //真实开团需要人数 $real_group_require_num = $real_group_require_num < 0 ? $group_require_num : $real_group_require_num; $configs['basic'] = \Yii::$app->services->setting->addons->get($mall_id, LuckyGroupEnum::ADDONS_NAME, 'basic'); $configs['bonus_pool'] = \Yii::$app->services->setting->addons->get($mall_id, LuckyGroupEnum::ADDONS_NAME, 'bonus_pool'); $joining_orders = LuckyGroupOrder::find() ->where(['id' => $order_ids, 'group_status' => 1]) ->andWhere(new \yii\db\Expression('`buy_nums` > `win_nums`')) ->indexBy('id') ->all(); $attend_order_num = count($joining_orders); //本次可开奖订单数(人数) echo '
';
            var_dump(
                '开团需要人数:' . $group_require_num,
                '活动设置的虚拟人数:' . $virtual_num,
                '真实开团需要人数:' . $real_group_require_num,
                '本次可开奖订单数(人数):' . $attend_order_num
            );
            // 随机拼中人数
            $random_win_num = ($activity['random_win_num'] <= 0) ? 1 : $activity['random_win_num'];
            if ($attend_order_num < $random_win_num) {
                //先删除订单id入队标记
                $queue_logic = new OrderPaidQueueLogic();
                $queue_logic->delOrderEnqueueFlag($order_arr);
                $order_id_enqueue = array_column($joining_orders, 'id');
                $queue_logic->enqueue($mall_id, $activity, $goods_id, $order_id_enqueue);
                return false;
            }
            $user_id_arr = array_column($joining_orders, 'user_id');
            $lottery_rules = new LotteryRulesLogic();
            $win_keys = $lottery_rules->checkWinOrLoss($mall_id, $joining_orders, $user_id_arr, $attend_order_num, $random_win_num, $configs['basic']);
            if (!is_array($win_keys)) $win_keys = [$win_keys];

            $this->updateGroupGoodsJoinNum($activity['id'], $goods_id, $attend_order_num);

            $group_users = LuckyGroupUser::lists(
                [
                    'where' => [
                        ['user_id' => $user_id_arr]
                    ],
                    'index' => 'user_id'
                ],
                false
            );
            $users = User::lists(
                [
                    'where' => [
                        ['id' => $user_id_arr]
                    ],
                    'index' => 'id'
                ]
            );
            $user_wallets = UserWallet::lists(
                [
                    'where' => [
                        ['user_id' => $user_id_arr]
                    ],
                    'index' => 'user_id'
                ],
                false
            );

            $win_log_list = LuckyGroupWinLog::lists([
                'where' => [
                    ['mall_id' => $mall_id],
                    ['activity_id' => $activity['id']],
                    ['status' => StatusEnum::ENABLED],
                    ['user_id' => $user_id_arr],
                ],
                'select' => 'user_id,sum(win_num) as win_num',
                'index' => 'user_id',
                'group' => 'user_id'
            ]);
            $expend_type = $activity['expend_type'] ?? ''; // 参团消耗类型
            $expend_num = $activity['expend_num'] ?? 0; // 参团消耗数量
            $yu_attend_times = $consume = 0;
            $order_ids = $win_order_ids = $loss_order_ids = '';
            $insert_wallet = $frozen_log_arr = $user_frozen_arr = $order_id_enqueue = [];
            $time = time();
            $attend_award_setting = json_decode($activity['attend_award_setting'], true);
            $win_award_setting = json_decode($activity['win_award_setting'], true);
            $bonus_pool = LuckyGroupBonusPool::findOne(['mall_id' => $mall_id, 'status' => StatusEnum::ENABLED]);
            $user_address_id_arr = [];
            $order_no_arr = [];
            $goods_attr_id = 0;
            foreach ($joining_orders as $key => $order) {
                $goods_attr_id = $order['goods_attr_id'];
                if (in_array($key, $win_keys)) {
                    $user_address_id_arr[] = $order['address_id'];
                    $order_no_arr[] = $order['order_no'];
                }
            }
            $pay_order_list = PaymentTradeOrder::lists(['where' => [['order_no' => $order_no_arr],['is_pay'=>1]], 'index' => 'order_no']);
            $trade_id_arr = array_column($pay_order_list, 'trade_id');
            $pay_trade_list = PaymentTrade::lists(['where' => [['id' => $trade_id_arr]], 'index' => 'id']);
            $user_address_arr = UserAddress::lists(['where' => [['id' => $user_address_id_arr]], 'index' => 'user_id']);

            $goods_attr = GoodsAttr::findOne(['id' => $goods_attr_id]);
            $goods = Goods::findOne(['id' => $goods_id]);
            $user_arr = [];
            $trans_pool_money = $subsidy = 0;
            $lottery_period_arr = [];
            $lottery_period = LuckyGroupLotteryPeriod::getOne([['activity_id' => $activity['id']], ['goods_id' => $goods_id]], false, [], 'number desc');
            $number = $lottery_period['number'] ?? 0;
            $win_money = $win_peoples = $attend_reward = 0;
            $loss_money = 0;
            $loss_peoples = 0;
            $attend_reward_amounts = 0;
            $win_reward_scores = 0;
            $win_reward_balances = 0;
            $group_failed_times = 0;
            $deplete_balances = 0;
            $deplete_scores = 0;
            $goods_price = 0;
            // 因为主商城订单在事务中。会导致触发事件时订单详情,所以需要一个数组存储
            $mainOrderList = [];
            foreach ($joining_orders as $key => $order) {
                $user_arr[$order['user_id']]['order_id'] = $order['id'];
                $goods_price = bcdiv($order['total_goods_price'] , $order['buy_nums'], 2);
                $order_ids .= $order['id'] . ',';
                //判断预扣参团次数是否大于0,是直接减预扣
                $attend_times = 0;
                if ($order['yu_attend_times'] <= 0) {
                    $res = $this->reduceAttendTimes($group_users, $order, $customize_arr);
                    if ($res == false) {
                        unset($joining_orders[$key]);
                        var_dump(3);
                        continue;
                    }
                    $attend_times = 1;
                } else {
                    $yu_attend_times = -1;
                }
                //消耗
                if ($expend_num > 0) {
                    if ($order['consume'] <= 0) {
                        $res = $this->reduceExpendNum($expend_type, $expend_num, $user_wallets, $order, $deplete_balances, $deplete_scores);
                        if ($res == false) {
                            unset($joining_orders[$key]);
                            var_dump(4);
                            continue;
                        }
                    } else {
                        $consume = -$expend_num;
                        if ($expend_type == LuckyGroupEnum::AWARD_TYPE_BALANCE) $deplete_balances += $expend_num;
                        if ($expend_type == LuckyGroupEnum::AWARD_TYPE_SCORE) $deplete_scores += $expend_num;
                    }
                }
                $res = $this->updateLuckyGroupUser($group_users[$order['user_id']], $order, $attend_times);
                if ($res == false) {
                    unset($joining_orders[$key]);
                    var_dump(2);
                    continue;
                }
                $res = $this->updateLuckyOrder($order, $yu_attend_times, $consume);
                if ($res == false) {
                    unset($joining_orders[$key]);
                    var_dump(1);
                    continue;
                }

                $win_user_id = $win_order_id = $loss_user_id = $loss_order_id = 0;
                $unit_price = $order['total_pay_price'] / $order['buy_nums'];
                if (in_array($key, $win_keys)) {
                    //生成主订单
                    $main_order = self::createMallOrder($order, $pay_order_list, $pay_trade_list, $user_address_arr, $goods, $goods_attr);
                    if ($main_order == false) {
                        //生成主订单失败,退款
                        //todo 退用户余额并修改状态为拼团失败
                        $desc = ('幸运拼团生成主订单失败');
                        var_dump('order_id:' . $order['id'] . $desc);
                        $order->group_status = 3;
                        $group_buy_text = Customize::to($customize_arr, 'group_buy_text');
                        $desc = ($group_buy_text ?? '幸运拼团') . '生成主订单失败';
                        $this->refundToBalance($order, $desc);
                        continue;
                    }

                    //拼中
                    $group_users[$order['user_id']]->win_num += 1;
                    $group_users[$order['user_id']]->save();
                    $order->group_status = LuckyGroupEnum::GROUP_SUCCESS;
                    $order->win_time = time();
                    $order->win_nums = $order->win_nums + 1;
                    //如果类型为自动拼团,并且购买数量大于中奖次数,则自动继续参与拼团
                    if ($order->attend_type == LuckyGroupEnum::ATTEND_TYPE_AUTO
                        && $order->buy_nums > $order->win_nums) {
                        $order->group_status = LuckyGroupEnum::GROUP_JOINING;
                        $order_id_enqueue[] = $order['id'];
                    }
                    $order->save();
                    $win_order_id = $order['id'];
                    $win_user_id = $order['user_id'];

                    $win_order_ids .= $win_order_id . ',';
                    $user_win_times = $win_log_list[$order['user_id']]['win_num'] ?? 0;

                    //生成拼中奖励
                    GroupRewardLogic::computeWinReward($win_award_setting, $mall_id, $win_user_id, $win_order_id, $activity['win_times'], $user_win_times+1, $insert_wallet, $win_reward_scores, $win_reward_balances, $customize_arr,
                        $order['order_no'],$order['user_id'],$goods_price,$goods['goods_name']);
                    try {
                        $mainOrderList[] = [
                            'id' => $main_order['id'],
                            'operator_id' => $main_order['user_id'],
                            'operator_name' => $users[$main_order['user_id']]['nickname'] ?? '',
                        ];
                    } catch (\Exception $e) {
                        var_dump($e->getMessage());
                    }

                    GroupRewardLogic::computePrizePool($configs, $order['id'], $group_users[$order['user_id']], $time, $bonus_pool['money'] ?? 0, $frozen_log_arr, $user_frozen_arr, $customize_arr);

                    $pool_trans_money = $activity['pool_trans_money']; //转到奖金池金额%
                    $is_percent_pool_trans = $activity['is_percent_pool_trans']; //是否按百分比算分配奖金池金额【1是 0否】
                    if ($pool_trans_money > 0) {
                        //计算转入奖金池金额,除以拼中订单购买数量
                        $trans_pool_money += $is_percent_pool_trans ? ($unit_price * $pool_trans_money / 100) : $pool_trans_money;
                    }
                    $win_money += $unit_price; //拼中金额
                    $win_peoples++;//拼中人数
                    LuckyGroupWinLog::setData(['mall_id'=>$mall_id,'user_id'=>$order['user_id'],'activity_id'=>$activity['id'],'win_num'=>1]);
                } else {
                    $group_failed_times += 1;
                    //拼不中
                    if ($order['attend_type'] == LuckyGroupEnum::ATTEND_TYPE_AUTO) {
                        $order_id_enqueue[] = $order['id'];
                        LuckyGroupWinLog::setData(['mall_id'=>$mall_id,'user_id'=>$order['user_id'],'activity_id'=>$activity['id'],'win_num'=>0]);
                    } else {
                        //拼团失败,退款
                        //todo 退用户余额并修改状态为拼团失败
                        $order->group_status = 3;
                        $group_buy_order_text = Customize::to($customize_arr, 'group_buy_order_text');
                        $join_team_text = Customize::to($customize_arr, 'join_team_text');
                        $desc = ($group_buy_order_text ?? '幸运拼团订单') . '(id:' . $order['id'] . ')' . ($join_team_text ?? '拼团') . '失败,退还购物金额';
                        var_dump('order_id:' . $order['id'] . $desc);
                        $this->refundToBalance($order, $desc);
                        $loss_order_id = $order['id'];
                        $loss_user_id = $order['user_id'];
                        $loss_order_ids .= $loss_order_id . ',';
                        $loss_money += $unit_price;
                        $loss_peoples++;//拼不中人数
                    }
                }
                $attend_reward_amounts += $unit_price;
                //生成参团奖励数据
                GroupRewardLogic::computeJoinReward($attend_award_setting, $activity['attend_user_type'], $mall_id,
                    $order['user_id'], $order['id'], $win_user_id, $win_order_id, $loss_user_id, $loss_order_id, $insert_wallet, $customize_arr, $attend_reward,
                    $order['order_no'],$order['user_id'],$goods_price,$goods['goods_name']
                );
                //生成推荐参团奖励数量
                GroupRewardLogic::computeInviteReward($mall_id, $goods_price, $configs, $order['id'], $users[$order['user_id']], $insert_wallet, $customize_arr,
                    $order['order_no'],$order['user_id'],$goods['goods_name']);
            }
            if (!empty($insert_wallet)) {
                $res = $this->sendUserWallet($insert_wallet, $group_users);
                if ($res == false) throw new Exception('发送资金队列失败');
            }
            //开团日志
            $params = [
                'mall_id' => $mall_id, 'goods_id' => $goods_id, 'group_require_num' => $group_require_num,
                'real_group_require_num' => $real_group_require_num,
                'activity_id' => $activity['id'], 'expend_type' => $expend_type, 'expend_num' => $expend_num,
                'virtual_num' => $virtual_num, 'attend_order_num' => $attend_order_num, 'order_id' => trim($order_ids, ','),
                'win_order_ids' => trim($win_order_ids, ','), 'win_reward_scores' => $win_reward_scores, 'win_reward_balances' => $win_reward_balances,
                'attend_reward_amounts' => $attend_reward_amounts,
                'distribute_bonus_pool_amounts' => $trans_pool_money,
            ];
            $open_reward_log_model = LuckyGroupOpenRewardLog::setData($params);
            if ($open_reward_log_model == false) throw new Exception('添加开团日志失败');

            //生成奖金池冻结数据
            if (!empty($frozen_log_arr)) {
                LuckyGroupFrozenLog::batchAdd($frozen_log_arr);
                if (!empty($user_frozen_arr)) {
                    foreach ($user_frozen_arr as $user_id => $money) {
                        $group_users[$user_id]->frozen_commission += $money;
                        $group_users[$user_id]->pool_commission += $money;
                        $group_users[$user_id]->save();
                    }
                }
            }

            // 参团等级佣金奖励发放
            if(MallAddons::isInstall($mall_id,AddonsEnum::ADDONS_NAME_AGENT)){
                GroupRewardLogic::sendGroupCommissionLog($configs, $joining_orders, $user_arr, $activity,$goods_price,$goods['goods_name']);
            }

            //先删除订单id入队标记
            $queue_logic = new OrderPaidQueueLogic();
            $queue_logic->delOrderEnqueueFlag($order_arr);
            if ($order_id_enqueue) {
                var_dump('重新入队订单id:' . implode(',', $order_id_enqueue));
                $queue_logic->enqueue($mall_id, $activity, $goods_id, $order_id_enqueue);
            }

            if ($trans_pool_money > 0) {
                LuckyGroupBonusPool::setData($bonus_pool, $mall_id, $trans_pool_money);
            }

            $send_sms_order_ids = [];
            foreach ($joining_orders as $key => $order) {
                $lottery_period_arr[] = [
                    $order['mall_id'],
                    $open_reward_log_model['id'],
                    $order['activity_id'],
                    $order['goods_id'],
                    $order['user_id'],
                    $order['id'],
                    $number + 1,
                    trim($win_order_ids, ','),
                    trim($loss_order_ids, ','),
                    StatusEnum::ENABLED,
                    $time,
                    $time,
                ];
                $send_sms_order_ids = $order['id'];
            }
            //添加期数
            LuckyGroupLotteryPeriod::setData($lottery_period_arr);
            //活动统计
            $params = [
                'activity_id' => $activity['id'],
                'mall_id' => $mall_id,
                'group_amounts' => $attend_reward_amounts,
                'group_peoples' => $random_win_num,
                'group_periods' => 1,
                'group_failed_times' => $group_failed_times,
                'deplete_balances' => $deplete_balances,
                'deplete_scores' => $deplete_scores,
                'win_reward_balances' => $win_reward_balances,
                'win_reward_scores' => $win_reward_scores,
                'distribute_bonus_pool_amounts' => $trans_pool_money,
            ];
            $res = LuckyGroupActivityStatistics::updateStatistics($params);
            //商城统计,按月
            $params = [
                'win_money' => $win_money,
                'win_peoples' => $win_peoples,
                'attend_commission' => $attend_reward,
                'mall_id' => $mall_id,
            ];
            var_dump('商城统计,按月');
            var_dump($params);
            $res = LuckyGroupMallStatistics::updateStatistics($params);
            //商城统计,按日
            $params = [
                'win_money' => $win_money,
                'loss_money' => $loss_money,
                'win_peoples' => $win_peoples,
                'loss_peoples' => $loss_peoples,
            ];
            $params['mall_id'] = $mall_id;
            $res = LuckyGroupMallOpenGroupStatistics::updateStatistics($params);
            $t->commit();
            if (!empty($mainOrderList)) { // 因为受到事务影响导致。执行队列事件是可能主商城订单详情并未创建成功。所以移动到事务外
                $event = new \common\events\order\OrderPaidEvent($mall_id);
                foreach ($mainOrderList as $main_order) {
                    $main_data['id'] = $main_order['id'];
                    $main_data['operator_id'] = $main_order['operator_id'] ?? 0;
                    $main_data['operator_name'] = $main_order['operator_name'];
                    \Yii::$app->services->events->dispatch($event, $main_data, $event->listeners);
                }
            }
            var_dump('开团成功');
            $send_service = new Notify();
            //发送短信通知 成功或失败
            $order_ids = explode(',', trim($order_ids, ','));
            \Yii::$app->custom->logs(__METHOD__ . "幸运拼团发送短信 " . json_encode($order_ids));
            if ($order_ids) {
                foreach ($order_ids as $order_id) {
                    \Yii::$app->custom->logs("幸运拼团发送短信 " . $order_id);
                    $send_service->send(['id' => $order_id]);
                }
            }

            return true;
        } catch (\Exception $e) {
            $t->rollBack();
            var_dump('openReward:err:' . $e->getMessage() . $e->getFile().$e->getLine());
            return false;
        }
    }

    public function sendUserWallet($insert_wallet, $group_users)
    {
        $mall_id = 0;
        // 批量插入数据
        try {
            //投递到资产队列
            if ($insert_wallet) {
                $res = UserWalletService::batchHandleByQueue($insert_wallet);
                if (empty($res)) throw new \Exception(UserWalletService::getStaticError());
                $arr = [];
                var_dump('sendUserWallet====insert_wallet'.json_encode($insert_wallet));
                foreach ($insert_wallet as $k => $item) {
                    $wallet_type = $item['wallet_type'];
                    $mall_id = $item['mall_id'];
                    if (isset($arr[$item['user_id']])) {
                        if (isset($arr[$item['user_id']][$wallet_type])) {
                            $arr[$item['user_id']][$wallet_type] += $item['money'];
                        } else {
                            $arr[$item['user_id']][$wallet_type] = $item['money'];
                        }
                    } else {
                        $arr[$item['user_id']] = [
                            $wallet_type => $item['money'],
                        ];
                    }
                }
                var_dump('sendUserWallet====arr'.json_encode($arr));
                foreach ($arr as $user_id => $value) {
                    if (isset($group_users[$user_id])) {
                        var_dump($user_id.'更新前'.$group_users[$user_id]->balance);
                        foreach ($value as $wallet_type => $money) {
                            $group_users[$user_id]->$wallet_type += $money;
                        }
                        $res = $group_users[$user_id]->save();
                        var_dump($user_id.'更新后'.$group_users[$user_id]->balance);
                        if (empty($res)) throw new \Exception('更新团长表奖励数额报错');
                    }else{
                        $lg_user = LuckyGroupUser::findOne(['user_id'=>$user_id,'mall_id'=>$mall_id,'status'=>1]);
                        if(empty($lg_user)){
                            $post  = ['user_id' => $user_id, 'level' => 0];
                            foreach ($value as $wallet_type => $money) {
                                $post[$wallet_type] = $money;
                            }
                            LuckyGroupUser::setData($mall_id, $post);
                        }else{
                            var_dump($user_id.'==更新前'.$lg_user->balance);
                            foreach ($value as $wallet_type => $money) {
                                $lg_user->$wallet_type += $money;
                            }
                            $lg_user->save();
                            var_dump($user_id.'==更新后'.$lg_user->balance);

                        }

                    }
                }
            }
            return true;
        } catch (\Exception $e) {
            echo '开团发送资金' . $e->getMessage();
            return false;
        }
    }

    //更新团长数据
    public function updateLuckyGroupUser($group_user, $order, $attend_times)
    {
        $group_user->has_attend_times += 1;
        $group_user->attend_times -= $attend_times;
        if ($group_user->attend_times < 0) $group_user->attend_times = 0;
        $res = $group_user->save();
        if ($res == false) {
            $order->group_status = 3;
            $this->refundToBalance($order, '更新团长数据失败');
            return false;
        }
        return true;
    }

    //更新订单数据
    public function updateLuckyOrder($order, $yu_attend_times, $consume)
    {
        if (!empty($yu_attend_times)) $order->yu_attend_times += $yu_attend_times;
        if (!empty($consume)) $order->consume += $consume;
        $order->open_times += 1;
        $res = $order->save();
        if ($res == false) {
            $this->refundToBalance($order, '更新订单数据失败');
            return false;
        }
        return true;
    }

    //扣减参团次数
    public function reduceAttendTimes($group_users, $order, $customize_arr)
    {
        $group_buy_order_text = Customize::to($customize_arr, 'group_buy_order_text');
        $join_into_team_text = Customize::to($customize_arr, 'join_into_team_text');
        $desc = ($group_buy_order_text ?? '幸运拼团订单') . ',' . ($join_into_team_text ?? '参团') . '次数不足';
        try {
            if ($group_users[$order['user_id']]['attend_times'] <= 0) {
                throw new Exception($desc);
            }
            return true;
        } catch (\Exception $e) {
            $order->group_status = 3;
            $this->refundToBalance($order, $desc);
            return false;
        }

    }

    //扣减消耗
    public function reduceExpendNum($expend_type, $expend_num, $user_wallets, &$order, &$deplete_balances, &$deplete_scores, $customize_arr = [])
    {
        $group_buy_order_text = Customize::to($customize_arr, 'group_buy_order_text');
        $join_into_team_text = Customize::to($customize_arr, 'join_into_team_text');
        try {
            $user_money = 0;
            if (!empty($expend_type) && !empty($expend_num)) {
                $is_can_continue = true;
                switch ($expend_type) {
                    case LuckyGroupEnum::AWARD_TYPE_BALANCE:
                        // 消耗余额
                        $user_money = $user_wallets[$order['user_id']]->$expend_type;
                        break;
                    case  LuckyGroupEnum::AWARD_TYPE_SCORE:
                        // 消耗积分
                        $user_money = $user_wallets[$order['user_id']]->$expend_type;
                        break;
                    default:
                }
                //判断积分、余额、货币是否足够
                if ($is_can_continue === false || $user_money < $expend_num) throw new Exception('拼团消耗不足');
                //参团消耗扣减
                if (in_array($expend_type, [LuckyGroupEnum::AWARD_TYPE_BALANCE, LuckyGroupEnum::AWARD_TYPE_SCORE])) {
                    //积分余额消耗
                    if ($expend_num > 0) {
                        $expend_name = '';
                        if ($expend_type == LuckyGroupEnum::AWARD_TYPE_BALANCE) {
                            $expend_name = '余额';
                            $deplete_balances += $expend_num;
                        }
                        if ($expend_type == LuckyGroupEnum::AWARD_TYPE_SCORE) {
                            $expend_name = '积分';
                            $deplete_scores += $expend_num;
                        }
                        $desc = ($group_buy_order_text ?? '幸运拼团订单') . '(' . $order['id'] . ')' . ($join_into_team_text ?? '参团') . '成功,扣减' . $expend_name . $expend_num;
                        $data = [
                            'message_id' => 0,
                            'not_add_total' => true,
                            'mall_id' => $order['mall_id'], 'user_id' => $order['user_id'],
                            'is_frozen' => false,
                            'wallet_type' => $expend_type,
                            'money' => -$expend_num,
                            'desc' => $desc,
                            'source_table' => $extension['source_table'] ?? '',
                            'source_table_id' => $extension['source_table_id'] ?? 0,
                            'from_type' => LuckyGroupEnum::ADDONS_NAME,
                            'capital_type' => UserWalletEnum::LUCKY_GROUP_CONSUME,
                        ];
                        $res = UserWalletService::handle(0, $data);
                        if ($res == false) {
                            $desc = ($group_buy_order_text ?? '幸运拼团订单') . ($join_into_team_text ?? '参团') . '扣减' . $expend_name . '失败';
                            throw new Exception($desc);
                        }
                    }
                }
            }
            return true;
        } catch (\Exception $e) {
            $order->group_status = 3;
            $this->refundToBalance($order, $e->getMessage());
            return false;
        }
    }

    //更新参团次数
    public function updateGroupGoodsJoinNum($activity_id, $goods_id, $attend_order_num)
    {
        $lucky_group_goods = LuckyGroupGoods::findOne(['activity_id' => $activity_id, 'goods_id' => $goods_id]);
        if(!$lucky_group_goods)  throw new \Exception('activity_id:'.$activity_id.',goods_id:'.$goods_id.' not exist');
        $open_times = $lucky_group_goods->open_times;
        $lucky_group_goods->open_times++;
        $lucky_group_goods->join_num = $lucky_group_goods->join_num + $attend_order_num;
        $res = $lucky_group_goods->save();
        if ($res == false) throw new Exception($lucky_group_goods->getErrorMessage());
        return $open_times;

    }

    public function refundToBalance($order, $desc = '', $wallet_type = 'balance')
    {
        // 开启事务
        $transaction = \Yii::$app->db->beginTransaction();
        $single_prize = bcdiv($order['total_pay_price'], $order['buy_nums'], 2) + 0;
        $refund_money = ($order['buy_nums'] - $order['win_nums']) * $single_prize; // 退款金额
        if ($refund_money <= 0) {
            \Yii::$app->custom->logs('退款金额小于等于0不进行退款', $order['order_no']);
            return true;
        }
        try {
            // 查看当前订单是否存在售后表中
            $refund = OrderRefund::find()->where(['order_no' => $order['order_no'], 'status' => StatusEnum::ENABLED])->exists();
            if ($refund) {
                \Yii::$app->custom->logs('幸运拼团退款订单已存在', $order['order_no']);
                return true;
            }
            // 不存在则创建退款订单
            $refundModel = new OrderRefund();
            $refundModel->mall_id = $order['mall_id'];
            $refundModel->user_id = $order['user_id'];
            $refundModel->order_id = $order['id'];
            $refundModel->order_no = $order['order_no'];
            $refundModel->type = 1;
            $refundModel->reason = '幸运拼团失败退款';
            $refundModel->refund_price = $refund_money;
            $refundModel->reality_refund_price = $refund_money;
            $refundModel->refund_at = time();
            $refundModel->num = ($order['buy_nums'] - $order['win_nums']);
            $refundModel->step_status = RefundStatusEnum::STEP_6;
            $refundModel->refund_status = RefundStatusEnum::FINISH;
            $res = $refundModel->save();
            if (!$res) {
                \Yii::$app->custom->logs('课程退款订单创建失败', OrderRefund::getStaticError());
                return true;
            }
            // 查询支付单号
            $trade_id = PaymentTradeOrder::find()->where(['order_no' => $order['order_no'], 'order_type' => PaymentTradeOrderEnum::LUCKY_GROUP_BUY_ORDER])
                ->select('trade_id')->scalar();
            if (empty($trade_id)) {
                \Yii::$app->custom->logs('课程退款订单不存在', $order['order_no']);
                return true;
            }
            $payment_trade = PaymentTrade::findOne(['id' => $trade_id]);

            $list = PaymentTrade::find()->where(['id' => $trade_id, 'is_pay' => 1])->all();
            if ($payment_trade->isMixedPay()) { // 组合支付退款
                $list = PaymentTradeItem::find()->where(['trade_id' => $trade_id, 'is_pay' => 1])->all();
            }
            $insert_wallet = [];
            $params = [
                'id' => $refundModel->id,
                'step_status' => RefundStatusEnum::STEP_6
            ];
            foreach ($list as $item) {
                if (in_array($item->pay_type, [PayTypeEnum::BALANCE, PayTypeEnum::SCORE])) { // 余额-积分退款
                    $wallet_type = $item->pay_type == PayTypeEnum::SCORE ? UserWalletService::WALLET_TYPE_SCORE : UserWalletService::WALLET_TYPE_BALANCE;
                    $insert_wallet [] = [
                        'mall_id' => $order['mall_id'],
                        'user_id' => $order['user_id'],
                        'is_frozen' => false,
                        'wallet_type' => $wallet_type,
                        'money' => $item->pay_fee,
                        'desc' => $desc,
                        'source_table' => LuckyGroupOrder::tableName(),
                        'source_table_id' => $order['id'],
                        'from_type' => LuckyGroupEnum::ADDONS_NAME,
                        'capital_type' => UserWalletEnum::REFUND_ORDER,
                    ];
                } elseif(in_array($item->pay_type,[PayTypeEnum::JOINPAY,PayTypeEnum::ALI,PayTypeEnum::JOINPAY_FAST_PAY,PayTypeEnum::WECHAT,PayTypeEnum::SANDPAY_FAST_PAY])) {
                    // 退款原路退款
                    $res = \Yii::$app->services->pay->refund(
                        $item->pay_fee,
                        $item->pay_fee,
                        $payment_trade->out_trade_no,
                        $order,
                        '幸运拼团订单退款',
                        '',
                        '',
                        $item->pay_type
                    );
                    if ($res === false) {
                        \Yii::$app->custom->logs('幸运拼团综合订单退款失败', $order['order_no']);
                        return true;
                    };
                } elseif ($res = GlobalInvoke::exec(GlobalInvoke::INVOKE_ORDER_REFUND, $order['mall_id'], [
                    'id'        => $refundModel->id,
                    'mall_id'   => $refundModel->mall_id,
                    'refund'    => $refundModel,
                    'params'    => $params,
                    'order_no'    => $order['order_no'],
                    'refund_order_no'    => $refundModel->order_no,
                    'payment_trade_id' => $payment_trade->id,
                    'refund_price' => $item->pay_fee,
                    'order_type' => 'LuckyGroup',
                    'pay_type' => $item->pay_type,
                ])) {
                    list($boolean, $msg) = $res;
                    if (!$boolean) {
                        \Yii::$app->custom->logs('幸运拼团退款订单退款失败', $msg);
                        return true;
                    }
                } else {
                    \Yii::$app->custom->logs('幸运拼团退款订单退款失败', '不存在退款方式');
                    return true;
                }
            }
            $payment_trade->setRefund($refundModel->id);
            LuckyGroupWinLog::setData(['mall_id'=>$order['mall_id'],'user_id'=>$order['user_id'],'activity_id'=>$order['activity_id'],'win_num'=>0]);
            $order->save();
            $transaction->commit();
            if (!empty($insert_wallet)) {
                UserWalletService::batchHandleByQueue($insert_wallet);
            }
        } catch (\Exception $e) {
            $transaction->rollBack();
            \Yii::$app->custom->logs('幸运拼团退款订单退款失败', $e->getMessage());
        }
        return true;
    }

    //创建主订单

    /**
     * @desc:生成主订单
     * @Author: hua
     * @Date: 2022/3/28
     * @Time: 10:47
     * @Copyright: copyright (c) 2021 广东七件事集团
     * @param $lucky_group_order
     * @param $pay_order_list
     * @param $pay_trade_list
     * @param $user_address_arr
     * @param $goods
     * @param $goods_attr
     * @return int
     * @throws Exception
     */
    public static function createMallOrder($lucky_group_order, $pay_order_list, $pay_trade_list, $user_address_arr, $goods, $goods_attr)
    {
       $t = \Yii::$app->db->beginTransaction();
        try {
            $new_goods_attr = GoodsAttr::findOne(['id' => $lucky_group_order->goods_attr_id]);


            $trade_id = $pay_order_list[$lucky_group_order['order_no']]['trade_id'];
            $out_trade_no = $pay_trade_list[$trade_id]['out_trade_no'];
            $user_address = $user_address_arr[$lucky_group_order['user_id']];

            $order = new Order();
            $order->loadDefaultValues();
            $order->mall_id = $lucky_group_order['mall_id'];
            $order->mch_id = $goods['mch_id'];
            $order->user_id = $lucky_group_order['user_id'];
            $order->order_no = StringHelper::generateOrderNo('s');
            $order->out_trade_no = $out_trade_no;
            $order->mobile = $user_address['mobile'] ?? '';
            if ($user_address) {
                $order->province = $user_address['province_id'];
                $order->city = $user_address['city_id'];
                $order->area = $user_address['district_id'];
                $order->town = $user_address['town_id'];
                $order->address = $user_address['detail'];
                $order->region_name = $user_address['province'] . $user_address['city'] . $user_address['district'] . $user_address['town'];
                $order->receiver_name = $user_address['name'];
            }
            $order->remark = $lucky_group_order['remark'];
            $order->shipping_type = ShippingTypeEnum::LOGISTICS;
            $order->shipping_money = $lucky_group_order['shipping_money'];
            $order->pay_money = $lucky_group_order['total_pay_price'];
            $order->goods_price = $lucky_group_order['total_goods_price'] / $lucky_group_order['buy_nums'];
            $order->original_goods_price = $lucky_group_order['total_goods_original_price'] / $lucky_group_order['buy_nums'];
            $order->order_status = OrderStatusEnum::PAY;
            $order->marketing_id = $lucky_group_order['id'];
            $order->marketing_type = LuckyGroupEnum::ADDONS_NAME;
            $order->pay_status = OrderStatusEnum::PAY;
            $order->extra_info = $lucky_group_order['major_data'];
            $order->payment_type = $lucky_group_order['payment_type'];
            $order->pay_time = $lucky_group_order['pay_at'];
            $order->score = 0;
            $res = $order->save();
            if ($res == false) throw new \Exception($order->getErrorMessage());
            $res = self::createMallOrderDetail($lucky_group_order, $order, $goods, $new_goods_attr);
            if ($res == false) throw new \Exception('创建主订单详情失败');
            if ($new_goods_attr->stock <= 0) throw new \Exception('库存不足');
            $new_goods_attr->stock--;
            $res = $new_goods_attr->save();
            if ($res == false) throw new \Exception($new_goods_attr->getErrorMessage());
            if ($goods->stock <= 0) throw new \Exception('库存不足');
            $goods->stock--;
            $goods->sales_num++;
            $res = $goods->save();
            if ($res == false) throw new \Exception($goods->getErrorMessage());
            $t->commit();
            return $order;
        } catch (\Exception $e) {
            $t->rollBack();
            var_dump($e->getMessage().$e->getFile().$e->getLine());
            return false;
        }

    }

    /**
     * @desc:生成主订单详情
     * @Author: hua
     * @Date: 2021/12/16
     * @Time: 14:32
     * @Copyright: copyright (c) 2021 广东七件事集团
     * @param $lucky_group_order
     * @param $order
     * @param $goods
     * @param $goods_attr
     * @param $marketing_type
     * @throws Exception
     */
    protected static function createMallOrderDetail($lucky_group_order, $order, $goods, $goods_attr)
    {
        // 因为主订单生成并且触发了订单支付事件。订单详情还没生成所以需要关联下
        try {
            // 订单详情
            $order_detail = new OrderDetail();
            $order_detail->loadDefaultValues();
            $order_detail->user_id = $lucky_group_order->user_id;
            $order_detail->mall_id = $lucky_group_order->mall_id;
            $order_detail->mch_id = $order->mch_id;
            $order_detail->order_id = $order->id;
            $order_detail->goods_id = $lucky_group_order->goods_id;
            $order_detail->goods_attr_id = $lucky_group_order->goods_attr_id;

            if ($goods) {
                $order_detail->goods_name = $goods->goods_name;
                //$order_detail->is_virtual = $goods->goods_type;
                $order_detail->is_virtual = $goods->goods_type == GoodsTypeEnum::GoodsTypeVirtual ? 1 : 0;
            }
            if ($goods_attr) {
                $order_detail->goods_attr_name = $goods_attr->name ?? '';
                $order_detail->price = $goods_attr->price;
                $order_detail->cost_price = $goods_attr->cost_price;
                $order_detail->original_goods_price = $goods_attr->original_price;
                $order_detail->pic_url = $goods_attr->pic_url ? $goods_attr->pic_url : $goods->cover_pic;
            }
            $order_detail->goods_price = $lucky_group_order['total_goods_price'] / $lucky_group_order['buy_nums'];
            $order_detail->goods_price = $lucky_group_order['total_goods_price'] / $lucky_group_order['buy_nums'];
            $order_detail->num = 1;
            $order_detail->marketing_id = $lucky_group_order->id;
            $order_detail->marketing_type = LuckyGroupEnum::ADDONS_NAME;
            $order_detail->order_status = OrderStatusEnum::PAY;
            $order_detail->remark = $lucky_group_order->remark;
            $res = $order_detail->save();
            if ($res == false) throw new \Exception('拼中生成订单详情失败');
            return $res;
        } catch (\Exception $e) {
            \Yii::$app->custom->logs('幸运拼团生成订单详情失败');
            return false;
        }
    }

    //获取上级数据
    protected static function getUserParentList($user_id_arr)
    {
        $user_relation_list = UserPartitionRelationship::lists(['where' => [['user_id' => $user_id_arr]], 'order' => 'part asc']);
        $data = [];
        foreach ($user_relation_list as $key => $value) {
            if (isset($data[$value['user_id']])) {
                $data[$value['user_id']] = array_merge($data[$value['user_id']], explode(',', $value['tree']));
            } else {
                $data[$value['user_id']] = explode(',', $value['tree']);
            }
        }
        return $data;
    }

    //获取等级数据
    protected static function getLevelConfig($activity)
    {
        $config_arr = [];
        $mall_id = $activity['mall_id'];
        if (!empty($activity['enable_commison'])) {
            $team_commission_setting = json_decode($activity['team_commission_setting'], true);
            $equal_commission_setting = json_decode($activity['equal_commission_setting'], true);
            $over_commission_setting = json_decode($activity['over_commission_setting'], true);
            foreach ($team_commission_setting as $item) {
                $config_arr[$item['level']]['is_percent_team'] = 0;
                $config_arr[$item['level']]['agent_team_prize'] = $item['team_commission'];
            }
            foreach ($equal_commission_setting as $item) {
                $config_arr[$item['level']]['is_percent_equal'] = 0;
                $config_arr[$item['level']]['agent_equal_prize'] = $item['equal_commission'];
            }
            foreach ($over_commission_setting as $item) {
                $config_arr[$item['level']]['is_percent_over'] = 0;
                $config_arr[$item['level']]['agent_over_prize'] = $item['over_commission'];
            }
        } else {
            $level_list = LuckyGroupLevel::lists(['where' => [['mall_id' => $mall_id], ['status' => StatusEnum::ENABLED]]]);
            foreach ($level_list as $item) {
                $config_arr[$item['level']]['is_percent_team'] = 0;
                $config_arr[$item['level']]['agent_team_prize'] = $item['team_commission'];
                $config_arr[$item['level']]['is_percent_equal'] = 0;
                $config_arr[$item['level']]['agent_equal_prize'] = $item['equal_commission'];
                $config_arr[$item['level']]['is_percent_over'] = 0;
                $config_arr[$item['level']]['agent_over_prize'] = $item['over_commission'];
            }
        }
        return $config_arr;
    }

    //禁用活动
    public function disableActivity($order_ids)
    {
        $joining_orders = LuckyGroupOrder::find()
            ->where(['id' => $order_ids, 'group_status' => 1])
            ->andWhere(new \yii\db\Expression('`buy_nums` > `win_nums`'))
            ->indexBy('id')
            ->all();
        foreach ($joining_orders as $key => $order) {
            $user_arr[$order['user_id']]['order_id'] = $order['id'];
            $order->group_status = 3;
            $this->refundToBalance($order, '禁用活动');
        }
    }
}