db->beginTransaction(); try { $date = date('ymd', time()); $award = $redpack->award;// 活动奖金池剩余金额 // 今日抢红包统计 $today_grad = RedpackUserCountDay::find()->where(['rid' => $redpack->id,'user_id' => $user->id, 'date' => $date, 'status' => StatusEnum::ENABLED])->asArray()->one(); $num = $redpack->limit_user_level_num[$user->level] ?? 0; if ($num <= 0) throw new \Exception("暂无红包可领"); $today_grad_num = $today_grad['grab_num_total'] ?? 0; if ($num - $today_grad_num <= 0) throw new \Exception("今日红包个数已领完"); // 解析红包规则内容 $rule_values = Json::decode($redpack->rule_values); // 首次抢红包金额配置 $money_start = bcmul($rule_values['second_money_start'] ?? 0, 100); $money_end = bcmul($rule_values['second_money_end'] ?? 0, 100); if (empty($today_grad)) { $money_start = bcmul($rule_values['first_money_start'], 100); $money_end = bcmul($rule_values['first_money_end'], 100); } $money = bcmul(rand($money_start, $money_end), 0.01, 2); // 扣减奖金池 if ($redpack->redpack_type != RedpackEnum::FREEZE_TO_ACTIVE) { // 判断可得金额是否大于奖金池剩余金额 if ($money >= $award) $money = $award; $redpack->award = $redpack->award - $money; } // 判断用户曾经是否抢过红包 $has_grab = RedpackUserGrab::find()->where(['mall_id' => $redpack->mall_id,'rid' => $redpack->id, 'user_id' => $user->id, 'status' => StatusEnum::ENABLED])->asArray()->one(); empty($has_grab) && $redpack->grab_user_num = $redpack->grab_user_num + 1; // 红包表数据统计汇总 $redpack->grab_money = $redpack->grab_money + $money; // 增加用户红包金额 $p_desc = ""; switch ($redpack->redpack_type) { case RedpackEnum::FREEZE_TO_ACTIVE : $is_frozen = false; $desc = "抢冻结到激活$pack_name"; // 将冻结红包的金额先减扣掉 $wallet = RedpackWallet::setData([ 'mall_id' => $redpack->mall_id, 'user_id' => $user->id, 'is_frozen' => true, 'is_deduct' => true, 'money' => -$money, 'source_table' => Redpack::briefTableName(), 'source_table_id' => $redpack->id, 'from_type' => RedpackEnum::FROM_RECEIVE, 'desc' => $desc, ]); if (!$wallet) throw new Exception(RedpackWallet::getStaticError()); $money = $wallet['money']; if ($money <= 0) throw new \Exception("暂无可激活的冻结$pack_name"); break; case RedpackEnum::INCREMENT_FREEZE : $is_frozen = true; $desc = '抢冻结' . $pack_name; $p_desc = '冻结' . $pack_name; break; case RedpackEnum::INCREMENT_ACTIVE : $is_frozen = false; $desc = '抢激活' . $pack_name; $p_desc = '激活' . $pack_name; break; } // 增加用户的红包余额 $res = RedpackWallet::setData([ 'mall_id' => $redpack->mall_id, 'user_id' => $user->id, 'is_frozen' => $is_frozen, 'money' => $money, 'source_table' => Redpack::briefTableName(), 'source_table_id' => $redpack->id, 'from_type' => RedpackEnum::FROM_RECEIVE, 'desc' => $desc, ]); if (!$res) throw new Exception(RedpackWallet::getStaticError()); // 增加抢红包次数 $count_day = [ 'mall_id' => $redpack->mall_id, 'rid' => $redpack->id, 'user_id' => $user->id, 'grab_num' => empty($today_grad['grab_num_total']) ? $num - 1 : $num - $today_grad['grab_num_total'] - 1, 'grab_num_total' => empty($today_grad['grab_num_total']) ? 1 : $today_grad['grab_num_total'] + 1, ]; !empty($today_grad['id']) && $count_day['id'] = $today_grad['id']; $res = RedpackUserCountDay::setData($count_day); if (!$res) throw new Exception(RedpackUserCountDay::getStaticError()); // 增加抢红包数据 $res = RedpackUserGrab::setData([ 'mall_id' => $redpack->mall_id, 'rid' => $redpack->id, 'user_id' => $user->id, 'grab_money' => $money, ]); if (!$res) throw new Exception(RedpackUserGrab::getStaticError()); // 判断上级是否需要增加,当前用户是否有上级 if ($redpack->reward_parent_rate > 0 && !empty($user->parent_id) && $redpack->award > 0 && $redpack->redpack_type > 1 && $redpack->is_limit_user_level_num) { // 增加用户的红包余额 $parent_money = bcmul($money, bcmul($redpack->reward_parent_rate, 0.01, 10), 2); if ($parent_money > $redpack->award) $parent_money = $redpack->award; $redpack->award -= $parent_money; // 奖池需要减去上级奖励金额 if ($parent_money >= 0.01) { $res = RedpackWallet::setData([ 'mall_id' => $redpack->mall_id, 'user_id' => $user->parent_id, 'is_frozen' => $is_frozen, 'money' => $parent_money, 'source_table' => Redpack::briefTableName(), 'source_table_id' => $redpack->id, 'from_type' => RedpackEnum::FROM_SUBORDINATE, 'desc' => "{$p_desc}: 会员ID [$user->id] 的直推$pack_name", ]); if (!$res) throw new Exception(RedpackWallet::getStaticError()); // 增加抢红包数据 $res = RedpackUserGrab::setData([ 'mall_id' => $redpack->mall_id, 'rid' => $redpack->id, 'user_id' => $user->parent_id, 'grab_money' => $parent_money, ]); if (!$res) throw new Exception(RedpackUserGrab::getStaticError()); } } // 更新红包活动 if (!$redpack->save()) throw new Exception($redpack->getErrorMessage()); $trans->commit(); return $money; } catch (\Exception $e) { self::setStaticError($e->getMessage()); $trans->rollBack(); return false; } } /** * 红包金额变动 * @Author: lun * @DateTime: 2022/3/22 0022 9:56 * @Copyright: copyright (c) 2021 广东七件事集团 * @param int $user_id */ public static function gradRedpack($user_id, Redpack $redpack, string $pack_name) { $trans = Yii::$app->db->beginTransaction(); try { $time_type = $redpack['time_type'];// 活动类型[1=每日红包,2=时间段红包] $date = date('ymd', time()); // 活动-每日抢红包,每天都有一次无需邀请人抢红包机会 // 活动-时间段抢红包,在这个时间段内,最多只有一次无需邀请人可抢红包机会 // 获取用户是否首次抢红包 if ($time_type == 1) { $is_first_grad = RedpackUserCountDay::find()->where(['rid' => $redpack->id,'user_id' => $user_id, 'date' => $date, 'status' => StatusEnum::ENABLED])->asArray()->one(); } else { $is_first_grad = RedpackUserCountDay::find()->where(['rid' => $redpack->id,'user_id' => $user_id, 'status' => StatusEnum::ENABLED, 'inviter_num' => 0])->asArray()->one(); } $award = $redpack->award;// 活动奖金池剩余金额 // 今日抢红包统计 $today_grad = RedpackUserCountDay::find()->where(['rid' => $redpack->id,'user_id' => $user_id, 'date' => $date, 'status' => StatusEnum::ENABLED])->asArray()->one(); // 解析红包规则内容 $rule_values = Json::decode($redpack->rule_values, true); if (empty($is_first_grad)) { // 首次抢红包金额配置 $money = rand($rule_values['first_money_start'] * 100, $rule_values['first_money_end'] * 100); } else { // 非首次抢到红包,检查最后一次抢红包次数是否是第一次抢,不是则找到今日最后一次抢的统计内容 // 判断今日抢红包次数是否已经超出 if ($today_grad['grab_num_total'] >= $rule_values['times']) throw new \Exception('今日抢红包次数已用完'); // 判断可抢次数是否还足够 $user_grad_num = empty($today_grad['inviter_num']) ? 0 : floor($today_grad['inviter_num'] / $rule_values['everyday_invitation']);// 用户已抢红包次数 if ($user_grad_num - $today_grad['grab_num_total'] + 1 <= 0) throw new \Exception('今日抢红包次数不足'); $money = rand($rule_values['everyday_invitation_start'] * 100, $rule_values['everyday_invitation_end'] * 100); } // 将奖励金额单位改为元 $money = $money / 100; // 扣减奖金池 if ($redpack->redpack_type != RedpackEnum::FREEZE_TO_ACTIVE) { // 判断可得金额是否大于奖金池剩余金额 if ($money >= $award) $money = $award; $redpack->award = $redpack->award - $money; } // 判断用户曾经是否抢过红包 $has_grab = RedpackUserGrab::find()->where(['mall_id' => $redpack->mall_id,'rid' => $redpack->id,'user_id' => $user_id, 'status' => StatusEnum::ENABLED])->asArray()->one(); empty($has_grab) && $redpack->grab_user_num = $redpack->grab_user_num + 1; // 红包表数据统计汇总 $redpack->grab_money = $redpack->grab_money + $money; if (!$redpack->save()) throw new Exception($redpack->getErrorMessage()); // 增加用户红包金额 switch ($redpack->redpack_type) { case RedpackEnum::FREEZE_TO_ACTIVE : $is_frozen = false; $desc = '抢冻结到激活' . $pack_name; // 将冻结红包的金额先减扣掉 $wallet = RedpackWallet::setData([ 'mall_id' => $redpack->mall_id, 'user_id' => $user_id, 'is_frozen' => true, 'is_deduct' => true, 'money' => -$money, 'source_table' => Redpack::briefTableName(), 'source_table_id' => $redpack->id, 'from_type' => RedpackEnum::FROM_RECEIVE, 'desc' => $desc, ]); if ($wallet == false) throw new Exception(RedpackWallet::getStaticError()); $money = $wallet['money']; if ($money <= 0) throw new \Exception("暂无可激活的冻结$pack_name"); break; case RedpackEnum::INCREMENT_FREEZE : $is_frozen = true; $desc = '抢冻结' . $pack_name; break; case RedpackEnum::INCREMENT_ACTIVE : $is_frozen = false; $desc = '抢激活' . $pack_name; break; } // 增加用户的红包余额 $res = RedpackWallet::setData([ 'mall_id' => $redpack->mall_id, 'user_id' => $user_id, 'is_frozen' => $is_frozen, 'money' => $money, 'source_table' => Redpack::briefTableName(), 'source_table_id' => $redpack->id, 'from_type' => RedpackEnum::FROM_RECEIVE, 'desc' => $desc, ]); if ($res == false) throw new Exception(RedpackWallet::getStaticError()); // 增加抢红包次数 $count_day = [ 'mall_id' => $redpack->mall_id, 'rid' => $redpack->id, 'user_id' => $user_id, 'grab_num' => empty($today_grad['grab_num_total']) ? $rule_values['times'] - 1 : $rule_values['times'] - $today_grad['grab_num_total'] - 1, 'grab_num_total' => empty($today_grad['grab_num_total']) ? 1 : $today_grad['grab_num_total'] + 1, ]; !empty($today_grad['id']) && $count_day['id'] = $today_grad['id']; $res = RedpackUserCountDay::setData($count_day); if ($res == false) throw new Exception(RedpackUserCountDay::getStaticError()); // 增加抢红包数据 $res = RedpackUserGrab::setData([ 'mall_id' => $redpack->mall_id, 'rid' => $redpack->id, 'user_id' => $user_id, 'grab_money' => $money, ]); if ($res == false) throw new Exception(RedpackUserGrab::getStaticError()); $trans->commit(); return $money; } catch (\Exception $e) { self::setStaticError($e->getMessage()); $trans->rollBack(); return false; } } /** * 赠送红包 * @Author: lun * @DateTime: 2022/3/26 0026 14:51 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $order_id * @param $order_status 1=支付完成,2=订单完成 * @return bool */ public static function giveRedpack($order_id, $order_status = 2) { try { $order = \common\models\order\Order::findOne(['id'=>$order_id]); if(!empty($order['store_id'])) return true; // 查询订单 $select = "mall_id,goods_id,user_id,goods_price,adjust_money,num"; $order_details = OrderDetail::find()->select($select)->where(['order_id' => $order_id])->indexBy("goods_id")->asArray()->all(); if (empty($order_details)) throw new \Exception("订单id={$order_id}的订单详情数据为空"); $goods_ids = array_keys($order_details);// 商品ids foreach ($order_details as $goods_id => $detail) { $user_id = $detail['user_id']; $mall_id = $detail['mall_id']; break; } // 获取配置【1=支付完成,2=订单完成】 $give_type = Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_REDPACK, 'basic.give_type'); if ($give_type != $order_status) return true; // 获取设置了红包的商品 $list = RedpackGoodsSetting::find()->where(['goods_id' => $goods_ids, 'is_enable' => StatusEnum::ENABLED, 'status' => StatusEnum::ENABLED])->asArray()->all();true; if (empty($list)) return true; foreach ($list as $item) { // 计算可赠送的红包金额 $pay_money = $order_details[$item['goods_id']]['goods_price'] + $order_details[$item['goods_id']]['adjust_money']; $money = $item['is_percent'] == 0 ? bcmul($item['give'], $order_details[$item['goods_id']]['num'], 2) : bcmul(($item['give'] / 100), $pay_money, 2); if ($money <= 0) continue; // 插入红包金额表 $wallet = RedpackWallet::setData([ 'mall_id' => $item['mall_id'], 'user_id' => $user_id, 'is_frozen' => $item['redpack_wallet_type'] == RedpackEnum::WALLET_REDPACK_FROZEN ? true : false, 'money' => $money, 'source_table' => 'order', 'source_table_id' => $order_id, 'from_type' => RedpackEnum::FROM_GOODS, 'desc' => '购物赠送', ]); if ($wallet == false) throw new Exception(RedpackWallet::getStaticError()); } return true; } catch (\Exception $e) { self::setStaticError($e->getMessage()); return false; } } /** * 红包返回 * @Author: lun * @DateTime: 2022/9/21 0021 9:54 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $order_detail_id * @param array $params * @return bool */ public static function backRedpack($order_detail_id, $params = []) { $trans = Yii::$app->db->beginTransaction(); try { $deduct = OrderMarketing::find()->select('deduct_currency')->where(['order_detail_id' => $order_detail_id, 'status' => StatusEnum::ENABLED])->scalar(); if (empty($deduct)) { $trans->commit(); return true; } $deduct_arr = Json::decode($deduct, true); foreach ($deduct_arr as $key => $item) { // 判断里面是否存在激活红包跟冻结红包 if (in_array($key, [RedpackEnum::WALLET_REDPACK, RedpackEnum::WALLET_REDPACK_FROZEN]) && $item['money'] > 0) { $wallet = RedpackWallet::setData([ 'mall_id' => $params['mall_id'], 'user_id' => $params['user_id'], 'is_frozen' => $key == RedpackEnum::WALLET_REDPACK_FROZEN ? true : false, 'money' => $item['money'], 'source_table' => $params['source_table'], 'source_table_id' => $params['source_table_id'], 'from_type' => $params['from_type'], 'desc' => $params['desc'] ?? '', 'no_icr_total' => true,// 不增加红包累计总额 ]); if ($wallet == false) throw new Exception(RedpackWallet::getStaticError()); } } $trans->commit(); return true; } catch (\Exception $e) { $trans->rollBack(); self::setStaticError($e->getMessage()); return false; } } /** * 订单加速冻结红包转激活红包 * @Author: * @DateTime: * @Copyright: copyright (c) 2021 广东七件事集团 * @param $order_id * @param int $orderStatus * @return bool */ public static function accelerateFrozenToActive($order_id, int $orderStatus = \common\enums\OrderStatusEnum::PAY) { try { $order = \common\models\order\Order::findOne(['id' => $order_id]); if (!empty($order['store_id'])) return true; // 查询订单 $select = "mall_id,goods_id,user_id,goods_price,adjust_money,num"; $order_details = OrderDetail::find()->select($select)->where(['order_id' => $order_id])->indexBy("goods_id")->asArray()->all(); if (empty($order_details)) throw new \Exception("订单id={$order_id}的订单详情数据为空"); $goods_ids = array_keys($order_details);// 商品ids foreach ($order_details as $goods_id => $detail) { $user_id = $detail['user_id']; $mall_id = $detail['mall_id']; break; } //获取红包配置 $config = Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_REDPACK, 'basic'); $config = RedpackHelper::initConfig($config); //获取蓝色积分配置 $blue_score_config = Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_BLUE_SCORE, 'basic'); if (empty($config['is_accelerated_activation'])) return true; //判断订单状态 // 因为订单队列执行慢,可能会出现客户支付成功后就操作订单完成。这个时候肯支付队列、订单完成队列的订单状态都是一致的。所以需要修改为由队列传递状态 if ($config['accelerate_settlement_type'] == 1 && $order->order_status != $orderStatus) { return true; } if ($config['accelerate_settlement_type'] == 2 && $order->order_status != $orderStatus) { return true; } $accelerated_user_level_ids = json_decode($config['accelerated_user_level_ids'], true); $accelerated_goods_ids = json_decode($config['accelerated_goods_ids'], true); $accelerated_goods_list = json_decode($config['accelerated_goods_list'], true); $accelerated_goods_list = array_column($accelerated_goods_list, null, 'id'); //获取用户上级 $user = \common\models\user\User::findOne(['id' => $user_id]); $user_parent = \common\models\user\User::findOne(['id' => $user->parent_id]); //没有上级信息 if (empty($user_parent)) return true; $user_level_res = \common\models\user\UserLevel::getUserLevelOne([['mall_id' => $mall_id], ['level' => $user_parent->level]], [], 1); //上级等级不在加速等级 if (!in_array($user_level_res['id'], $accelerated_user_level_ids)) return true; $goods_intersect = array_intersect($goods_ids, $accelerated_goods_ids); //没有商品可以进行加速 if (empty($goods_intersect)) return true; $money = 0; //计算加速冻结红包数额 foreach ($accelerated_goods_list as $item) { if (in_array($item['id'], $goods_intersect)) { $money += $item['accelerate_number']; } } if ($money == 0) return true; $user_redpack_wallet = RedpackWallet::findOne(['user_id' => $user_parent->id, 'status' => StatusEnum::ENABLED]); //没有冻结红包 if (empty($user_redpack_wallet) || $user_redpack_wallet['frozen_redpack'] == 0 ) return true; if ($user_redpack_wallet['frozen_redpack'] < $money) { //冻结红包数额少于加速数额,则将冻结红包全部转换 $money = $user_redpack_wallet['frozen_redpack']; } $trans = Yii::$app->db->beginTransaction(); //扣除冻结红包 $res = RedpackWallet::setData([ 'mall_id' => $mall_id, 'user_id' => $user_parent->id, 'is_frozen' => true, 'is_deduct' => true, 'money' => -$money, 'from_type' => RedpackEnum::FROM_ORDER_ACCELERATED_FROZEN_ROLL_OUT, 'desc' => '订单加速冻结红包转出', ]); if ($res === false) throw new Exception('执行失败'); //是否安装and开启了蓝色积分转换 $has_blue_score = MallAddons::isInstall($mall_id,AddonsEnum::ADDONS_BLUE_SCORE); if ($has_blue_score && !empty($blue_score_config) && $blue_score_config['is_enable'] == StatusEnum::ENABLED) { if (!empty($blue_score_config['transfer_rate']) || $blue_score_config['transfer_rate'] > 0) { //计算激活红包转换的蓝色积分 $integral = round($money * $blue_score_config['transfer_rate'] / 100, 2); //计算剩余的激活红包 $money = round($money * (1 - ($blue_score_config['transfer_rate'] / 100)), 2);; //转换蓝色积分 $res = BlueScore::setData([ 'mall_id' => $mall_id, 'user_id' => $user_parent->id, 'integral' => $integral, 'from_type' => BlueScoreEnum::FROM_ORDER_ACCELERATED_ACTIVE_TO_BLUE_SCORE, 'desc' => '用户(' . $user_id . '),获得订单(' . $order_id .')加速冻结红包转蓝色积分奖励,蓝色积分+' . $integral, 'source_table' => \common\models\order\Order::tableName(), 'source_table_id' => $order_id, ]); if ($res === false) throw new Exception('执行失败'); } } //转激活红包 $res = RedpackWallet::setData([ 'mall_id' => $mall_id, 'user_id' => $user_parent->id, 'is_frozen' => false, 'is_deduct' => true, 'money' => $money, 'from_type' => RedpackEnum::FROM_ORDER_ACCELERATED_FROZEN_TO_ACTIVE, 'desc' => '订单加速冻结红包转激活红包', ]); if ($res === false) throw new Exception('执行失败'); $trans->commit(); return true; } catch (\Exception $e) { $trans->rollBack(); self::setStaticError($e->getMessage()); return false; } } }