StorePink.php 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. <?php
  2. /**
  3. *
  4. * @author: xaboy<365615158@qq.com>
  5. * @day: 2017/12/18
  6. */
  7. namespace app\models\store;
  8. use app\models\routine\RoutineFormId;
  9. use app\models\routine\RoutineTemplate;
  10. use app\models\tree\TreeRecommend;
  11. use app\models\user\User;
  12. use app\models\user\UserBill;
  13. use app\models\user\WechatUser;
  14. use crmeb\basic\BaseModel;
  15. use crmeb\services\WechatTemplateService;
  16. use crmeb\traits\ModelTrait;
  17. use think\facade\Log;
  18. use think\facade\Route;
  19. /**
  20. * TODO 拼团Model
  21. * Class StorePink
  22. * @package app\models\store
  23. */
  24. class StorePink extends BaseModel
  25. {
  26. /**
  27. * 数据表主键
  28. * @var string
  29. */
  30. protected $pk = 'id';
  31. /**
  32. * 模型名称
  33. * @var string
  34. */
  35. protected $name = 'store_pink';
  36. use ModelTrait;
  37. /**
  38. * 获取拼团完成的用户
  39. * @param $uid
  40. * @return array
  41. */
  42. public static function getPinkOkList($uid)
  43. {
  44. $list = self::alias('a')->where('a.status', 2)->where('a.is_refund', 0)->where('a.uid', '<>', $uid)->join('User u', 'u.uid=a.uid', 'right')->column('nickname', 'id');
  45. $msg = [];
  46. foreach ($list as &$item) {
  47. $msg[] = $item .= '拼团成功';
  48. }
  49. return $msg;
  50. }
  51. /*
  52. * 获取拼团完成的商品总件数
  53. * */
  54. public static function getPinkOkSumTotalNum($id)
  55. {
  56. return self::where('status', 2)->where('is_refund', 0)->sum('total_num');
  57. }
  58. /**
  59. * 获取一条拼团数据
  60. * @param $id
  61. * @return mixed
  62. */
  63. public static function getPinkUserOne($id)
  64. {
  65. $model = new self();
  66. $model = $model->alias('p');
  67. $model = $model->field('p.*,u.nickname,u.avatar');
  68. $model = $model->where('id', $id);
  69. $model = $model->join('user u', 'u.uid = p.uid');
  70. return $model->find();
  71. }
  72. /**
  73. * 获取拼团的团员
  74. * @param $id
  75. * @return mixed
  76. */
  77. public static function getPinkMember($id)
  78. {
  79. $model = new self();
  80. $model = $model->alias('p');
  81. $model = $model->field('p.*,u.nickname,u.avatar');
  82. $model = $model->where('k_id', $id);
  83. $model = $model->where('is_refund', 0);
  84. $model = $model->join('user u', 'u.uid = p.uid');
  85. $model = $model->order('id asc');
  86. return $model->select();
  87. }
  88. /**
  89. * 设置结束时间
  90. * @param $idAll
  91. * @return $this
  92. */
  93. public static function setPinkStopTime($idAll)
  94. {
  95. $model = new self();
  96. $model = $model->where('id', 'IN', $idAll);
  97. return $model->update(['stop_time' => time(), 'status' => 2]);
  98. }
  99. /**
  100. * 获取正在拼团的数据 团长
  101. * @param int $cid 产品id
  102. * @param int $isAll 是否查找所有拼团
  103. * @return array
  104. */
  105. public static function getPinkAll($cid, $isAll = false)
  106. {
  107. $model = new self();
  108. $model = $model->alias('p');
  109. $model = $model->field('p.id,p.uid,p.people,p.price,p.stop_time,u.nickname,u.avatar');
  110. $model = $model->where('stop_time', '>', time());
  111. $model = $model->where('p.cid', $cid);
  112. $model = $model->where('p.k_id', 0);
  113. $model = $model->where('p.is_refund', 0);
  114. $model = $model->order('p.add_time desc');
  115. $model = $model->join('user u', 'u.uid = p.uid');
  116. $list = $model->select();
  117. $list = count($list) ? $list->toArray() : [];
  118. if ($isAll) {
  119. $pindAll = [];
  120. foreach ($list as &$v) {
  121. $v['count'] = self::getPinkPeople($v['id'], $v['people']);
  122. $v['h'] = date('H', $v['stop_time']);
  123. $v['i'] = date('i', $v['stop_time']);
  124. $v['s'] = date('s', $v['stop_time']);
  125. $pindAll[] = $v['id'];//开团团长ID
  126. $v['stop_time'] = (int)$v['stop_time'];
  127. }
  128. return [$list, $pindAll];
  129. }
  130. return $list;
  131. }
  132. /**
  133. * 获取还差几人
  134. * @param $kid
  135. * @param $people
  136. * @return string
  137. */
  138. public static function getPinkPeople($kid, $people)
  139. {
  140. $model = new self();
  141. $model = $model->where('k_id', $kid)->where('is_refund', 0);
  142. $count = bcadd($model->count(), 1, 0);
  143. return bcsub($people, $count, 0);
  144. }
  145. /**
  146. * 判断订单是否在当前的拼团中
  147. * @param $orderId
  148. * @param $kid
  149. * @return bool
  150. */
  151. public static function getOrderIdAndPink($orderId, $kid)
  152. {
  153. $model = new self();
  154. $pink = $model->where('k_id|id', $kid)->column('order_id');
  155. if (in_array($orderId, $pink)) return true;
  156. else return false;
  157. }
  158. /**
  159. * 判断用户是否在团内
  160. * @param $id
  161. * @return int|string
  162. */
  163. public static function getIsPinkUid($id = 0, $uid = 0)
  164. {
  165. $pink = self::where('k_id|id', $id)->where('uid', $uid)->where('is_refund', 0)->count();
  166. if ($pink) return true;
  167. else return false;
  168. }
  169. /**
  170. * 判断是否发送模板消息 0 未发送 1已发送
  171. * @param $uidAll
  172. * @return int|string
  173. */
  174. public static function isTpl($uidAll, $pid)
  175. {
  176. if (is_array($uidAll))
  177. $count = self::where('uid', 'IN', implode(',', $uidAll))->where('is_tpl', 0)->where('id|k_id', $pid)->count();
  178. else
  179. $count = self::where('uid', $uidAll)->where('is_tpl', 0)->where('k_id|id', $pid)->count();
  180. return $count;
  181. }
  182. /**
  183. * 拼团成功提示模板消息
  184. * @param $uidAll
  185. * @param $pid
  186. */
  187. public static function orderPinkAfter($uidAll, $pid)
  188. {
  189. $pinkInfo = self::where('p.id|p.k_id', $pid)->alias('p')->field(['p.people', 't.title', 'p.add_time', 'p.order_id', 'u.nickname'])->join('user u', 'u.uid = p.uid')->join('store_combination t', 'p.cid = t.id')->find();
  190. if (!$pinkInfo) return false;
  191. foreach ($uidAll as $key => &$item) {
  192. $openid = WechatUser::uidToOpenid($item, 'openid');
  193. $routineOpenid = WechatUser::uidToOpenid($item, 'routine_openid');
  194. if ($openid) { //公众号模板消息
  195. $firstWeChat = '亲,您的拼团已经完成了';
  196. $keyword1WeChat = self::where('id|k_id', $pid)->where('uid', $item)->value('order_id');
  197. $keyword2WeChat = self::alias('p')->where('p.id|p.k_id', $pid)->where('p.uid', $item)->join('store_combination c', 'c.id=p.cid')->value('c.title');
  198. $remarkWeChat = '点击查看订单详情';
  199. $urlWeChat = Route::buildUrl('order/detail/' . $keyword1WeChat)->suffix('')->domain(true)->build();
  200. WechatTemplateService::sendTemplate($openid, WechatTemplateService::ORDER_USER_GROUPS_SUCCESS, [
  201. 'first' => $firstWeChat,
  202. 'keyword1' => $keyword1WeChat,
  203. 'keyword2' => $keyword2WeChat,
  204. 'remark' => $remarkWeChat
  205. ], $urlWeChat);
  206. } else if ($routineOpenid) {// 小程序模板消息
  207. RoutineTemplate::sendPinkSuccess($item, $pinkInfo['title'], $pinkInfo['nickname'] ?? '', $pinkInfo['add_time'], $pinkInfo['people'], '/pages/order_details/index?order_id=' . $pinkInfo['order_id']);
  208. }
  209. }
  210. self::beginTrans();
  211. $res1 = self::where('uid', 'IN', implode(',', $uidAll))->where('id|k_id', $pid)->update(['is_tpl' => 1]);
  212. self::checkTrans($res1);
  213. }
  214. /**
  215. * 拼团失败发送的模板消息
  216. * @param $uid
  217. * @param $pid
  218. */
  219. public static function orderPinkAfterNo($uid, $pid, $formId = '', $fillTilt = '', $isRemove = false)
  220. {
  221. $store = self::alias('p')->where('p.id|p.k_id', $pid)->field('c.*')->where('p.uid', $uid)->join('store_combination c', 'c.id=p.cid')->find();
  222. $pink = self::where('id|k_id', $pid)->where('uid', $uid)->find();
  223. $openid = WechatUser::uidToOpenid($uid, 'openid');
  224. $routineOpenid = WechatUser::uidToOpenid($uid, 'routine_openid');
  225. if ($isRemove) {
  226. if ($openid) {//公众号发送模板消息
  227. $urlWeChat = Route::buildUrl('order/detail/' . $pink->order_id)->suffix('')->domain(true)->build();
  228. WechatTemplateService::sendTemplate($openid, WechatTemplateService::ORDER_USER_GROUPS_LOSE, [
  229. 'first' => '亲,您的拼团取消',
  230. 'keyword1' => $store->title,
  231. 'keyword2' => $pink->price,
  232. 'keyword3' => $pink->price,
  233. 'remark' => '点击查看订单详情'
  234. ], $urlWeChat);
  235. } else if ($routineOpenid) {//小程序发送模板消息
  236. RoutineTemplate::sendPinkFail($uid, $store->title, $pink->people, '亲,您的拼团取消,点击查看订单详情', '/pages/order_details/index?order_id=' . $pink->order_id);
  237. }
  238. } else {
  239. if ($openid) {//公众号发送模板消息
  240. $urlWeChat = Route::buildUrl('order/detail/' . $pink->order_id)->suffix('')->domain(true)->build();
  241. WechatTemplateService::sendTemplate($openid, WechatTemplateService::ORDER_USER_GROUPS_LOSE, [
  242. 'first' => '亲,您的拼团失败',
  243. 'keyword1' => $store->title,
  244. 'keyword2' => $pink->price,
  245. 'keyword3' => $pink->price,
  246. 'remark' => '点击查看订单详情'
  247. ], $urlWeChat);
  248. } else if ($routineOpenid) {//小程序发送模板消息
  249. RoutineTemplate::sendPinkFail(
  250. $uid,
  251. $store->title,
  252. $pink->people,
  253. '亲,您拼团失败,自动为您申请退款,退款金额为:' . $pink->price,
  254. '/pages/order_details/index?order_id=' . $pink->order_id
  255. );
  256. }
  257. }
  258. self::where('id', $pid)->update(['status' => 3, 'stop_time' => time()]);
  259. self::where('k_id', $pid)->update(['status' => 3, 'stop_time' => time()]);
  260. }
  261. /**
  262. * 获取当前拼团数据返回订单编号
  263. * @param $id
  264. * @return array|false|\PDOStatement|string|\think\Model
  265. */
  266. public static function getCurrentPink($id, $uid)
  267. {
  268. $pink = self::where('id', $id)->where('uid', $uid)->find();
  269. if (!$pink) $pink = self::where('k_id', $id)->where('uid', $uid)->find();
  270. return StoreOrder::where('id', $pink['order_id_key'])->value('order_id');
  271. }
  272. public static function systemPage($where)
  273. {
  274. $model = new self;
  275. $model = $model->alias('p');
  276. $model = $model->field('p.*,c.title');
  277. if ($where['data'] !== '') {
  278. list($startTime, $endTime) = explode(' - ', $where['data']);
  279. $model = $model->where('p.add_time', '>', strtotime($startTime));
  280. $model = $model->where('p.add_time', '<', strtotime($endTime));
  281. }
  282. if ($where['status']) $model = $model->where('p.status', $where['status']);
  283. $model = $model->where('p.k_id', 0);
  284. $model = $model->order('p.id desc');
  285. $model = $model->join('StoreCombination c', 'c.id=p.cid');
  286. return self::page($model, function ($item) use ($where) {
  287. $item['count_people'] = bcadd(self::where('k_id', $item['id'])->count(), 1, 0);
  288. }, $where);
  289. }
  290. public static function isPinkBe($data, $id)
  291. {
  292. $data['id'] = $id;
  293. $count = self::where($data)->count();
  294. if ($count) return $count;
  295. $data['k_id'] = $id;
  296. $count = self::where($data)->count();
  297. if ($count) return $count;
  298. else return 0;
  299. }
  300. public static function isPinkStatus($pinkId)
  301. {
  302. if (!$pinkId) return false;
  303. $stopTime = self::where('id', $pinkId)->value('stop_time');
  304. if ($stopTime < time()) return true; //拼团结束
  305. else return false;//拼团未结束
  306. }
  307. /**
  308. * 判断拼团结束 后的状态
  309. * @param $pinkId
  310. * @return bool
  311. */
  312. public static function isSetPinkOver($pinkId)
  313. {
  314. $people = self::where('id', $pinkId)->value('people');
  315. $stopTime = self::where('id', $pinkId)->value('stop_time');
  316. if ($stopTime < time()) {
  317. $countNum = self::getPinkPeople($pinkId, $people);
  318. if ($countNum) return false;//拼团失败
  319. else return true;//拼团成功
  320. } else return true;
  321. }
  322. /**
  323. * 拼团退款
  324. * @param $id
  325. * @return bool
  326. */
  327. public static function setRefundPink($oid)
  328. {
  329. $res = true;
  330. $order = StoreOrder::where('id', $oid)->find();
  331. if ($order['pink_id']) $id = $order['pink_id'];
  332. else return $res;
  333. $count = self::where('id', $id)->where('uid', $order['uid'])->find();//正在拼团 团长
  334. $countY = self::where('k_id', $id)->where('uid', $order['uid'])->find();//正在拼团 团员
  335. if (!$count && !$countY) return $res;
  336. if ($count) {//团长
  337. //判断团内是否还有其他人 如果有 团长为第二个进团的人
  338. $kCount = self::where('k_id', $id)->order('add_time asc')->find();
  339. if ($kCount) {
  340. $res11 = self::where('k_id', $id)->update(['k_id' => $kCount['id']]);
  341. $res12 = self::where('id', $kCount['id'])->update(['stop_time' => $count['add_time'] + 86400, 'k_id' => 0]);
  342. $res1 = $res11 && $res12;
  343. $res2 = self::where('id', $id)->update(['stop_time' => time() - 1, 'k_id' => 0, 'is_refund' => $kCount['id'], 'status' => 3]);
  344. } else {
  345. $res1 = true;
  346. $res2 = self::where('id', $id)->update(['stop_time' => time() - 1, 'k_id' => 0, 'is_refund' => $id, 'status' => 3]);
  347. }
  348. //修改结束时间为前一秒 团长ID为0
  349. $res = $res1 && $res2;
  350. } else if ($countY) {//团员
  351. $res = self::where('id', $countY['id'])->update(['stop_time' => time() - 1, 'k_id' => 0, 'is_refund' => $id, 'status' => 3]);
  352. }
  353. return $res;
  354. }
  355. /**
  356. * 拼团人数完成时,判断全部人都是未退款状态
  357. * @param $pinkIds
  358. * @return bool
  359. */
  360. public static function setPinkStatus($pinkIds)
  361. {
  362. $orderPink = self::where('id', 'IN', $pinkIds)->where('is_refund', 1)->count();
  363. if (!$orderPink) return true;
  364. else return false;
  365. }
  366. /**
  367. * 创建拼团
  368. * @param $order
  369. * @return mixed
  370. */
  371. public static function createPink($order)
  372. {
  373. $order = StoreOrder::tidyOrder($order, true)->toArray();
  374. $openid = WechatUser::uidToOpenid($order['uid'], 'openid');
  375. $routineOpenid = WechatUser::uidToOpenid($order['uid'], 'routine_openid');
  376. $product = StoreCombination::where('id', $order['combination_id'])->field('effective_time,title,bingo_people')->find();
  377. if ($product) {
  378. if ($order['pink_id']) {//拼团存在
  379. $res = false;
  380. $pink['uid'] = $order['uid'];//用户id
  381. if (self::isPinkBe($pink, $order['pink_id'])) return false;
  382. $pink['order_id'] = $order['order_id'];//订单id 生成
  383. $pink['order_id_key'] = $order['id'];//订单id 数据库id
  384. $pink['total_num'] = $order['total_num'];//购买个数
  385. $pink['total_price'] = $order['pay_price'];//总金额
  386. $pink['k_id'] = $order['pink_id'];//拼团id
  387. foreach ($order['cartInfo'] as $v) {
  388. $pink['cid'] = $v['combination_id'];//拼团产品id
  389. $pink['pid'] = $v['product_id'];//产品id
  390. $pink['people'] = StoreCombination::where('id', $v['combination_id'])->value('people');//几人拼团
  391. $pink['price'] = $v['productInfo']['price'];//单价
  392. $pink['stop_time'] = 0;//结束时间
  393. $pink['add_time'] = time();//开团时间
  394. $res = self::create($pink)->toArray();
  395. }
  396. if ($openid) { //公众号模板消息
  397. $urlWeChat = Route::buildUrl('order/detail/' . $order['order_id'])->suffix('')->domain(true)->build();
  398. WechatTemplateService::sendTemplate($openid, WechatTemplateService::ORDER_USER_GROUPS_SUCCESS, [
  399. 'first' => '亲,您已成功参与拼团',
  400. 'keyword1' => $order['order_id'],
  401. 'keyword2' => $product->title,
  402. 'remark' => '点击查看订单详情'
  403. ], $urlWeChat);
  404. } else if ($routineOpenid) {
  405. $nickname = User::where('uid', self::where('id', $pink['k_id'])->value('uid'))->value('nickname');
  406. RoutineTemplate::sendPinkSuccess(
  407. $order['uid'], $product->title,
  408. $nickname,
  409. $pink['add_time'],
  410. $pink['people'],
  411. '/pages/order_details/index?order_id=' . $pink['order_id']
  412. );
  413. }
  414. //处理拼团完成
  415. list($pinkAll, $pinkT, $count, $idAll, $uidAll) = self::getPinkMemberAndPinkK($pink);
  416. if ($pinkT['status'] == 1) {
  417. if (!$count)//组团完成
  418. self::PinkComplete($uidAll, $idAll, $pink['uid'], $pinkT, $product['bingo_people']);
  419. else
  420. self::PinkFail($pinkAll, $pinkT, 0);
  421. }
  422. if ($res) return true;
  423. else return false;
  424. } else {
  425. $res = false;
  426. $pink['uid'] = $order['uid'];//用户id
  427. $pink['order_id'] = $order['order_id'];//订单id 生成
  428. $pink['order_id_key'] = $order['id'];//订单id 数据库id
  429. $pink['total_num'] = $order['total_num'];//购买个数
  430. $pink['total_price'] = $order['pay_price'];//总金额
  431. $pink['k_id'] = 0;//拼团id
  432. foreach ($order['cartInfo'] as $v) {
  433. $pink['cid'] = $v['combination_id'];//拼团产品id
  434. $pink['pid'] = $v['product_id'];//产品id
  435. $pink['people'] = StoreCombination::where('id', $v['combination_id'])->value('people');//几人拼团
  436. $pink['price'] = $v['productInfo']['price'];//单价
  437. $pink['stop_time'] = bcadd(time(), bcmul($product->effective_time, 3600, 0), 0);//结束时间
  438. $pink['add_time'] = time();//开团时间
  439. $res1 = self::create($pink)->toArray();
  440. $res2 = StoreOrder::where('id', $order['id'])->update(['pink_id' => $res1['id']]);
  441. $res = $res1 && $res2;
  442. }
  443. // 开团成功发送模板消息
  444. if ($openid && $order['is_channel'] != 1) { //公众号模板消息
  445. $urlWeChat = Route::buildUrl('/order/detail/' . $pink['order_id'])->suffix('')->domain(true)->build();
  446. WechatTemplateService::sendTemplate($openid, WechatTemplateService::OPEN_PINK_SUCCESS, [
  447. 'first' => '您好,您已成功开团!赶紧与小伙伴们分享吧!!!',
  448. 'keyword1' => $product->title,
  449. 'keyword2' => $pink['total_price'],
  450. 'keyword3' => $pink['people'],
  451. 'remark' => '点击查看订单详情'
  452. ], $urlWeChat);
  453. } else if ($routineOpenid && $order['is_channel'] == 1) {
  454. $nickname = User::where('uid', $order['uid'])->value('nickname');
  455. RoutineTemplate::sendPinkSuccess(
  456. $order['uid'], $product->title,
  457. $nickname,
  458. $pink['add_time'],
  459. $pink['people'],
  460. '/pages/order_details/index?order_id=' . $pink['order_id']
  461. );
  462. }
  463. if ($res) return true;
  464. else return false;
  465. }
  466. } else {
  467. Log::error('拼团支付成功读取产品数据失败订单号:' . $order['order_id']);
  468. }
  469. }
  470. /*
  471. * 获取一条今天正在拼团的人的头像和名称
  472. * */
  473. public static function getPinkSecondOne()
  474. {
  475. $addTime = mt_rand(time() - 30000, time());
  476. return self::where('p.add_time', '>', $addTime)->alias('p')->where('p.status', 1)->join('User u', 'u.uid=p.uid')->field('u.nickname,u.avatar as src')->find();
  477. }
  478. /**
  479. * 拼团成功后给团长返佣金
  480. * @param int $id
  481. * @return bool
  482. */
  483. // public static function setRakeBackColonel($id = 0){
  484. // if(!$id) return false;
  485. // $pinkRakeBack = self::where('id',$id)->field('people,price,uid,id')->find()->toArray();
  486. // $countPrice = bcmul($pinkRakeBack['people'],$pinkRakeBack['price'],2);
  487. // if(bcsub((float)$countPrice,0,2) <= 0) return true;
  488. // $rakeBack = (sys_config('rake_back_colonel') ?: 0)/100;
  489. // if($rakeBack <= 0) return true;
  490. // $rakeBackPrice = bcmul($countPrice,$rakeBack,2);
  491. // if($rakeBackPrice <= 0) return true;
  492. // $mark = '拼团成功,奖励佣金'.floatval($rakeBackPrice);
  493. // self::beginTrans();
  494. // $res1 = UserBill::income('获得拼团佣金',$pinkRakeBack['uid'],'now_money','colonel',$rakeBackPrice,$id,0,$mark);
  495. // $res2 = User::bcInc($pinkRakeBack['uid'],'now_money',$rakeBackPrice,'uid');
  496. // $res = $res1 && $res2;
  497. // self::checkTrans($res);
  498. // return $res;
  499. // }
  500. /*
  501. * 拼团完成更改数据写入内容
  502. * @param array $uidAll 当前拼团uid
  503. * @param array $idAll 当前拼团pink_id
  504. * @param array $pinkT 团长信息
  505. * @return int
  506. * */
  507. public static function PinkComplete($uidAll, $idAll, $uid, $pinkT, $bingo_people)
  508. {
  509. $pinkBool = 6;
  510. try {
  511. if (self::setPinkStatus($idAll)) {
  512. self::setPinkStopTime($idAll);
  513. $bingo = [];
  514. // for ($i = 0; $i < $bingo_people; $i++) {
  515. // do {
  516. // $id = $idAll[rand(0, count($idAll) - 1)];
  517. // } while (in_array($id, $bingo) || !$id);
  518. // $bingo[] = $id;
  519. // }
  520. if (in_array($uid, $uidAll)) {
  521. if (self::isTpl($uidAll, $pinkT['id'])) self::orderPinkAfter($uidAll, $pinkT['id']);
  522. $pinkBool = 1;
  523. } else $pinkBool = 3;
  524. // foreach ($idAll as $vi) {
  525. // $pink_info = self::get($vi);
  526. // if (!in_array($vi, $bingo)) {
  527. // StoreOrder::refundPink($pink_info['order_id_key']);
  528. // self::pinkReturn($pink_info['order_id_key']);
  529. // } else {
  530. // TreeRecommend::insertTree($pink_info['uid'], User::where('uid', $pink_info['uid'])->value('spread_uid'));
  531. // self::pinkIntegral($pink_info['order_id_key']);
  532. // }
  533. // self::pinkRecommend($pink_info['order_id_key']);
  534. // }
  535. }
  536. return $pinkBool;
  537. } catch (\Exception $e) {
  538. self::setErrorInfo($e->getMessage());
  539. return $pinkBool;
  540. }
  541. }
  542. /*
  543. * 拼团失败 退款
  544. * @param array $pinkAll 拼团数据,不包括团长
  545. * @param array $pinkT 团长数据
  546. * @param int $pinkBool
  547. * @param boolen $isRunErr 是否返回错误信息
  548. * @param boolen $isIds 是否返回记录所有拼团id
  549. * @return int| boolen
  550. * */
  551. public static function PinkFail($pinkAll, $pinkT, $pinkBool, $isRunErr = true, $isIds = false)
  552. {
  553. self::startTrans();
  554. $pinkIds = [];
  555. try {
  556. if ($pinkT['stop_time'] < time()) {//拼团时间超时 退款
  557. $pinkBool = -1;
  558. array_push($pinkAll, $pinkT);
  559. foreach ($pinkAll as $v) {
  560. if (StoreOrder::orderApplyRefund(StoreOrder::getPinkOrderId($v['order_id_key']), $v['uid'], '拼团时间超时') && self::isTpl($v['uid'], $pinkT['id'])) {
  561. // if (StoreOrder::refundPink($v['order_id_key']) && self::isTpl($v['uid'], $pinkT['id'])) {
  562. if ($isIds) array_push($pinkIds, $v['id']);
  563. self::orderPinkAfterNo($pinkT['uid'], $pinkT['id']);
  564. } else {
  565. if ($isRunErr) return $pinkBool;
  566. }
  567. }
  568. }
  569. self::commit();
  570. if ($isIds) return $pinkIds;
  571. return $pinkBool;
  572. } catch (\Exception $e) {
  573. self::rollback();
  574. return $pinkBool;
  575. }
  576. }
  577. public static function pinkReturn($order_id)
  578. {
  579. $product = StoreOrder::get($order_id);
  580. if (!$product) return self::setErrorInfo('数据不存在');
  581. $cart_info = StoreOrderCartInfo::where('cart_id', 'in', $product['cart_id'])->select();
  582. $return = 0;
  583. foreach ($cart_info as $v) {
  584. $info = $v['cart_info'];
  585. $return += $info['cart_num'] * ($info['productInfo']['attrInfo']['return']);
  586. }
  587. $res = true;
  588. if ($return > 0) {
  589. $balance = User::where('uid', $product['uid'])->value('brokerage_price');
  590. $res = $res && UserBill::income('拼团佣金', $product['uid'], 'now_money', 'brokerage', $return, $order_id, $balance + $return, '参加拼团未中,获得佣金' . $return);
  591. $res = $res && User::where('uid', $product['uid'])->inc('brokerage_price', $return)->update();
  592. }
  593. return $res;
  594. }
  595. public static function pinkIntegral($order_id)
  596. {
  597. $product = StoreOrder::get($order_id);
  598. if (!$product) return self::setErrorInfo('数据不存在');
  599. $cart_info = StoreOrderCartInfo::where('cart_id', 'in', $product['cart_id'])->select();
  600. $return = 0;
  601. foreach ($cart_info as $v) {
  602. $info = $v['cart_info'];
  603. $return += $info['cart_num'] * ($info['productInfo']['attrInfo']['integral']);
  604. }
  605. $res = true;
  606. if ($return > 0) {
  607. $balance = User::where('uid', $product['uid'])->value('integral');
  608. $res = $res && UserBill::income('拼团中奖送响亮积分', $product['uid'], 'integral', 'pink_success', $return, $order_id, $balance + $return, '参加拼团中奖,获得响亮积分' . $return);
  609. $res = $res && User::where('uid', $product['uid'])->inc('integral', $return)->update();
  610. }
  611. return $res;
  612. }
  613. public static function pinkRecommend($order_id)
  614. {
  615. $product = StoreOrder::get($order_id);
  616. if (!$product) return self::setErrorInfo('数据不存在');
  617. if ($product['pay_type'] == 'pink_integral') return true;
  618. $user = User::where('uid', $product['uid'])->find();
  619. if (!$user) return self::setErrorInfo('用户不存在');
  620. $spread = User::where('uid', $user['spread_uid'])->find();
  621. if (TreeRecommend::where('uid', $user['uid'])->count() > 1) {
  622. $spread = $user;
  623. }
  624. if (!$spread) return true;
  625. if ($spread['last_recommend_award']) $return = sys_config('recommend_double', 0);
  626. else $return = sys_config('recommend_single', 0);
  627. if ($spread['integral'] < $return) return true;
  628. $res = true;
  629. if ($return > 0) {
  630. $balance_integral = User::where('uid', $spread['uid'])->value('integral');
  631. $balance_brokerage = User::where('uid', $spread['uid'])->value('brokerage_price');
  632. $res = $res && UserBill::expend('礼包推荐奖[积分转换]', $spread['uid'], 'integral', 'pink_recommend_pay', $return / 2, $order_id, bcsub($balance_integral, $return / 2, 2), '推荐用户购礼包商品,响亮积分' . ($return / 2) . '转为推荐奖' . $return);
  633. $res = $res && UserBill::income('礼包推荐奖', $spread['uid'], 'now_money', 'brokerage', $return, $order_id, bcadd($balance_brokerage, $return, 2), '推荐用户购礼包商品' . $return);
  634. $res = $res && User::where('uid', $spread['uid'])->dec('integral', $return / 2)->update();
  635. $res = $res && User::where('uid', $spread['uid'])->inc('brokerage_price', $return)->update();
  636. $res = $res && User::where('uid', $spread['uid'])->update(['last_recommend_award' => ($spread['last_recommend_award'] ? 0 : 1)]);
  637. }
  638. return $res;
  639. }
  640. /*
  641. * 获取参团人和团长和拼团总人数
  642. * @param array $pink
  643. * @return array
  644. * */
  645. public static function getPinkMemberAndPinkK($pink)
  646. {
  647. //查找拼团团员和团长
  648. if ($pink['k_id']) {
  649. $pinkAll = self::getPinkMember($pink['k_id']);
  650. $pinkT = self::getPinkUserOne($pink['k_id']);
  651. } else {
  652. $pinkAll = self::getPinkMember($pink['id']);
  653. $pinkT = $pink;
  654. }
  655. $pinkT = $pinkT->hidden(['order_id', 'total_price', 'cid', 'pid', 'add_time', 'k_id', 'is_tpl', 'is_refund'])->toArray();
  656. $pinkAll = $pinkAll->hidden(['total_price', 'cid', 'pid', 'add_time', 'k_id', 'is_tpl', 'is_refund'])->toArray();
  657. $count = (int)bcadd(count($pinkAll), 1, 0);
  658. $count = (int)bcsub($pinkT['people'], $count, 0);
  659. $idAll = [];
  660. $uidAll = [];
  661. //收集拼团用户id和拼团id
  662. foreach ($pinkAll as $k => $v) {
  663. $idAll[$k] = $v['id'];
  664. $uidAll[$k] = $v['uid'];
  665. }
  666. $idAll[] = $pinkT['id'];
  667. $uidAll[] = $pinkT['uid'];
  668. return [$pinkAll, $pinkT, $count, $idAll, $uidAll];
  669. }
  670. /*
  671. * 取消开团
  672. * @param int $uid 用户id
  673. * @param int $pink_id 团长id
  674. * @return boolean
  675. * */
  676. public static function removePink($uid, $cid, $pink_id, $nextPinkT = null)
  677. {
  678. $pinkT = self::where('uid', $uid)
  679. ->where('id', $pink_id)
  680. ->where('cid', $cid)
  681. ->where('k_id', 0)
  682. ->where('is_refund', 0)
  683. ->where('status', 1)
  684. ->where('stop_time', '>', time())
  685. ->find();
  686. if (!$pinkT) return self::setErrorInfo('未查到拼团信息,无法取消');
  687. self::startTrans();
  688. try {
  689. list($pinkAll, $pinkT, $count, $idAll, $uidAll) = self::getPinkMemberAndPinkK($pinkT);
  690. if (count($pinkAll)) {
  691. if (self::getPinkPeople($pink_id, $pinkT['people'])) {
  692. //拼团未完成,拼团有成员取消开团取 紧跟团长后拼团的人
  693. if (isset($pinkAll[0])) $nextPinkT = $pinkAll[0];
  694. } else {
  695. //拼团完成
  696. self::PinkComplete($uidAll, $idAll, $uid, $pinkT, StoreCombination::where('id', $cid)->value('bingo_people'));
  697. return self::setErrorInfo(['status' => 200, 'msg' => '拼团已完成,无法取消']);
  698. }
  699. }
  700. //取消开团
  701. if (StoreOrder::orderApplyRefund(StoreOrder::getPinkOrderId($pinkT['order_id_key']), $pinkT['uid'], '拼团取消开团') && self::isTpl($pinkT['uid'], $pinkT['id'])) {
  702. $formId = RoutineFormId::getFormIdOne($uid);
  703. if ($formId) RoutineFormId::delFormIdOne($formId);
  704. self::orderPinkAfterNo($pinkT['uid'], $pinkT['id'], $formId, '拼团取消开团', true);
  705. } else
  706. return self::setErrorInfo(['status' => 200, 'msg' => StoreOrder::getErrorInfo()], true);
  707. //当前团有人的时候
  708. if (is_array($nextPinkT)) {
  709. self::where('id', $nextPinkT['id'])->update(['k_id' => 0, 'status' => 1, 'stop_time' => $pinkT['stop_time']]);
  710. self::where('k_id', $pinkT['id'])->update(['k_id' => $nextPinkT['id']]);
  711. StoreOrder::where('order_id', $nextPinkT['order_id'])->update(['pink_id' => $nextPinkT['id']]);
  712. }
  713. self::commitTrans();
  714. return true;
  715. } catch (\Exception $e) {
  716. return self::setErrorInfo($e->getLine() . ':' . $e->getMessage() . ':' . $e->getFile(), true);
  717. }
  718. }
  719. /**
  720. * 获取用户拼团到结束时间后还是拼团中的拼团
  721. * @return mixed
  722. */
  723. public static function pinkListEnd()
  724. {
  725. $model = new self;
  726. $model = $model->field('id,people');//开团编号
  727. $model = $model->where('stop_time', '<=', time());//小于当前时间
  728. $model = $model->where('status', 1);//进行中的拼团
  729. $model = $model->where('k_id', 0);//团长
  730. $model = $model->where('is_refund', 0);//未退款
  731. return $model->select();
  732. }
  733. /**
  734. * 拼团成功
  735. * @param array $pinkRegimental 成功的团长编号
  736. * @return bool
  737. * @throws \Exception
  738. */
  739. public static function successPinkEdit(array $pinkRegimental)
  740. {
  741. if (!count($pinkRegimental)) return true;
  742. foreach ($pinkRegimental as $key => &$item) {
  743. $pinkList = self::where('k_id', $item)->column('id', 'id');
  744. $pinkList[] = $item;
  745. $pinkList = implode(',', $pinkList);
  746. self::setPinkStatus($pinkList);//修改完成状态
  747. self::setPinkStopTime($pinkList);//修改结束时间
  748. $pinkUidList = self::isTplPink($pinkList);//获取未发送模板消息的用户
  749. if (count($pinkUidList)) self::sendPinkTemplateMessageSuccess($pinkUidList, $item);//发送模板消息
  750. }
  751. return true;
  752. }
  753. /**
  754. * 拼团失败
  755. * @param array $pinkRegimental 失败的团长编号
  756. * @return bool
  757. * @throws \think\db\exception\DataNotFoundException
  758. * @throws \think\db\exception\ModelNotFoundException
  759. * @throws \think\exception\DbException
  760. */
  761. public static function failPinkEdit(array $pinkRegimental)
  762. {
  763. if (!count($pinkRegimental)) return true;
  764. foreach ($pinkRegimental as $key => &$item) {
  765. $pinkList = self::where('k_id', $item)->column('id', 'id');
  766. $pinkList[] = $item;
  767. $pinkList = implode(',', $pinkList);
  768. self::refundPink($pinkList);//申请退款
  769. self::pinkStopStatus($pinkList);//修改状态
  770. $pinkUidList = self::isTplPink($pinkList);//获取未发送模板消息的用户
  771. if (count($pinkUidList)) self::sendPinkTemplateMessageError($pinkUidList, $item);//发送模板消息
  772. }
  773. return true;
  774. }
  775. /**
  776. * 发送模板消息 失败
  777. * @param array $pinkUidList 拼团用户编号
  778. * @param $pink 团长编号
  779. * @throws \think\db\exception\DataNotFoundException
  780. * @throws \think\db\exception\ModelNotFoundException
  781. * @throws \think\exception\DbException
  782. */
  783. public static function sendPinkTemplateMessageError(array $pinkUidList, $pink)
  784. {
  785. foreach ($pinkUidList as $key => &$item) {
  786. $openid = WechatUser::uidToOpenid($item, 'openid');
  787. $routineOpenid = WechatUser::uidToOpenid($item, 'routine_openid');
  788. $store = self::alias('p')->where('p.id|p.k_id', $pink)->field('c.*')->where('p.uid', $item)->join('store_combination c', 'c.id = p.cid')->find();
  789. $pink = self::where('id|k_id', $pink)->where('uid', $item)->find();
  790. if ($openid) {
  791. //公众号模板消息
  792. $urlWeChat = Route::buildUrl('order/detail/' . $pink->order_id)->suffix('')->domain(true)->build();
  793. WechatTemplateService::sendTemplate($openid, WechatTemplateService::ORDER_USER_GROUPS_LOSE, [
  794. 'first' => '亲,您的拼团失败',
  795. 'keyword1' => $store->title,
  796. 'keyword2' => $pink->price,
  797. 'keyword3' => $pink->price,
  798. 'remark' => '点击查看订单详情'
  799. ], $urlWeChat);
  800. } else if ($routineOpenid) {
  801. //小程序模板消息
  802. RoutineTemplate::sendPinkFail(
  803. $item,
  804. $store->title,
  805. $pink->people,
  806. '亲,您拼团失败,自动为您申请退款,退款金额为:' . $pink->price,
  807. '/pages/order_details/index?order_id=' . $pink->order_id
  808. );
  809. }
  810. }
  811. self::where('uid', 'IN', implode(',', $pinkUidList))->where('id|k_id', $pink)->update(['is_tpl' => 1]);
  812. }
  813. /**
  814. * 拼团失败 申请退款
  815. * @param $pinkList
  816. * @return bool
  817. */
  818. public static function refundPink($pinkList)
  819. {
  820. $refundPinkList = self::where('id', 'IN', $pinkList)->column('order_id,uid', 'id');
  821. if (!count($refundPinkList)) return true;
  822. foreach ($refundPinkList as $key => &$item) {
  823. // StoreOrder::refundPink($item['id']);
  824. StoreOrder::orderApplyRefund($item['order_id'], $item['uid'], '拼团时间超时');//申请退款
  825. }
  826. }
  827. /**
  828. * 拼团结束修改状态
  829. * @param $pinkList
  830. * @return StorePink
  831. */
  832. public static function pinkStopStatus($pinkList)
  833. {
  834. return self::where('id', 'IN', $pinkList)->update(['status' => 3]);
  835. }
  836. /**
  837. * 获取未发送模板消息的用户
  838. * @param $pinkList 拼团编号
  839. * @return array
  840. */
  841. public static function isTplPink($pinkList)
  842. {
  843. return self::where('id', 'IN', $pinkList)->where('is_tpl', 0)->column('uid', 'uid');
  844. }
  845. /**
  846. * 发送模板消息 成功
  847. * @param array $pinkUidList 拼团用户编号
  848. * @param $pink 团长编号
  849. * @throws \Exception
  850. */
  851. public static function sendPinkTemplateMessageSuccess(array $pinkUidList, $pink)
  852. {
  853. foreach ($pinkUidList as $key => &$item) {
  854. $openid = WechatUser::uidToOpenid($item, 'openid');
  855. $routineOpenid = WechatUser::uidToOpenid($item, 'routine_openid');
  856. $nickname = WechatUser::uidToOpenid(self::where('id', $pink)->value('uid'), 'nickname');
  857. if ($openid) {
  858. //公众号模板消息
  859. $firstWeChat = '亲,您的拼团已经完成了';
  860. $keyword1WeChat = self::where('id|k_id', $pink)->where('uid', $item)->value('order_id');
  861. $keyword2WeChat = self::alias('p')->where('p.id|p.k_id', $pink)->where('p.uid', $item)->join('store_combination c', 'c.id=p.cid')->value('c.title');
  862. $remarkWeChat = '点击查看订单详情';
  863. $urlWeChat = Route::buildUrl('order/detail/' . $keyword1WeChat)->suffix('')->domain(true)->build();
  864. WechatTemplateService::sendTemplate($openid, WechatTemplateService::ORDER_USER_GROUPS_SUCCESS, [
  865. 'first' => $firstWeChat,
  866. 'keyword1' => $keyword1WeChat,
  867. 'keyword2' => $keyword2WeChat,
  868. 'remark' => $remarkWeChat
  869. ], $urlWeChat);
  870. } else if ($routineOpenid) {
  871. //小程序模板消息
  872. $pinkInfo = self::where('k.id|k.k_id', $pink)->alias('k')->where('k.uid', $item)
  873. ->field(['k.order_id', 'k.people', 'k.add_time', 'c.title'])
  874. ->join('store_combination c', 'c.id = k.cid')->find();
  875. RoutineTemplate::sendPinkSuccess(
  876. $item, $pinkInfo['title'] ?? '',
  877. $nickname,
  878. $pinkInfo['add_time'] ?? 0,
  879. $pinkInfo['people'] ?? 0,
  880. '/pages/order_details/index?order_id=' . $pinkInfo['order_id'] ?? ''
  881. );
  882. }
  883. }
  884. self::where('uid', 'IN', implode(',', $pinkUidList))->where('id|k_id', $pink)->update(['is_tpl' => 1]);
  885. }
  886. /**
  887. * 修改到期的拼团状态
  888. * @return bool
  889. * @throws \think\db\exception\DataNotFoundException
  890. * @throws \think\db\exception\ModelNotFoundException
  891. * @throws \think\exception\DbException
  892. */
  893. public static function statusPink()
  894. {
  895. $pinkListEnd = self::pinkListEnd();
  896. if (!$pinkListEnd) return true;
  897. $pinkListEnd = $pinkListEnd->toArray();
  898. $failPinkList = [];//拼团失败
  899. $successPinkList = [];//拼团失败
  900. foreach ($pinkListEnd as $key => &$value) {
  901. $countPeople = (int)bcadd(self::where('k_id', $value['id'])->count(), 1, 0);
  902. if ($countPeople == $value['people'])
  903. $successPinkList[] = $value['id'];
  904. else
  905. $failPinkList[] = $value['id'];
  906. }
  907. $success = self::successPinkEdit($successPinkList);
  908. $error = self::failPinkEdit($failPinkList);
  909. $res = $success && $error;
  910. if (!$res)
  911. throw new \Exception('拼团订单取消失败!');
  912. }
  913. }