| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- <?php
- namespace addons\Sudoku\common\logic;
- use addons\Coupon\common\enums\AddonsCouponEnum;
- use addons\Coupon\common\models\AddonsCouponCatRelate;
- use addons\Coupon\common\models\AddonsCouponUserRelate;
- use addons\Sudoku\common\enums\SudokuEnum;
- use addons\Sudoku\common\models\AddonsSudoku;
- use addons\Sudoku\common\models\AddonsSudokuLog;
- use common\enums\AddonsEnum;
- use common\enums\OrderStatusEnum;
- use common\enums\RedisKeyEnum;
- use common\enums\UserWalletEnum;
- use common\helpers\LockHelper;
- use common\helpers\StringHelper;
- use common\models\goods\Goods;
- use common\models\order\Order;
- use common\models\order\OrderDetail;
- use common\models\user\UserAddress;
- use common\models\user\UserWallet;
- use common\traits\ErrorTrait;
- use Faker\Provider\Address;
- use PHPUnit\Util\Exception;
- use services\common\UserWalletService;
- use yii;
- /**
- * Class LotteryLogic
- * @Author: ltm
- * @DateTime: 2021/12/23 0023 10:21
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @package addons\Sudoku\common\logic
- */
- class LotteryLogic
- {
- use ErrorTrait;
- /**
- * @Author: ltm
- * @DateTime: 2021/12/23 0023 10:21
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @param $data['score'] 积分
- * @param $data['user_id'] 会员ID
- * @return bool
- */
- public function execute($data)
- {
- $config = Yii::$app->services->setting->addons->get($data['mall_id'], SudokuEnum::ADDONS_NAME, 'basic');
- //统计会员剩余次数,和积分是否足
- $user_wallet_model = UserWallet::findOne(['user_id' => $data['user_id']]);
- $data['score'] = $user_wallet_model['score'];
- $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_SUDOKU , $data['user_id']);
- $identification = uniqid();
- try {
- if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多');
- //检验活动时间
- if(strtotime($config['start_at']) > time()) throw new Exception("活动未开始");
- if(strtotime($config['end_at']) < time()) throw new Exception("活动已结束");
- $this->checkUser($config,$data);
- //检验奖品是否都有效
- $prizeList = $this->checkprize($data);
- //计算中奖
- $prize_id = $this->computeWin($prizeList);
- //添加抽奖纪录
- $res = $this->savePrizeLog($prize_id,$data,$prizeList,$config);
- LockHelper::ulock($lock_key,$identification);
- return $res;
- } catch (Exception $e) {
- LockHelper::ulock($lock_key,$identification);
- $this->setError($e->getMessage());
- return false;
- }
- }
- //抽奖纪录
- public function savePrizeLog($prize_id,$data,$prizeList,$config){
- $trans = Yii::$app->db->beginTransaction();
- try {
- $prize_data = null;// 中奖的奖品
- $return['msg'] = '';
- $think_data = [];// 谢谢参与奖品初始化
- foreach ($prizeList as $k => $v) {
- if($v['id'] == $prize_id) {
- $prize_data = $v;
- }
- if ($v['type'] == 5) {// 获取一个谢谢参与奖品
- $think_data = $v;
- }
- }
- // 如果获取ID是系统补全的话,则直接返回谢谢参与
- if ($prize_id == 0 && empty($prize_data)) {
- $prize_data = $think_data ?? ['type' => 5, 'id' => 0];
- }
- // 当次奖品属于无效奖品时,则会把谢谢参与奖品给替换上去
- if (!empty($prize_data['is_valid'])) {
- $prize_data = $think_data ? $think_data : ['type' => 5,'id' => 0];
- }
- $savedata['mall_id'] = $data['mall_id'];
- $savedata['sudoku_id'] = $prize_data['id'];
- $savedata['user_id'] = $data['user_id'];
- $savedata['type'] = $prize_data['type'];
- $savedata['created_at'] = time();
- switch ($prize_data['type']){
- case '1': //奖励金额
- $savedata['status'] = 1;
- $savedata['receive_at'] = time();
- $savedata['red_packet_amount'] = $prize_data['red_packet_amount'];
- $return['msg'] = '恭喜您获得'.$prize_data['red_packet_amount'].'元';
- $this->stock($prize_data['id']);//减去库存
- $this->balanceOrScore($data,$prize_data['red_packet_amount'],$prize_data['score'],1);
- break;
- case '2': //奖励优惠卷
- $savedata['status'] = 1;
- $savedata['coupon_id'] = $prize_data['coupon_id'];
- $give_coupon_arr[$prize_data['coupon_id']] = 1;
- $savedata['receive_at'] = time(); //var_dump($prize_data);
- $return['msg'] = '恭喜您获得一张'.$prize_data['coupon']['name'].'优惠券';
- $this->stock($prize_data['id']);//减去库存
- $coupon_res = AddonsCouponUserRelate::giveCoupon($data['mall_id'],$data['user_id'],$give_coupon_arr,AddonsCouponEnum::SEND_FROM9);
- if ($coupon_res === false) {// 优惠券发放失败则直接返回谢谢参与
- $savedata['type'] = 5;
- $return['msg'] = '谢谢参与';
- if (!empty($think_data)) {
- $savedata['sudoku_id'] = $think_data['id'];
- $prize_data = $think_data;
- }
- }
- break;
- case '3': //奖励积分
- $savedata['status'] = 1;
- $savedata['score'] = $prize_data['score'];
- $savedata['receive_at'] = time();
- $return['msg'] = '恭喜您获得'.$prize_data['score'].'积分';
- $this->stock($prize_data['id']);//减去库存
- $this->balanceOrScore($data,null,$prize_data['score'],2);
- break;
- case '4': //奖励商品
- $savedata['goods_id'] = $prize_data['goods_id'];
- $savedata['status'] = 0;
- $return['msg'] = '获得'.$prize_data['goods']['goods_name'].'商品一件,快去领取吧';
- $this->stock($prize_data['id']);//减去库存
- break;
- case '5': //谢谢参与
- $savedata['status'] = 1;
- $savedata['receive_at'] = time();
- $return['msg'] = '谢谢参与';
- break;
- }
- $return['id'] = $prize_data['id'];
- //抽奖扣除积分
- $this->useScore($data,$config['use_point']);
- //保存记录
- if(empty($savedata['red_packet_amount'])) $savedata['red_packet_amount'] = 0;
- if(empty($savedata['score'])) $savedata['score'] = 0;
- $this->saveSodokuLog($savedata);
- $trans->commit();
- return $return;
- } catch (Exception $e) {
- $trans->rollBack();
- $this->setError($e->getMessage());
- Yii::error('Sodoku savePrizeLog error:'.$e->getMessage().',line:'.$e->getLine());
- return false;
- }
- }
- //减去九宫格库存
- public function stock($id){
- $sudoku_data = AddonsSudoku::findOne([['id' => $id]]);
- $sudoku_data->stock = $sudoku_data->stock - 1;
- $sudoku_data->save();
- }
- //九宫格抽奖消耗积分
- public function useScore($data,$score){
- $insert_wallet [] = ['mall_id' => $data['mall_id'], 'user_id' => $data['user_id'],
- 'is_frozen' => false,
- 'wallet_type' => UserWalletService::WALLET_TYPE_SCORE,
- 'money' => '-'.$score,
- 'desc' => '九宫格抽奖消耗积分',
- 'source_table' => SudokuEnum::ADDONS_NAME,
- 'source_table_id' => $data['user_id'],
- 'from_type' => UserWalletEnum::FROM_SUDOKU_DEDUCT,
- 'capital_type' => UserWalletEnum::DEDUCT,
- ];
- $res = UserWalletService::batchHandleByQueue($insert_wallet);
- //if ($res === false) throw new \Exception(UserWalletService::getStaticError());
- }
- //赠送余额
- public function balanceOrScore($data,$balance,$score,$type){
- $insert_wallet [] = ['mall_id' => $data['mall_id'], 'user_id' => $data['user_id'],
- 'is_frozen' => false,
- 'wallet_type' => $type==1 ? UserWalletService::WALLET_TYPE_BALANCE : UserWalletService::WALLET_TYPE_SCORE,
- 'money' => $type==1 ? $balance : $score,
- 'desc' => $type==1 ? "九宫格抽奖奖励余额" : "九宫格抽奖奖励积分",
- 'source_table' => SudokuEnum::ADDONS_NAME,
- 'source_table_id' => $data['user_id'],
- 'from_type' => UserWalletEnum::FROM_SUDOKU_DEDUCT,
- 'capital_type' => UserWalletEnum::GIVE,
- ];
- $res = UserWalletService::batchHandleByQueue($insert_wallet);
- //if ($res === false) return $this->error(UserWallet::getStaticError());
- }
- //保存纪录
- public function saveSodokuLog($savedata){
- $res = AddonsSudokuLog::setData($savedata);
- if ($res === false) throw new Exception(AddonsSudokuLog::getStaticError());
- return true;
- }
- //判断会员资格
- public function checkUser($config,$data){
- //统计会员剩余次数
- if($config['type']==1){
- $params['where'][] = ['>','created_at',strtotime(date('Y-m-d'))];
- }
- $params['where'][] = ['=','user_id',$data['user_id']];
- $count_times = AddonsSudokuLog::count($params);
- $limit_times = $config['lucky_number'] - $count_times;
- if($limit_times<=0){
- throw new Exception("次数不足");
- }
- if($config['use_point']>$data['score']){
- $score_name = \Yii::$app->services->setting->mall->get($data['mall_id'], 'score.score_name') ?? '积分';
- throw new Exception($score_name."不足");
- }
- return true;
- }
- //检验奖品
- public function checkprize($data){
- $params['where'][] = ['mall_id'=>$data['mall_id']];
- $params['order'] = 'id asc';
- $params['with'] = ['goods','coupon'];
- $list = AddonsSudoku::lists($params,true);
- if($list){
- foreach ($list as $k => $v){
- if($v['stock'] <= 0 || $v['probability'] <= 0){
- $list[$k]['is_valid'] = '1'; //没库存,概率0
- continue;
- }
- if($v['stock'] <= 0 && $v['type'] != 5) $list[$k]['is_valid'] = '1'; //九宫格设定的库存已经消耗完
- //判断优惠卷是否有效和是否有库存
- if($v['type']==2){
- if($v['coupon']){
- if($v['coupon']['status'] < 1){
- $list[$k]['is_valid'] = '1'; //优惠卷已经失效
- }
- }else{
- $list[$k]['is_valid'] = '1'; //优惠卷异常,查询不到结果
- }
- }
- //判断商品是否有效,否有库存是否售卖
- if($v['type']==4){
- if($v['goods']){ //var_dump($v['goods']);die;
- if($v['goods']['status'] == '-1') $list[$k]['is_valid'] = '1';//商品已经下架
- if($v['goods']['stock'] <= 0) $list[$k]['is_valid'] = '1';//商品库存不足
- if($v['goods']['is_on_sale'] == 0) $list[$k]['is_valid'] = '1';//商品已经下架
- }else{
- $list[$k]['is_valid'] = '1'; //优惠卷异常,查询不到结果
- }
- }
- }
- }
- return $list;
- }
- //计算中奖奖品
- public function randomsum($prizeList){
- $is_valid_sum = 0;
- $randomarray = []; //var_dump($prizeList);
- $num = 100;
- $thank_id = '';
- foreach ($prizeList as $k => $v){
- if(!$v['is_valid']){ //有效奖品
- $max_value = $v['probability'] * $num;
- if($max_value>0){
- for ($i=0;$i<$max_value;$i++) {
- $randomarray[] = $v['id'];
- }
- }
- }else{
- $is_valid_sum = $is_valid_sum + $v['probability'];
- }
- if($v['type'] == 5) $thank_id = $v['id'];
- }
- if($is_valid_sum > 0 && $thank_id) for ($i=0;$i<$is_valid_sum * $num;$i++) $randomarray[] = $thank_id;
- shuffle($randomarray);
- if(!$randomarray) throw new Exception("您来晚了,奖品已经抽取完");
- return $randomarray[array_rand($randomarray,1)];
- }
- /**
- * 根据概率计算可中奖的奖品
- * @Author: lun
- * @DateTime: 2023/8/22 0022 15:50
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @param $prizeList
- * @return int|string
- */
- public function computeWin($prizeList)
- {
- $arr = [];
- foreach ($prizeList as $item) {
- $arr[$item['id']] = $item['probability'];
- $list[$item['id']] = $item;
- }
- $rid = $this->getRand($arr);
- return $rid;
- }
- /**
- * 获取中奖奖品id
- * @Author: lun
- * @DateTime: 2023/8/22 0022 15:51
- * @Copyright: copyright (c) 2021 广东七件事集团
- * @param $proArr
- * @return int|string
- */
- public function getRand($proArr)
- {
- if (empty($proArr)) return '';
- // 计算总概率
- $totalProbability = array_sum($proArr);
- if (empty($totalProbability)) return '';
- $proList = [];
- // 设置需要生成的数组数
- foreach ($proArr as $key => $value) {
- if (!is_numeric($value)) continue;
- // 去除小数点概率
- $value = intval($value);
- $valueList = array_fill(0, $value, $key);
- $proList = array_merge($proList, $valueList);
- }
- // 当客户设置概率总和小于100时,补全概率
- if (count($proList) < 100) $proList = array_merge(array_fill(0, 100 - count($proList), '0'), $proList);
- // 打乱数组进行随机抽取
- shuffle($proList);
- $randomNumber = array_rand($proList);
- if (empty($randomNumber)) return '';
- return $proList[$randomNumber];
- }
- }
|