BoxRecordService.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. <?php
  2. namespace app\common\service;
  3. use app\admin\model\dao\BoxMidHandle;
  4. use app\common\model\BoxHandleAllModel;
  5. use app\common\model\BoxHandleModel;
  6. use app\common\model\BoxMidHandleModel;
  7. use app\common\model\BoxModel;
  8. use app\common\model\BoxRecordModel;
  9. use app\common\model\MoneyLogModel;
  10. use app\common\model\ScoreLogModel;
  11. use app\common\model\ShopGoodsModel;
  12. use app\common\model\UserModel;
  13. use app\common\model\UserUnmoneyModel;
  14. use think\facade\Db;
  15. use utils\RedisCache;
  16. /**
  17. * 盒子预约记录服务 by wes
  18. * Class BoxRecordService
  19. * @package app\common\service
  20. */
  21. class BoxRecordService
  22. {
  23. protected static $instance = null;
  24. protected $model = null;
  25. public function __construct()
  26. {
  27. $this->model = new BoxRecordModel();
  28. }
  29. /**
  30. * 静态化入口
  31. * @return static|null
  32. */
  33. public static function make()
  34. {
  35. if (!self::$instance) {
  36. self::$instance = new static();
  37. }
  38. return self::$instance;
  39. }
  40. /**
  41. * 获取待处理福袋
  42. * @param $params
  43. * @param int $pageSize
  44. */
  45. public function getCatchList($params, $pageSize = 20)
  46. {
  47. $where = ['r.status' => 1];
  48. $uid = isset($params['uid']) ? $params['ud'] : 0;
  49. if ($uid > 0) {
  50. $where['r.uid'] = $uid;
  51. }
  52. $mobile = isset($params['mobile']) ? trim($params['mobile']) : '';
  53. if (!empty($mobile)) {
  54. $where['r.mobile'] = $mobile;
  55. }
  56. $boxId = isset($params['box_id']) ? trim($params['box_id']) : '';
  57. if (!empty($boxId)) {
  58. $where['r.box_id'] = $boxId;
  59. }
  60. $qiCount = isset($params['qi_count']) ? $params['qi_count'] : 0;
  61. if ($qiCount > 0) {
  62. $where['r.qi_count'] = $qiCount;
  63. }
  64. $lunCount = isset($params['lun_count']) ? $params['lun_count'] : 0;
  65. if ($lunCount > 0) {
  66. $where['r.lun_count'] = $lunCount;
  67. }
  68. $isMatch = isset($params['is_set_match']) ? $params['is_set_match'] : 0;
  69. if ($isMatch > 0) {
  70. $where['r.is_set_match'] = $isMatch;
  71. }
  72. $list = $this->model->alias('r')
  73. ->where($where)
  74. ->where(function ($query) use ($params) {
  75. $box10 = isset($params['box10']) ? $params['box10'] : 0;
  76. $box20 = isset($params['box20']) ? $params['box20'] : 0;
  77. $box30 = isset($params['box30']) ? $params['box30'] : 0;
  78. $box40 = isset($params['box40']) ? $params['box40'] : 0;
  79. if ($box10 > 0) {
  80. $query->where('r.box10', '>=', $box10);
  81. }
  82. if ($box20 > 0) {
  83. $query->where('r.box20', '>=', $box20);
  84. }
  85. if ($box30 > 0) {
  86. $query->where('r.box30', '>=', $box30);
  87. }
  88. if ($box40 > 0) {
  89. $query->where('r.box40', '>=', $box40);
  90. }
  91. })
  92. ->where('r.create_time', '>=', date('Y-m-d'))
  93. ->leftJoin('user u', 'u.id = r.uid')
  94. ->field(Db::raw('r.*,u.mobile,u.total_null_box,sum(r.num) as num,u.total_free,u.total_appoint_count,u.total_income,u.yesterday_money,u.box10 as ubox10,u.box20 as ubox20,u.box30 as ubox30,u.box40 as ubox40,u.path'))
  95. ->group('group_key')
  96. ->order('r.create_time desc')
  97. ->order('r.qi_count desc')
  98. ->order('r.lun_count desc')
  99. ->order('r.num desc')
  100. ->paginate($pageSize)
  101. ->each(function($item, $k){
  102. $path = isset($item['path'])? $item['path'] : '';
  103. $path = $path? explode(',', $path):[];
  104. $path[] = $item['uid'];
  105. $item['last_team_profit'] = UserUnmoneyModel::whereIn('uid',$path)->whereDay('create_time','yesterday')->sum('money');
  106. $item['today_team_profit'] = UserUnmoneyModel::whereIn('uid',$path)->whereDay('create_time','today')->sum('money');
  107. });
  108. $list = $list ? $list->toArray() : [];
  109. return $list;
  110. }
  111. /**
  112. * 统计小于某预约数量的渔业次数
  113. * @param $uid 用户ID
  114. * @param $boxId 福袋ID
  115. * @param int $num 数量
  116. * @return array|mixed|null
  117. * @throws \think\db\exception\DbException
  118. */
  119. public function getCountByUser($uid, $boxId, $num = 5)
  120. {
  121. $cacheKey = "caches:boxRecord:count:{$uid}_{$boxId}_{$num}";
  122. $data = RedisCache::get($cacheKey);
  123. if ($data) {
  124. return $data;
  125. }
  126. $count = $this->model->where(['uid' => $uid, 'box_id' => $boxId, 'status' => 1])
  127. ->where('num', '<', $num)
  128. ->count('id');
  129. if ($count) {
  130. RedisCache::set($cacheKey, $count, rand(3, 5));
  131. }
  132. return $data;
  133. }
  134. /**
  135. * 预约福袋处理
  136. * @param $uid
  137. * @param $params
  138. * @param $user_info
  139. * @throws \think\Exception
  140. * @throws \think\db\exception\DataNotFoundException
  141. * @throws \think\db\exception\DbException
  142. * @throws \think\db\exception\ModelNotFoundException
  143. */
  144. public function applyBox($uid, $params)
  145. {
  146. $boxCount = isset($params['buy_count']) ? intval($params['buy_count']) : 0;
  147. $boxId = isset($params['box_id']) ? intval($params['box_id']) : 0;
  148. $payType = isset($params['pay_type']) ? intval($params['pay_type']) : 0;
  149. if ($boxCount <= 0) {
  150. sr_throw('请选择预约福袋类型');
  151. }
  152. if ($boxId <= 0 || $payType <= 0) {
  153. sr_throw('预约参数错误');
  154. }
  155. if (!in_array($payType, [1, 2])) {
  156. sr_throw('支付类型错误');
  157. }
  158. // 验证福袋功能是否开启
  159. $boxIsApply = SystemConfigService::make()->getConfigByName('fudai_is_apply', 1, 'fudai');
  160. if ($boxIsApply != 1) {
  161. sr_throw('福袋预约功能暂未开放');
  162. }
  163. // 福袋信息和验证
  164. $boxInfo = BoxModel::where('id', $boxId)->find();
  165. $openStatus = isset($boxInfo['open_status']) ? $boxInfo['open_status'] : 0;
  166. if (!$boxInfo) {
  167. sr_throw('福袋参数错误');
  168. }
  169. if ($openStatus != 1) {
  170. sr_throw('该期福袋预约未开启');
  171. }
  172. if ($boxCount > 20) {
  173. sr_throw('最多可预约20个');
  174. }
  175. // 如果预约数量小于5
  176. if ($boxCount < 5 && $this->getCountByUser($uid, $boxId, 5) >= 4) {
  177. sr_throw('每一场数量小于5最多只能预约4次');
  178. }
  179. // 预约数量限制
  180. if ($this->model->where(['uid' => $uid, 'status' => 1])->sum('num') > 100) {
  181. sr_throw('每一场最多可预约100次');
  182. }
  183. $lun = 1;
  184. $time = time();
  185. $canBuy = false;
  186. $times = explode('|', $boxInfo['time_set']);
  187. $curTimeDay = sr_getcurtime(time(), 'Y-m-d');
  188. $openTime = '';
  189. foreach ($times as $key => $val) {
  190. $timesarr = explode('-', $val);
  191. $beginTime = strtotime($curTimeDay . ' ' . $timesarr[0]);
  192. $endTime = strtotime($curTimeDay . ' ' . $timesarr[1]);
  193. if ($time > $beginTime && $time < $endTime) {
  194. $canBuy = true;
  195. $lun = $key + 1;
  196. $openTime = date('Y-m-d H:i:s', $endTime + 30 * 60);
  197. }
  198. }
  199. if (!$canBuy) {
  200. sr_throw('no_open');
  201. }
  202. // 总金额
  203. $totalPay = $boxCount * env('boxsetting.one_box_price', 288);
  204. $userInfo = UserModel::where(['id' => $uid])->field('id,score,money,has_fd')->find();
  205. $userMoney = isset($userInfo['money']) ? floatval($userInfo['money']) : 0;
  206. $userScore = isset($userInfo['score']) ? floatval($userInfo['score']) : 0;
  207. $hasFd = isset($userInfo['has_fd']) ? intval($userInfo['has_fd']) : 0;
  208. // 积分支付
  209. if ($payType == 1) {
  210. if ($userScore < $totalPay) {
  211. sr_throw('积分不足,预约失败');
  212. }
  213. // 扣除用户积分
  214. if (!UserModel::where('id', $uid)->dec('score', $totalPay)->update()) {
  215. sr_throw('扣除账户积分失败');
  216. }
  217. // 积分流水
  218. $data = [
  219. 'uid' => $uid,
  220. 'type' => 1,
  221. 'score' => $totalPay,
  222. 'create_at' => sr_getcurtime(time()),
  223. 'state' => 2,
  224. 'before_score' => $userScore,
  225. 'after_score' => max(0, $userScore - $totalPay),
  226. 'from_id' => 0,
  227. 'uid2' => 0,
  228. 'remark' => '预约福袋:' . $boxCount . '个'
  229. ];
  230. if (!ScoreLogModel::insertGetId($data)) {
  231. sr_throw('扣除积分处理失败');
  232. }
  233. }
  234. // 余额支付
  235. if ($payType == 2) {
  236. if ($userMoney < $totalPay) {
  237. sr_throw('余额不足,预约失败');
  238. }
  239. // 扣除用户余额
  240. if (!UserModel::where('id', $uid)->dec('money', $totalPay)->update()) {
  241. sr_throw('扣除账户余额失败');
  242. }
  243. // 余额流水
  244. $data = [
  245. 'uid' => $uid,
  246. 'type' => 1,
  247. 'money' => $totalPay,
  248. 'create_at' => sr_getcurtime(time()),
  249. 'state' => 2,
  250. 'before_money' => $userMoney,
  251. 'after_money' => max(0, $userMoney - $totalPay),
  252. 'from_id' => 0,
  253. 'uid2' => 0,
  254. 'remark' => '预约福袋:' . $boxCount . '个'
  255. ];
  256. if (!MoneyLogModel::insertGetId($data)) {
  257. sr_throw('扣除余额处理失败');
  258. }
  259. }
  260. // 预约记录
  261. $recordData = [
  262. 'box_id' => $params['box_id'],
  263. 'num' => $params['buy_count'],
  264. 'lun_count' => $lun,
  265. 'uid' => $uid,
  266. 'create_time' => sr_getcurtime($time),
  267. 'open_time' => $openTime ? $openTime : sr_getcurtime(time() + 30 * 60),
  268. 'box_img' => $boxInfo['box_img'],
  269. 'group_key' => $boxId . '_' . $boxInfo['qi_count'] . '_' . $lun . '_' . $uid,
  270. 'box_title' => $boxInfo['box_title'],
  271. 'qi_count' => $boxInfo['qi_count'],
  272. 'pay_type' => $params['pay_type']
  273. ];
  274. if (!$this->model->insertGetId($recordData)) {
  275. sr_throw('预约处理失败');
  276. }
  277. // 统计用户预约次数
  278. if (!UserModel::where('id', $uid)->inc('total_appoint_count', $params['buy_count'])->update()) {
  279. sr_throw('用户预约数据处理失败');
  280. }
  281. // 清除拆袋缓存
  282. RedisCache::clear("caches:box:open:user_" . $uid);
  283. return true;
  284. }
  285. /**
  286. * 设置福袋匹配数据
  287. * @param $ids
  288. * @param $data
  289. * @return bool
  290. * @throws \think\Exception
  291. * @throws \think\db\exception\DataNotFoundException
  292. * @throws \think\db\exception\DbException
  293. * @throws \think\db\exception\ModelNotFoundException
  294. */
  295. public function setBoxMatch($ids, $data)
  296. {
  297. $ids = $ids ? explode(',', $ids) : [];
  298. $box10 = isset($data['box10']) ? intval($data['box10']) : 0;
  299. $box20 = isset($data['box20']) ? intval($data['box20']) : 0;
  300. $box30 = isset($data['box30']) ? intval($data['box30']) : 0;
  301. $box40 = isset($data['box40']) ? intval($data['box40']) : 0;
  302. $boxList = BoxRecordModel::whereIn('id', $ids)->where('status', 1)
  303. ->field('uid,box_id,group_key,box10,box20,box30,box40,is_set_match')
  304. ->select();
  305. $boxList = $boxList ? $boxList->toArray() : [];
  306. if (empty($boxList)) {
  307. return '请选择有效的用户进行操作';
  308. }
  309. if (count($ids) != count($boxList)) {
  310. return '存在不可设置的用户';
  311. }
  312. $matchCount = intval($box10 + $box20 + $box30 + $box40);
  313. foreach ($boxList as $item) {
  314. $uid = isset($item['uid']) ? $item['uid'] : 0;
  315. $groupKey = isset($item['group_key']) ? $item['group_key'] : '';
  316. $applyCount = $this->model->where(['group_key'=>$groupKey,'status'=>1])->sum('num');
  317. if ($matchCount > $applyCount) {
  318. return "用户[{$uid}]不能设置超过最大预约量{$applyCount}个";
  319. }
  320. }
  321. $updateData = ['box10' => $box10, 'box20' => $box20, 'box30' => $box30, 'box40' => $box40, 'is_set_match' => 1, 'update_time' => date('Y-m-d H:i:s')];
  322. $hasXy = isset($data['hs_xy'])? $data['hs_xy'] : '';
  323. if ($hasXy == 'on') {
  324. $updateData['hs_xy'] = 1;
  325. }else {
  326. $updateData['hs_xy'] = 0;
  327. }
  328. Db::startTrans();
  329. if (!$this->model->whereIn('id', $ids)->update($updateData)) {
  330. Db::rollback();
  331. return '设置匹配数据失败';
  332. }
  333. Db::commit();
  334. return true;
  335. }
  336. /**
  337. * 开奖处理
  338. * @param $ids
  339. * @param $post
  340. * @return string
  341. * @throws \think\db\exception\DataNotFoundException
  342. * @throws \think\db\exception\DbException
  343. * @throws \think\db\exception\ModelNotFoundException
  344. */
  345. public function openBox($ids, $post)
  346. {
  347. set_time_limit(0);
  348. if (empty($ids)) {
  349. return '请先选择要开出的用户';
  350. }
  351. $cacheTime = 7200;
  352. $key = md5(json_encode($ids));
  353. $date = date('Y-m-d H:i:s');
  354. $cacheKey = "caches:boxOpen:" . date('mdHi') . "_{$key}:";
  355. if (RedisCache::get($cacheKey . 'lock')) {
  356. return '正在开奖中,请不要关闭页面或重复提交,若失败请20秒后再试';
  357. }
  358. RedisCache::setnx($cacheKey . 'lock', 1, rand(10, 20));
  359. if ($this->model->whereIn('id', $ids)->where('is_set_match', 2)->value('id')) {
  360. RedisCache::set($cacheKey . 'error', ['ids' => $ids, 'date' => $date, 'msg' => '存在未设置匹配数据的记录'], $cacheTime);
  361. return '存在未设置匹配数据的记录';
  362. }
  363. // 盒子验证
  364. $boxInfo = BoxService::make()->getCacheInfo();
  365. if (empty($boxInfo)) {
  366. RedisCache::set($cacheKey . 'error', ['ids' => $ids, 'date' => $date, 'msg' => '进行中的福袋数据不存在或预约中'], $cacheTime);
  367. return '当前福袋场次未开或预约中';
  368. }
  369. // 处理的预约记录
  370. $recordList = $this->model->alias('a')->whereIn('a.id', $ids)
  371. ->leftJoin('user u', 'u.id=a.uid')
  372. ->where('a.status', 1)
  373. ->field('a.id,a.box_id,a.num,a.uid,a.group_key,a.hs_xy,a.box10,a.box20,a.box30,a.box40,a.pay_type,a.open_time,u.has_fd,u.path,u.pid')
  374. ->select();
  375. $recordList = $recordList? $recordList->toarray() : [];
  376. if (empty($recordList)) {
  377. RedisCache::set($cacheKey . 'error', ['ids' => $ids, 'date' => $date, 'msg' => '暂无有效的预约记录'], $cacheTime);
  378. return '暂无有效的预约记录';
  379. }
  380. if (count($ids) != count($recordList)) {
  381. RedisCache::set($cacheKey . 'error', ['ids' => $ids,'count'=>count($recordList), 'date' => $date, 'msg' => '存在已处理记录,请刷新后重试'], $cacheTime);
  382. return '存在已处理记录,请刷新后重试~';
  383. }
  384. // 盒子商品
  385. $appointGoods = ShopGoodsService::make()->getBoxMatchGoods(20, 0,20);
  386. $boxGoods[10] = ShopGoodsService::make()->getBoxMatchGoods(10, 1,20);
  387. $boxGoods[20] = ShopGoodsService::make()->getBoxMatchGoods(20, 1,20);
  388. $boxGoods[30] = ShopGoodsService::make()->getBoxMatchGoods(30, 1,20);
  389. $boxGoods[40] = ShopGoodsService::make()->getBoxMatchGoods(40, 1,20);
  390. if (empty($appointGoods) && empty($boxGoods[10]) && empty($boxGoods[20]) && empty($boxGoods[30]) && empty($boxGoods[40])) {
  391. RedisCache::set($cacheKey . 'error', ['ids' => $ids, 'date' => $date, 'msg' => '请先设置福袋商品'], $cacheTime);
  392. return '请先设置福袋商品';
  393. }
  394. // 处理预约记录
  395. Db::startTrans();
  396. try {
  397. $boxMidList = [];
  398. $boxOpenArr = [];
  399. $awardUids = []; // 中奖的用户
  400. $groupKeys = []; // 已处理的记录分组
  401. $nullAwardCount = 0;
  402. $allAwardCount = 0;
  403. $boxCount = 0;
  404. foreach ($recordList as $key => $val) {
  405. $rid = isset($val['id']) ? $val['id'] : 0;
  406. $uid = isset($val['uid']) ? $val['uid'] : 0;
  407. $boxId = isset($val['box_id']) ? $val['box_id'] : 0;
  408. $groupKey = isset($val['group_key']) ? $val['group_key'] : '';
  409. $hasXy = isset($val['hs_xy']) ? $val['hs_xy'] : 0;
  410. $payType = isset($val['pay_type']) ? $val['pay_type'] : 0;
  411. $openTime = isset($val['open_time']) && $val['open_time'] ? $val['open_time'] : sr_getcurtime(time() + 120);
  412. if (!$rid || !$uid || !$boxId || empty($groupKey)) {
  413. Db::rollback();
  414. RedisCache::set($cacheKey . "r{$rid}_{$groupKey}_error", ['ids' => $ids, 'info' => $val, 'date' => $date, 'msg' => "抱歉用户[{$uid}]存在错误的预约数据,开袋失败"], $cacheTime);
  415. return "抱歉用户[{$uid}]存在错误的预约数据,开袋失败";
  416. }
  417. // 本次总预约数量
  418. $total = $this->model->where(['group_key' => $groupKey,'status'=> 1])->sum('num');
  419. $scorePayNum = $this->model->where(['group_key' => $groupKey,'status'=> 1,'pay_type'=>1])->sum('num');
  420. $box10 = isset($val['box10']) ? intval($val['box10']) : 0;
  421. $box20 = isset($val['box20']) ? intval($val['box20']) : 0;
  422. $box30 = isset($val['box30']) ? intval($val['box30']) : 0;
  423. $box40 = isset($val['box40']) ? intval($val['box40']) : 0;
  424. $openBoxNum = intval($box10 + $box20 + $box30 + $box40);
  425. $boxCount = $boxCount + $total;
  426. // 验证开出的盒子数和预约数量
  427. $tempScorePayNum = $scorePayNum;
  428. $nullCount = max(0, $total - $openBoxNum); // 空盒数量
  429. if ($openBoxNum > $total) {
  430. Db::rollback();
  431. RedisCache::set($cacheKey . "r{$rid}_{$groupKey}_error", ['ids' => $ids, 'total' => $total,'scoreNum'=>$tempScorePayNum, 'openNum' => $openBoxNum, 'info' => $val, 'date' => $date, 'msg' => "开袋失败:用户[{$uid}]的匹配数量设置超出预约数量"], $cacheTime);
  432. return "开袋失败:用户[{$uid}]的匹配数量设置超出预约数量";
  433. }
  434. // 处理空盒
  435. if ($nullCount > 0) {
  436. $time = sr_getcurtime(time() + $key);
  437. for ($i = 0; $i < $nullCount; $i++) {
  438. $boxMidList[] = [
  439. 'h_sn' => createdHandleOrderSn(),
  440. 'uid' => $uid,
  441. 'rid' => $rid,
  442. 'status' => 1,
  443. 'goods_id' => 0,
  444. 'create_time' => $time,
  445. 'box_settle_time' => $openTime,
  446. 'box_type' => 0,
  447. 'goods_price' => 0,
  448. 'pay_type' => $scorePayNum>0? 1 : 2
  449. ];
  450. $nullAwardCount++;
  451. $scorePayNum--;
  452. }
  453. }
  454. // 中奖处理
  455. $awardCount = 0;
  456. $openGoodsIds = [];
  457. if ($openBoxNum > 0) {
  458. $boxArr = [10 => '普通', 20 => '稀有', 30 => '史诗', 40 => '传说'];
  459. foreach ($boxArr as $bk => $bName) {
  460. $goodsArr = isset($boxGoods[$bk]) ? $boxGoods[$bk] : [];
  461. $awardNum = isset($val['box' . $bk]) ? intval($val['box' . $bk]) : 0;
  462. $time = sr_getcurtime(time() + ($bk / 10));
  463. // 有中奖
  464. if ($awardNum > 0) {
  465. for ($i = 0; $i < $awardNum; $i++) {
  466. // 指定稀有
  467. $openGoods = $goodsArr;
  468. if ($hasXy == 1 && $i != 0 && $bk == 20) {
  469. $openGoods = isset($appointGoods) ? $appointGoods : [];
  470. }
  471. $rand = $openGoods ? rand(0, count($openGoods) - 1) : 0;
  472. $goods = isset($openGoods[$rand]) ? $openGoods[$rand] : [];
  473. $goodsId = isset($goods['goods_id']) ? $goods['goods_id'] : 0;
  474. if (empty($openGoods) || empty($goods) || $goodsId <= 0) {
  475. Db::rollback();
  476. RedisCache::set($cacheKey . "r{$rid}_{$groupKey}_error", ['ids' => $ids, 'total' => $total,'scoreNum'=>$tempScorePayNum, 'openNum' => $openBoxNum, 'info' => $val, 'date' => $date, 'msg' => "开袋失败:[{$bName}]福袋商品没有库存可以开奖,请先设置"], $cacheTime);
  477. return "开袋失败:[{$bName}]福袋商品没有足够库存可以开奖,请先设置";
  478. }
  479. $boxMidList[] = [
  480. 'h_sn' => createdHandleOrderSn(),
  481. 'uid' => $uid,
  482. 'rid' => $rid,
  483. 'status' => 2,
  484. 'goods_id' => $goodsId,
  485. 'create_time' => $time,
  486. 'box_settle_time' => $openTime,
  487. 'box_type' => $bk,
  488. 'goods_price' => isset($goods['price']) ? $goods['price'] : 0,
  489. 'pay_type' => $scorePayNum>0? 1 : 2
  490. ];
  491. // 中奖数据
  492. $boxOpenArr[] = [
  493. 'status' => 1,
  494. 'h_sn' => createdHandleOrderSn(),
  495. 'uid' => $uid,
  496. 'rid' => $rid,
  497. 'handle_type' => 0,
  498. 'goods_id' => $goodsId,
  499. 'create_time' => $time,
  500. 'open_time' => $openTime,
  501. 'box_type' => $bk,
  502. 'goods_price' => isset($goods['price']) ? $goods['price'] : 0
  503. ];
  504. $openGoodsIds[] = $goodsId;
  505. // 用户已中奖
  506. $awardUids[$uid] = 1;
  507. // 累计中奖数
  508. $awardCount++;
  509. $allAwardCount++;
  510. $scorePayNum--;
  511. }
  512. }
  513. }
  514. // 如果设置了盒子但是未开出有,则开奖失败
  515. if (empty($openGoodsIds)) {
  516. Db::rollback();
  517. RedisCache::set($cacheKey . "r{$rid}_{$groupKey}_error", ['ids' => $ids, 'total' => $total,'scoreNum'=>$tempScorePayNum, 'openNum' => $openBoxNum, 'info' => $val, 'date' => $date, 'msg' => "开袋失败:用户[{$uid}]福袋开奖处理错误"], $cacheTime);
  518. return "开袋失败:用户[{$uid}]福袋开奖处理错误";
  519. }
  520. }
  521. // 更新开奖记录的开出商品ID
  522. $updateData = ['status' => 3, 'update_time' => date('Y-m-d H:i:s')];
  523. if ($openGoodsIds) {
  524. $updateData['goods_ids'] = implode(',', $openGoodsIds);
  525. }
  526. if (!$this->model->where('id', $rid)->update($updateData)) {
  527. Db::rollback();
  528. RedisCache::set($cacheKey . "r{$rid}_{$groupKey}_error", ['ids' => $ids, 'total' => $total,'scoreNum'=>$tempScorePayNum, 'openNum' => $openBoxNum, 'info' => $val, 'date' => $date, 'msg' => "开袋失败:用户[{$uid}]更新开袋状态失败"], $cacheTime);
  529. return "开袋失败:用户[{$uid}]更新开袋状态失败";
  530. }
  531. // 处理用户开盒数据统计
  532. $hasFd = isset($val['has_fd']) ? $val['has_fd'] : 0;
  533. $isUpdate = UserModel::where('id', $uid)
  534. // 中奖数据
  535. ->inc('total_null_box', $nullCount)
  536. ->inc('box10', $box10)
  537. ->inc('box20', $box20)
  538. ->inc('box30', $box30)
  539. ->inc('box40', $box40)
  540. // 团队数据
  541. ->inc('today_box', $awardCount)
  542. ->inc('today_team_box', $awardCount)
  543. ->inc('total_box', $awardCount)
  544. ->inc('total_team_box', $awardCount)
  545. // 是否中过福袋
  546. ->inc('has_fd', $awardCount && !$hasFd ? 1 : 0)
  547. ->update();
  548. if (!$isUpdate) {
  549. Db::rollback();
  550. RedisCache::set($cacheKey . "r{$rid}_{$groupKey}_error", ['ids' => $ids, 'total' => $total,'scoreNum'=>$tempScorePayNum, 'openNum' => $openBoxNum, 'info' => $val, 'date' => $date, 'msg' => "开袋失败:更新用户[{$uid}]的中奖数据错误"], $cacheTime);
  551. return "开袋失败:更新用户[{$uid}]的中奖数据错误";
  552. }
  553. // 团毒统计中奖次数更新
  554. $upperPath = isset($val['path']) ? $val['path'] : '';
  555. $pid = isset($val['pid']) ? $val['pid'] : 0;
  556. if ($awardCount > 0 && $upperPath) {
  557. if (!UserModel::where('id', 'in', $upperPath)->inc('total_team_box', $awardCount)->inc('has_update_level', (!$hasFd? 1:0))->update()) {
  558. Db::rollback();
  559. RedisCache::set($cacheKey . "r{$rid}_{$groupKey}_error", ['ids' => $ids, 'total' => $total,'scoreNum'=>$tempScorePayNum, 'path' => $upperPath, 'openNum' => $openBoxNum, 'info' => $val, 'date' => $date, 'msg' => "开袋失败:更新用户[{$uid}]的团队中奖数据错误"], $cacheTime);
  560. return "开袋失败:更新用户[{$uid}]的团队中奖数据错误";
  561. }
  562. // 如果当前用户第一次中奖,且有直推上级,上级有效直推累计
  563. if($pid>0 && !$hasFd){
  564. //UserModel::where('id', 'in', $pid)->inc('zt_num_valid', 1)->update();
  565. }
  566. // 清理有效直推和团队人数缓存
  567. RedisCache::keyDel("caches:users:counts*");
  568. }
  569. // 处理成功
  570. $groupKeys[] = $groupKey;
  571. RedisCache::set($cacheKey . "r{$rid}_{$groupKey}_catch", ['ids' => $ids, 'total' => $total,'scoreNum'=>$tempScorePayNum, 'awardCount' => $awardCount, 'openNum' => $openBoxNum, 'null' => $nullCount, 'info' => $val, 'date' => $date, 'msg' => "开袋处理成功:更新用户[{$uid}]的数据处理成功"], $cacheTime);
  572. }
  573. if (empty($groupKeys) || empty($boxMidList)) {
  574. Db::rollback();
  575. RedisCache::set($cacheKey . "error", ['ids' => $ids, 'count' => count($boxMidList),'scoreNum'=>$tempScorePayNum, 'groupKeys' => $groupKeys, 'date' => $date, 'msg' => "开袋失败:没有开出有效福袋"], $cacheTime);
  576. return "开袋失败:没有开出有效福袋";
  577. }
  578. // 更新同组盒子状态
  579. if (!$this->model->whereIn('group_key', $groupKeys)->update(['status' => 3, 'update_time' => date('Y-m-d H:i:s')])) {
  580. Db::rollback();
  581. RedisCache::set($cacheKey . "error", ['ids' => $ids, 'count' => count($boxMidList),'scoreNum'=>$tempScorePayNum, 'date' => $date, 'msg' => "开袋失败:更新福袋开袋状态数据错误"], $cacheTime);
  582. return "开袋失败:更新福袋开袋状态数据错误";
  583. }
  584. // 插入匹配数据
  585. if (!BoxMidHandleModel::insertAll($boxMidList)) {
  586. Db::rollback();
  587. RedisCache::set($cacheKey . "error", ['ids' => $ids, 'count' => count($boxMidList),'scoreNum'=>$tempScorePayNum, 'date' => $date, 'msg' => "开袋失败:写入福袋处理数据错误"], $cacheTime);
  588. return "开袋失败:写入福袋处理数据错误";
  589. }
  590. // 插入备份中奖盒子数据
  591. if ($boxOpenArr && !BoxHandleModel::insertAll($boxOpenArr)) {
  592. Db::rollback();
  593. RedisCache::set($cacheKey . "error", ['ids' => $ids, 'count' => count($boxMidList),'scoreNum'=>$tempScorePayNum, 'award' => count($boxOpenArr), 'date' => $date, 'msg' => "开袋失败:写入福袋中奖数据错误"], $cacheTime);
  594. return "开袋失败:写入福袋中奖数据错误";
  595. }
  596. // 插入中奖盒子数据
  597. if ($boxOpenArr && !BoxHandleAllModel::insertAll($boxOpenArr)) {
  598. Db::rollback();
  599. RedisCache::set($cacheKey . "errora", ['ids' => $ids, 'count' => count($boxMidList),'scoreNum'=>$tempScorePayNum, 'award' => count($boxOpenArr), 'date' => $date, 'msg' => "开袋失败:写入备份福袋中奖数据错误"], $cacheTime);
  600. return "开袋失败:写入福袋中奖数据错误";
  601. }
  602. Db::commit();
  603. RedisCache::clear($cacheKey . 'lock');
  604. RedisCache::set($cacheKey . "error", ['ids' => $ids, 'count' => count($boxMidList),'scoreNum'=>$tempScorePayNum, 'null' => $nullAwardCount, 'award' => $allAwardCount, 'date' => $date, 'msg' => "开袋失败:写入福袋中奖数据错误"], $cacheTime);
  605. return ['code' => 0, 'msg' => "开袋成功,本次提交处理数据" . count($ids) . "条,累计福袋{$boxCount}个,开出空袋:{$nullAwardCount}个,中奖{$allAwardCount}个。", 'data' => $ids];
  606. } catch (\Exception $exception){
  607. Db::rollback();
  608. RedisCache::set($cacheKey.'fail', ['ids'=> $ids,'error'=>['msg'=>$exception->getMessage(),'trace'=>$exception->getTrace()]], 3600);
  609. return '开奖失败:'.$exception->getMessage();
  610. }
  611. }
  612. }