BoxHandleService.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. <?php
  2. namespace app\common\service;
  3. use app\common\model\BoxHandleAllModel;
  4. use app\common\model\BoxHandleModel;
  5. use app\common\model\MoneyLogModel;
  6. use app\common\model\RecyclecardLogModel;
  7. use app\common\model\ShopGoods;
  8. use app\common\model\ShopOrder;
  9. use app\common\model\ShopOrderGoodsModel;
  10. use app\common\model\ShopOrderShippingModel;
  11. use app\common\model\UserAddressModel;
  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 BoxHandleService
  19. * @package app\common\service
  20. */
  21. class BoxHandleService
  22. {
  23. protected static $instance = null;
  24. protected $model = null;
  25. public function __construct()
  26. {
  27. $this->model = new BoxHandleModel();
  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 $uid
  43. * @param array $params
  44. * @param int $pageSize
  45. * @param string $field
  46. * @return array|mixed
  47. * @throws \think\Exception
  48. * @throws \think\db\exception\DataNotFoundException
  49. * @throws \think\db\exception\DbException
  50. * @throws \think\db\exception\ModelNotFoundException
  51. */
  52. public function getBoxListByUser($uid, $params=[], $pageSize=10, $field='')
  53. {
  54. $type = isset($params['type'])? $params['type'] : 0;
  55. $boxType = isset($params['box_type'])? $params['box_type'] : 0;
  56. if (!in_array($type, [1, 2])) {
  57. sr_throw('订单类型参数错误');
  58. }
  59. if ($boxType && !in_array($boxType, [10, 20, 30, 40])) {
  60. sr_throw('盒子类型参数错误');
  61. }
  62. $where = ['r.uid'=>$uid,'r.box_type'=>0,'r.status'=>$type,'r.is_delete'=> 2];
  63. if($boxType>0){
  64. $where['r.box_type'] = $boxType;
  65. }else{
  66. unset($where['r.box_type']);
  67. }
  68. // var_dump($where);
  69. $list = $this->model->alias('r')
  70. ->where($where)
  71. ->where(function($query) use($params){
  72. $keyword = isset($params['keywords'])? trim($params['keywords']):'';
  73. if($keyword){
  74. $query->where('r.h_sn','like',"%{$keyword}%");
  75. }
  76. })
  77. ->where(function($query){
  78. $query->where('r.open_time','<=',date('Y-m-d H:i:s'))->whereOr('r.open_time','null');
  79. })
  80. ->where(function($query) use($params){
  81. $time = isset($params['time'])? $params['time'] : '';
  82. $time1 = isset($params['time1'])? $params['time1'] : '';
  83. if($time){
  84. $query->where('r.create_time','>=', $time);
  85. }else if($time1){
  86. $query->where('r.create_time','<', $time1);
  87. }
  88. })
  89. ->field('r.*')
  90. ->order('r.create_time desc,r.id desc')
  91. ->paginate($pageSize)
  92. ->each(function($val, $k){
  93. $goodsInfo = ShopGoodsService::make()->getCacheInfoById($val['goods_id'], 'goods_name,goods_sn,goods_img,price,spec_name');
  94. $val['goods_name'] = $goodsInfo['goods_name'];
  95. $val['goods_sn'] = $goodsInfo['goods_sn'];
  96. $val['goods_img'] = $goodsInfo['goods_img'];
  97. $val['price'] = $goodsInfo['price'];
  98. $val['time_text'] = $val['create_time']? date('H:i:s', strtotime($val['create_time'])):'';
  99. $val['spec_name'] = $goodsInfo['spec_name'];
  100. if ($val['box_type'] == 10) {
  101. $val['is_canrecycle'] = 0;
  102. } else {
  103. $val['is_canrecycle'] = 1;
  104. }
  105. });
  106. $list = $list?$list->toArray():[];
  107. return isset($list['data'])? $list['data'] : [];
  108. }
  109. /**
  110. * 获取历史中奖福袋
  111. * @param $uid
  112. * @param array $params
  113. * @param int $pageSize
  114. * @param string $field
  115. * @return array|mixed
  116. * @throws \think\Exception
  117. * @throws \think\db\exception\DataNotFoundException
  118. * @throws \think\db\exception\DbException
  119. * @throws \think\db\exception\ModelNotFoundException
  120. */
  121. public function getHistoryBoxList($uid, $params=[], $pageSize=10, $field='')
  122. {
  123. $type = isset($params['type'])? $params['type'] : 0;
  124. $boxType = isset($params['box_type'])? $params['box_type'] : 0;
  125. if (!in_array($type, [1, 2])) {
  126. sr_throw('订单类型参数错误');
  127. }
  128. if ($boxType && !in_array($boxType, [10, 20, 30, 40])) {
  129. sr_throw('盒子类型参数错误');
  130. }
  131. $where = ['r.uid'=>$uid,'r.box_type'=>0,'r.status'=>$type,'r.is_delete'=> 2];
  132. if($boxType>0){
  133. $where['r.box_type'] = $boxType;
  134. }else{
  135. unset($where['r.box_type']);
  136. }
  137. $list = BoxHandleAllModel::alias('r')
  138. ->where($where)
  139. ->where(function($query) use($params){
  140. $keyword = isset($params['keywords'])? trim($params['keywords']):'';
  141. if($keyword){
  142. $query->where('r.h_sn','like',"%{$keyword}%");
  143. }
  144. })
  145. ->where(function($query){
  146. $query->where('r.open_time','<=',date('Y-m-d H:i:s'))->whereOr('r.open_time','null');
  147. })
  148. ->where('r.create_time','<',date('Y-m-d'))
  149. ->field('r.*')
  150. ->order('r.create_time desc,r.id desc')
  151. ->paginate($pageSize)
  152. ->each(function($val, $k){
  153. $goodsInfo = ShopGoodsService::make()->getCacheInfoById($val['goods_id'], 'goods_name,goods_sn,goods_img,price,spec_name');
  154. $val['goods_name'] = $goodsInfo['goods_name'];
  155. $val['goods_sn'] = $goodsInfo['goods_sn'];
  156. $val['goods_img'] = $goodsInfo['goods_img'];
  157. $val['price'] = $goodsInfo['price'];
  158. $val['time_text'] = $val['create_time']? date('H:i:s', strtotime($val['create_time'])):'';
  159. $val['spec_name'] = $goodsInfo['spec_name'];
  160. if ($val['box_type'] == 10) {
  161. $val['is_canrecycle'] = 0;
  162. } else {
  163. $val['is_canrecycle'] = 1;
  164. }
  165. });
  166. $list = $list?$list->toArray():[];
  167. return isset($list['data'])? $list['data'] : [];
  168. }
  169. /**
  170. * 获取福袋统计
  171. * @param $uid
  172. * @param $status
  173. * @param int $dateType
  174. * @return mixed
  175. */
  176. public function getBoxCount($uid,$status,$dateType=1)
  177. {
  178. $counts = ['10'=>0,'20'=>0,'30'=>0,'40'=>0];
  179. $model = new BoxHandleModel();
  180. // $model = $dateType == 1? new BoxHandleModel() : new BoxHandleAllModel();
  181. $datas = $model->where(['uid'=>$uid,'status'=>$status,'is_delete'=>2])
  182. ->where(function($query){
  183. $query->where('open_time','<=',date('Y-m-d H:i:s'))->whereOr('open_time','null');
  184. })
  185. ->where(function($query) use($dateType){
  186. if($dateType == 1){
  187. $query->where('create_time','>=',date('Y-m-d'));
  188. }else{
  189. $query->where('create_time','<',date('Y-m-d'));
  190. }
  191. })
  192. ->field(Db::raw('box_type,status,count(*) as total'))
  193. ->group('box_type')
  194. ->select();
  195. $datas = $datas? $datas->toArray() : [];
  196. $datas = array_column($datas,'total','box_type');
  197. if($datas){
  198. $counts = [
  199. '10'=> isset($datas[10])? $datas[10]:0,
  200. '20'=> isset($datas[20])? $datas[20]:0,
  201. '30'=> isset($datas[30])? $datas[30]:0,
  202. '40'=> isset($datas[40])? $datas[40]:0,
  203. ];
  204. }
  205. return $counts;
  206. }
  207. /**
  208. * 一键发货
  209. * @param $uid 用户ID
  210. * @param $params
  211. * @throws Exception
  212. * @throws \think\db\exception\DataNotFoundException
  213. * @throws \think\db\exception\DbException
  214. * @throws \think\db\exception\ModelNotFoundException
  215. */
  216. public function boxDelivery($uid, $params){
  217. $handIds = $params['hand_ids'];
  218. $addressId = $params['address_id'];
  219. $catchType = isset($params['date_type'])? $params['date_type'] : 0;
  220. $ids = explode(',', $handIds);
  221. if(empty($ids)){
  222. sr_throw('请选择发货的商品');
  223. }
  224. if (!in_array($catchType, [1,2])){
  225. sr_throw('处理参数错误');
  226. }
  227. $model = new BoxHandleModel();
  228. // $model = $catchType==1? new BoxHandleModel() : new BoxHandleAllModel();
  229. $boxList = $model->whereIn('id', $ids)
  230. ->where(['uid'=>$uid,'status'=>1,'is_delete'=>2])
  231. ->field('id,h_sn,status,uid,rid,handle_type,goods_id,box_type,goods_price')
  232. ->select();
  233. if (count($boxList) != count($ids)){
  234. sr_throw('商品参数错误或已处理,请刷新后重试');
  235. }
  236. $addressInfo = UserAddressModel::getAddressIdDetails((int)$addressId, $uid);
  237. if (!$addressInfo){
  238. sr_throw('地址错误');
  239. }
  240. $i=0;
  241. $catchIds = [];
  242. $orders = $orderGoods = $orderShippings = [];
  243. $orderId = ShopOrder::max('order_id')+1;
  244. $curTime = sr_getcurtime(time());
  245. $cacheKey = "caches:box:deliveryCatch:user_{$uid}:";
  246. foreach ($boxList as $key=>$val){
  247. $goodsInfo = ShopGoodsService::make()->getCacheInfoById($val['goods_id']);
  248. if(empty($goodsInfo)){
  249. sr_throw('商品参数错误');
  250. }
  251. // 判断该福袋是否已经处理
  252. if($model->where(['id'=>$val['id'],'status'=>2])->value('id')){
  253. sr_throw('商品已处理');
  254. }
  255. // 验证是否有处理订单
  256. if(ShopOrder::where(['user_id'=> $uid,'order_source'=> '福袋单号:'.$val['h_sn'],'status'=>1])->value('order_id')){
  257. sr_throw('存在已发货商品');
  258. }
  259. // 订单数据
  260. $orderId = $orderId+$i;
  261. $orders[] = [
  262. 'order_id'=>$orderId,
  263. 'order_sn'=>createdFDOrderSn(),
  264. 'payment'=>0,
  265. 'ship_postfee'=>0,
  266. 'user_id'=>$uid,
  267. 'status'=>1,
  268. 'num'=>1,
  269. 'order_type'=>5,
  270. 'order_remark'=> '福袋:'.$val['h_sn'],
  271. 'order_source'=> '福袋单号:'.$val['h_sn'],
  272. 'supplier_name'=>$goodsInfo['supplier_name'],
  273. 'total_price'=>0,
  274. 'created_time'=>$curTime,
  275. 'rebate_score'=>0,
  276. ];
  277. $orderGoods[] = [
  278. 'order_id'=> $orderId,
  279. 'goods_id'=> $goodsInfo['goods_id'],
  280. 'goods_name'=> $goodsInfo['goods_name'],
  281. 'goods_category'=> $goodsInfo['category'],
  282. 'goods_img'=> $goodsInfo['goods_img'],
  283. 'num'=>1,
  284. 'price'=> $goodsInfo['price'],
  285. 'total_fee'=> $goodsInfo['price'],
  286. 'spec_ids'=>1,
  287. 'spec_text'=> $goodsInfo['spec_name'],
  288. 'uid'=>$uid,
  289. 'rebate_score'=>0,
  290. 'total_rebate_score'=>0
  291. ];
  292. $orderShippings[] = [
  293. 'order_id'=> $orderId,
  294. 'sp_name'=> $addressInfo['name'],
  295. 'sp_mobile'=> $addressInfo['mobile'],
  296. 'sp_province'=> $addressInfo['sp_province'],
  297. 'sp_city'=> $addressInfo['sp_city'],
  298. 'sp_county'=> $addressInfo['sp_county'],
  299. 'sp_remark'=> $addressInfo['remark'],
  300. 'sp_mergename'=> $addressInfo['mergename'],
  301. 'created_time'=>$curTime
  302. ];
  303. $catchIds[] = $val['id'];
  304. $i++;
  305. }
  306. // 验证处理数据
  307. if(empty($orders) || empty($catchIds) || empty($orderGoods) || empty($orderShippings)){
  308. sr_throw('发货处理失败');
  309. }
  310. // 插入订单
  311. if(!ShopOrder::insertAll($orders)){
  312. sr_throw('处理发货订单错误');
  313. }
  314. // 发货订单商品
  315. if(!ShopOrderGoodsModel::insertAll($orderGoods)){
  316. sr_throw('处理发货订单商品数据错误');
  317. }
  318. // 发货订单信息
  319. if(!ShopOrderShippingModel::insertAll($orderShippings)){
  320. sr_throw('处理发单数据错误');
  321. }
  322. // 今日数据处理/历史数据处理
  323. if(!$model->whereIn('id', $catchIds)->update(['status'=>2,'handle_type'=>1,'update_time'=> $curTime])){
  324. sr_throw('处理福袋数据失败');
  325. }
  326. return true;
  327. }
  328. /**
  329. * 一件回收
  330. * @param $uid
  331. * @param $params
  332. * @return array
  333. * @throws \think\Exception
  334. * @throws \think\db\exception\DataNotFoundException
  335. * @throws \think\db\exception\DbException
  336. * @throws \think\db\exception\ModelNotFoundException
  337. */
  338. public function boxGoodsReBuy($uid, $params){
  339. $handIds = $params['hand_ids'];
  340. $isRetrieve = SystemConfigService::make()->getConfigByName('fudai_is_retrieve',1,'fudai');
  341. $isRetrieve = $isRetrieve? $isRetrieve : 0;
  342. if(!$isRetrieve){
  343. sr_throw('回收功能已暂时关闭');
  344. }
  345. $catchType = isset($params['date_type'])? $params['date_type'] : 0;
  346. $ids = explode(',', $handIds);
  347. if(empty($ids)){
  348. sr_throw('请选择回收的商品');
  349. }
  350. if (!in_array($catchType, [1,2])){
  351. sr_throw('处理参数错误');
  352. }
  353. $num = count($ids);
  354. $model = new BoxHandleModel();
  355. // $model = $catchType==1? new BoxHandleModel() : new BoxHandleAllModel();
  356. $boxList = $model->whereIn('id', $ids)
  357. ->where(['uid'=>$uid,'status'=>1,'is_delete'=>2])
  358. ->field('id,h_sn,status,uid,rid,handle_type,goods_id,box_type,goods_price')
  359. ->select();
  360. if (count($boxList) != count($ids)){
  361. sr_throw('商品参数错误或已处理,请刷新后重试');
  362. }
  363. if ($model->where('box_type', 10)->where('id', 'in', $ids)->value('id')){
  364. sr_throw('普通商品只能发货,不能回收');
  365. }
  366. if(UserUnmoneyModel::where(['ids'=> $handIds,'status'=>1])->value('id')){
  367. sr_throw('商品已处理');
  368. }
  369. // 待处理的总金额
  370. $totalMoney = $model->where('id', 'in', $ids)->sum('goods_price');
  371. $serviceFee = $num* env('boxsetting.RECYCLE_ONBOX_PRICE');
  372. $endMoney = $totalMoney - $serviceFee;
  373. if ($endMoney < 0){
  374. sr_throw('错误,请联系客服');
  375. }
  376. // 申请
  377. if ($params['action'] == 'apply'){
  378. return [
  379. 'total_count'=>count($boxList),
  380. 'end_money'=>$endMoney,
  381. 'total_money'=>$totalMoney
  382. ];
  383. }
  384. // 回收
  385. else if ($params['action'] == 'surerecycle'){
  386. $userInfo = UserService::make()->getCacheInfo($uid,'id,score,money,recycle_count,profit_money');
  387. $recycleCount = isset($userInfo['recycle_count'])? $userInfo['recycle_count'] : 0;
  388. $userProfitMoney = isset($userInfo['profit_money'])? $userInfo['profit_money'] : 0;
  389. $userMoney = isset($userInfo['money'])? $userInfo['money'] : 0;
  390. $userScore = isset($userInfo['score'])? $userInfo['score'] : 0;
  391. // 回收卡扣除
  392. if ($recycleCount < $num){
  393. sr_throw('回收卡不足'.$num.'个');
  394. }
  395. // 扣除回收卡
  396. if(!UserModel::where('id',$uid)->dec('recycle_count', $num)->update()){
  397. sr_throw('回收卡扣除失败');
  398. }
  399. $data = [
  400. 'uid'=>$uid,
  401. 'type'=>3,
  402. 'score'=> $num,
  403. 'create_at'=>sr_getcurtime(time()),
  404. 'state'=> 2,
  405. 'before_score'=> $recycleCount,
  406. 'after_score'=> max(0,$recycleCount - $num),
  407. 'from_id'=> 0,
  408. 'uid2'=> $handIds
  409. ];
  410. if(!RecyclecardLogModel::insertGetId($data)){
  411. sr_throw('回收卡扣除处理失败');
  412. }
  413. // 288的原价一个,累计回收到余额到钱
  414. $totalFee = $num * env('boxsetting.ONE_BOX_PRICE');
  415. // 扣除手续费后的钱除去原价为利润
  416. $profitMoney = max(0, $endMoney - $totalFee);
  417. if(!UserModel::where('id', $uid)->inc('money', $totalFee)->update()){
  418. sr_throw('回收余额结算错误');
  419. }
  420. $data = [
  421. 'uid'=>$uid,
  422. 'type'=> 2,
  423. 'money'=> $totalFee,
  424. 'create_at'=>sr_getcurtime(time()),
  425. 'state'=> 1,
  426. 'before_money'=> $userMoney,
  427. 'after_money'=> floatval($userMoney + $totalFee),
  428. 'from_id'=> 0,
  429. 'uid2'=> $handIds,
  430. 'free_type'=> 0,
  431. 'remark'=> "回收{$num}个福袋商品"
  432. ];
  433. if(!MoneyLogModel::insertGetId($data)){
  434. sr_throw('回收商品金额处理失败');
  435. }
  436. // 利润
  437. if ($profitMoney>0){
  438. // 利润结算
  439. if(!UserModel::where('id', $uid)->inc('profit_money', $profitMoney)->update()){
  440. sr_throw('回收商品利润结算错误');
  441. }
  442. // 添加用户利润记录
  443. $data = [
  444. 'uid'=>$uid,
  445. 'money'=> $profitMoney,
  446. 'status'=> 2,
  447. 'type'=> 1,
  448. 'ids'=> $handIds,
  449. 'state'=> 1,
  450. 'before_money'=> $userProfitMoney,
  451. 'after_money'=> floatval($userProfitMoney + $profitMoney),
  452. 'remark'=> "回收{$num}个福袋结算,总金额:{$totalMoney}",
  453. 'create_time'=>sr_getcurtime(time())
  454. ];
  455. if(!UserUnmoneyModel::insertGetId($data)){
  456. sr_throw('商品回收利润处理错误');
  457. }
  458. // 更新团队利润数据
  459. }
  460. // 改变用户处理状态
  461. if(!$model->whereIn('id', $ids)->update(['status'=>2, 'handle_type'=>2, 'update_time'=>date('Y-m-d H:i:s')])){
  462. sr_throw('更新回收处理状态失败');
  463. }
  464. $logData = ['ids'=> $ids,'totalMoney'=> $totalMoney,'fee'=>$serviceFee,'profit'=>$profitMoney,'back'=>$totalFee,'data'=>$data,'date'=>date('Y-m-d H:i:s')];
  465. RedisCache::set("caches:box:recycle:user_{$uid}:".md5(json_encode($ids)), $logData, 7200);
  466. return [
  467. 'ids'=> $ids,
  468. 'total_fee'=> $totalFee,
  469. 'profit_money'=> $profitMoney
  470. ];
  471. }
  472. }
  473. }